Compare commits

...

1206 Commits

Author SHA1 Message Date
10fb8e88ce fix: change click and load package name 2025-12-10 13:36:33 +01:00
5f300d9e7b feat: nb initial click and load 2025-12-10 12:49:30 +01:00
99ac2ea3b0 feat: nas move archive extraction to filebot script 2025-12-10 11:40:19 +01:00
2caa36c0ab fix: nas filebot and add extraction passwords 2025-12-10 11:29:05 +01:00
55c15c790d fix: fw lightning 2025-12-10 11:28:08 +01:00
450d9d6457 fix: claude.md update 2025-12-07 12:59:43 +01:00
e08bf42eaa fix: nas leds and disks 2025-12-07 12:59:27 +01:00
8e0e5c0d16 feat: add disks to monitoring 2025-12-05 21:57:58 +01:00
ada9db7942 feat: add disks to nas 2025-12-04 15:01:47 +01:00
5995612407 fix: amzebs add mysql port 2025-12-04 12:46:28 +01:00
5762916970 feat: add mcp server 2025-12-04 11:39:17 +01:00
dd456eab69 feat: update pyload 2025-12-04 11:39:08 +01:00
18a8fde66e feat: add uv for mcp 2025-12-04 11:38:22 +01:00
f97c9185c1 docs: update claude 2025-12-02 11:28:05 +01:00
8bf4b185a1 feat(nas): update to 25.11, add software, add storage plan 2025-12-02 11:27:52 +01:00
8424d771f6 feat(fw): update to 25.11 2025-12-02 08:34:57 +01:00
840f99a7e9 feat(amzebs-01): update to 25.11 2025-12-01 23:02:35 +01:00
1b27bafd41 feat(web-arm): update to 25.11
- Migrate logind.extraConfig to logind.settings.Login
- Update dovecot alert for service rename (dovecot2 → dovecot)
- Fix sa-core buildGoModule env attribute for CGO_ENABLED
2025-12-01 22:48:02 +01:00
4770d671c0 docs: add commit footer convention to CLAUDE.md 2025-12-01 22:25:08 +01:00
28a7bed3b9 feat(mail): update to 25.11 with TLS hardening
- Upgrade NixOS channel from 25.05 to 25.11
- Fix dovecot systemd service rename (dovecot2 -> dovecot)
- Convert postfix numeric settings to integers (25.11 requirement)
- Remove insecure 512-bit DH params, fix 2048-bit DH params
- Update postfix ciphers to modern ECDHE/DHE+AESGCM/CHACHA20
- Require TLS 1.2 minimum for OpenLDAP
- Remove weak ciphers (3DES, RC4, aNULL) from OpenLDAP
2025-12-01 22:24:57 +01:00
170becceb0 fix: nvim 2025-12-01 22:05:24 +01:00
6e8f530537 feat: amz add cron job 2025-12-01 16:17:45 +01:00
209bafd70f feat: test-configuration script get real errors 2025-12-01 16:17:28 +01:00
1d182437db feat: nb update to 25.11 2025-12-01 16:17:10 +01:00
6c046a549e feat: change pushover emergency on alerts 2025-12-01 13:29:37 +01:00
0a30a2ac23 fix: ai-mailer restart on secret change 2025-12-01 13:29:26 +01:00
82c15e8d26 feat: pyload config change, cyberghost change 2025-11-30 19:53:13 +01:00
f277d089bd feat: add cyberghost module 2025-11-30 19:29:33 +01:00
7ed345b8e8 feat: add pyload extraction passwords 2025-11-30 19:29:24 +01:00
bd6b15b617 changes 2025-11-29 22:42:09 +01:00
3282b7d634 fix: monitoring 2025-11-29 22:42:00 +01:00
21ed381d18 fix: pyload 2025-11-29 22:41:48 +01:00
4500f41983 feat: add ugreen nas leds 2025-11-29 13:12:18 +01:00
1d30eeb939 feat: update victoriametrics secret 2025-11-28 23:51:33 +01:00
537f144885 feat: add smart alerting and noatime to disks 2025-11-28 23:50:24 +01:00
dbada3c509 feat: change harddisk nas 2025-11-28 21:17:07 +01:00
c8be707420 fix: nas handling 2025-11-28 20:54:12 +01:00
fdba2c75c7 feat: add nas host 2025-11-28 20:53:47 +01:00
55d600c0c0 feat: add nas to fleet 2025-11-28 18:49:56 +01:00
71c5bd5e6c change claude 2025-11-28 01:57:30 +01:00
998f04713f fix(nb): additional sops.lua bug fixes
- Use nvim_buf_get_name(args.buf) instead of vim.fn.expand("%:p") in BufReadPost
- Add timeout to encrypt operation to prevent infinite hangs
- Add microsecond precision to temp file names to prevent collisions
- Strip trailing newline before vim.split to avoid extra empty lines
- Add trailing newline when writing temp file for POSIX compliance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 01:54:20 +01:00
6935fbea8b fix: sops implementation 2025-11-28 01:32:23 +01:00
301e090251 feat: add Claude.md 2025-11-28 01:00:55 +01:00
58d8ef050c feat: install own claude-code 2025-11-27 22:10:05 +01:00
41cb2ec791 fix: update script for claude-code 2025-11-27 22:09:48 +01:00
1faec5b2d1 feat: add updated claude code 2025-11-27 21:49:24 +01:00
111b8cec97 feat: change rustdesk for epicenter 2025-11-27 21:49:11 +01:00
3aaebdb1c4 fix: filebot 2025-11-27 12:50:00 +01:00
3e7b8c93e3 feat: split pyload 2025-11-26 22:39:07 +01:00
3e2f46377e fix: pyload and filebot 2025-11-26 21:08:58 +01:00
38bead3dc8 fix: pyload 2025-11-26 12:48:24 +01:00
351d36b217 fix: changes to pyload 2025-11-26 00:26:21 +01:00
59a37c9b46 feat: add jellyfin and hardware acceleration for transcoding 2025-11-25 19:48:52 +01:00
d7d3722ce7 fix: pyload 2025-11-25 17:03:03 +01:00
6475524d23 fix: amz postfix setup 2025-11-23 11:29:07 +01:00
1a70ca9564 feat: add pyload 2025-11-23 11:28:57 +01:00
d6f206f0bb feat: add email 2025-11-21 14:00:47 +01:00
b3c5366f31 feat: nb change building speed 2025-11-19 00:00:58 +01:00
fab06ca4d5 feat: change livingroom to hue 2025-11-19 00:00:43 +01:00
bd1d04943d fix: change deconz 2025-11-19 00:00:34 +01:00
8305d1b0c5 fix: nb chromium 2025-11-18 22:31:07 +01:00
2d812c03eb feat: ai-mailer add faq page 2025-11-18 22:30:54 +01:00
156e63fd6c feat: amz changes 2025-11-18 22:30:41 +01:00
a912c4dc55 feat: amz enable all hosts 2025-11-15 21:56:40 +01:00
8a2a68a91c feat: add alerting for amz ebs server and websites blackbox 2025-11-14 23:08:27 +01:00
01d3ab1357 feat: amzebs-01 update deployment key 2025-11-14 22:08:56 +01:00
20c5af7a69 feat: add amzebs-01 host 2025-11-14 20:06:01 +01:00
865311bf49 feat: initial amzebs config 2025-11-14 09:30:19 +01:00
9fab06795a update esphome readme 2025-11-13 19:32:49 +01:00
038fb7ae76 feat: update ai-mailer 2025-11-13 11:53:14 +01:00
3775e0dd7b feat: add ai-image-alt 2025-11-12 22:50:09 +01:00
66a5d69846 feat: add php 2025-11-12 22:48:54 +01:00
8747f887f8 fix: invidious 2025-11-12 22:48:48 +01:00
39f4460e0a feat: upgrade foundry to v13 2025-11-12 22:48:31 +01:00
6f8626ca8a feat: update ai-mailer 2025-11-12 14:30:35 +01:00
04c08bf419 fix: invidious 2025-11-03 14:43:28 +01:00
709a24366a fix: piped 2025-11-03 12:12:14 +01:00
63dad8c626 fix: invidious password 2025-11-03 01:38:16 +01:00
b57342f53e feat: add invidious 2025-11-03 00:59:18 +01:00
7cefa3a650 add bghelper to piped 2025-11-02 20:36:20 +01:00
5d54ae898e fix: piped cors header 2025-11-02 15:27:35 +01:00
794d5c2dad feat: move piped to fw host 2025-11-02 14:34:30 +01:00
04cdf1bd2f feat: remove korean-skin.care site 2025-11-02 13:42:54 +01:00
b4c4e31437 feat: backup web-02 databases 2025-11-02 12:30:35 +01:00
56bb321e4a fix: n8n 2025-11-02 10:46:50 +01:00
c0d868088e fix: n8n 2025-11-02 10:46:36 +01:00
df5c89f071 feat: add n8n 2025-11-02 00:29:43 +01:00
b73bc3e80a feat: initial n8n config 2025-11-01 23:44:03 +01:00
db25b2bfbb feat: add cleanup for grafana alerting rules 2025-11-01 11:09:05 +01:00
819bfc1531 feat: adjusted the gitea runner dockerfile to include chrome for puppeteer 2025-11-01 09:43:27 +01:00
cfdb8d8474 fix: nvim sops error 2025-10-28 16:31:20 +01:00
d50ed9858c fix: nvim sops, remove lsp 2025-10-28 14:10:04 +01:00
7af4b6a5d1 feat: web stack make php optional 2025-10-27 16:38:12 +01:00
ca04f5d8c3 feat: nb add ownstash api project 2025-10-27 16:37:54 +01:00
a02cefc62a feat: make cloonar website use the web stack module 2025-10-23 19:27:17 +02:00
28974e9688 feat: gitea runner open cache port 2025-10-23 03:06:36 +02:00
aaf5f79895 feat: fw remove unstable packages 2025-10-23 02:53:58 +02:00
eccac4d4a2 feat: gitea runner cache config 2025-10-23 02:30:09 +02:00
399f67ba25 feat: fw speed up builds 2025-10-23 02:30:00 +02:00
439a580dfe feat: fw update gitea to use a docker image with puppeteer, webp and avif deps 2025-10-23 02:15:34 +02:00
bfae290927 feat(web-arm): add AVIF image support to cloonar.dev
Implement AVIF image content negotiation with WebP fallback for
cloonar.dev website. Browser will receive AVIF if supported and
available, otherwise WebP, falling back to original JPEG/PNG.

- Add AVIF-first content negotiation in image location block
- Maintain existing WebP fallback logic
- Include .avif in long-term cache headers (365d)
- Add Vary: Accept header for proper CDN/browser caching

AVIF files should be placed at /avif/$request_uri.avif to be served.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-22 23:55:08 +02:00
1eeb0b7102 fix ssh key for website 2025-10-22 23:49:16 +02:00
f49ac19af1 fix identityfile for host 2025-10-22 23:49:03 +02:00
27c85ff9d0 fix: nvim sops double save issue 2025-10-22 19:19:40 +02:00
b6d44b5a20 fix: nvim sops lua 2025-10-22 19:14:36 +02:00
b8b7574536 fix: nb nvim auto open claude 2025-10-22 15:25:39 +02:00
5ee2cb2b56 feat: nb update signal desktop files 2025-10-22 15:25:19 +02:00
6c88bc1790 feat: update readme to new nixos-infect channel 2025-10-22 15:24:34 +02:00
6be832b012 feat: nb add ssh config for whoidentifies.me 2025-10-22 14:30:35 +02:00
fc9ef6b9ff feat: nb add sway launcher cleanup 2025-10-22 14:29:53 +02:00
ec19103a81 fix: nb change open mapping for the terminal 2025-10-22 13:23:50 +02:00
7499a21cbd feat: nb add wim-api project 2025-10-22 12:31:53 +02:00
5758b3a320 fix(nvim): enable yaml syntax highlighting for sops files
Add BufReadPre autocmd to set filetype=yaml before buffer is loaded,
ensuring syntax highlighting works immediately when opening encrypted
sops files. Also updated BufReadPost to unconditionally set yaml
filetype after decryption.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-22 12:29:10 +02:00
7d2f818fca feat: nb add env variable for sops 2025-10-22 11:58:58 +02:00
19d0946e06 feat: add sops to vim 2025-10-22 09:52:40 +02:00
7d5294e7b9 fix: hibernate resume for nb 2025-10-19 18:14:40 +02:00
28ed3fcf74 fix(nb): resolve keyboard/touchpad and btrfs read-only issues after suspend
This commit addresses two critical suspend/resume issues on the nb host:

1. Keyboard and touchpad not working after suspend
   - Added i2c_hid_acpi kernel module
   - Created systemd service to reload the module after resume
   - Excluded input devices from TLP USB autosuspend

2. /nix/persist becoming read-only after suspend
   - Moved swap from /nix/persist to dedicated @swap subvolume
   - Added systemd service to remount /nix/persist if needed
   - Separated swap from persistent data to prevent btrfs corruption

Changes:
- Created hosts/nb/modules/suspend-fixes.nix with resume hooks
- Updated swap path from /nix/persist/swapfile to /swap/swapfile
- Added /swap filesystem mount for @swap btrfs subvolume
- Added USB_EXCLUDE_INPUT=1 to TLP configuration

Note: Manual step required before deployment - create @swap subvolume.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 16:43:02 +02:00
5a35cd04a6 feat: nvim update terminal keybindings 2025-10-19 16:03:29 +02:00
5648224062 fix(nb): force signal-desktop to use X11 with --ozone-platform=x11
Electron 38 has built-in Wayland auto-detection. Even without
ELECTRON_OZONE_PLATFORM_HINT, it detects WAYLAND_DISPLAY and tries
to use Wayland, triggering the empty window bug in Signal Desktop.

Explicitly force X11/XWayland mode with --ozone-platform=x11 flag
to prevent auto-detection and fix the empty window issue.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 15:56:24 +02:00
bbb9cacd71 fix(nb): remove wayland flags from signal-desktop to fix empty window
Signal Desktop has a known Electron bug where the window never appears
when using Wayland Ozone platform flags. The ready-to-show event doesn't
fire properly on Wayland. Running in XWayland mode resolves this issue.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 15:28:42 +02:00
40743442e9 fix: use autoupgrade only on AC 2025-10-19 13:31:31 +02:00
7564c5d740 fix: nb change signal flags 2025-10-19 13:25:48 +02:00
3a6d5bb8c4 fix: nb add /boot mount 2025-10-19 12:17:04 +02:00
f256ca7fad feat: nvim add another terminal for ai agents 2025-10-19 12:03:57 +02:00
cb18e436ca feat: nb battery improvement 2025-10-19 12:01:45 +02:00
019b1166ec fix: nb right repo for soundscape 2025-10-18 22:14:13 +02:00
cc15f27205 feat: nb performance tweaks 2025-10-16 21:48:21 +02:00
356c049aaf feat: nb performance tweaks 2025-10-15 11:39:29 +02:00
df6465fa8a feat: nb performance tweaks 2025-10-15 11:25:46 +02:00
a05c33ad87 fix: nb disable attic cache 2025-10-15 10:09:39 +02:00
67906cbf16 fix: attic cache 2025-10-15 10:09:26 +02:00
09e381ecc4 feat: add attic cache 2025-10-14 22:30:20 +02:00
7fd35b79c4 fix: blacklist attic website exporter 2025-10-14 22:29:44 +02:00
c9900e4314 fix: atticd server 2025-10-14 22:24:35 +02:00
5ea3bac570 feat: add update-keys script 2025-10-14 20:02:42 +02:00
eae7bb0e09 feat: web-arm add atticd 2025-10-14 20:01:45 +02:00
465daec0ab feat: change authelia 2025-10-14 19:54:45 +02:00
f516f46b06 feat: update secrets 2025-10-14 19:54:24 +02:00
742d0172cf feat: web-arm install atticd 2025-10-14 19:14:46 +02:00
e0568ddfdc fix: chromium extension installation 2025-10-14 14:14:04 +02:00
9941dfa61f feat: add adb 2025-10-14 14:13:47 +02:00
aac9e9f38f fix: fivefilters https 2025-10-14 14:13:37 +02:00
bdda87778c feat: add android studio 2025-10-13 13:23:51 +02:00
fccec6d87c fix: chrome dev tools mcp 2025-10-13 13:23:37 +02:00
5e259e0b42 feat: add fivefilters 2025-10-13 13:23:13 +02:00
496c483050 feat: web-arm cloonar.dev new key 2025-10-11 21:52:42 +02:00
1433f88d53 feat: nb changes for claude code 2025-10-11 21:52:32 +02:00
506c4f9357 fix: nb flatpak installation 2025-10-10 13:18:31 +02:00
a4ed475237 feat: nb add flatpak iptv package 2025-10-10 12:23:51 +02:00
de43e917c5 feat: nb dominik add project and clean up projects 2025-10-10 10:01:58 +02:00
be515979cf feat: nb add claude code 2025-10-10 10:01:42 +02:00
cc03069d57 feat: add nssTools 2025-10-08 22:19:51 +02:00
fe7aaadf64 feat: add AGENTS.md 2025-10-08 22:14:09 +02:00
0b6549a359 fix: nb codex-cli wrapper 2025-10-08 22:05:19 +02:00
af60555eea update secrets 2025-10-08 21:48:34 +02:00
64334192de fix: nb update hashes for browser extensions 2025-10-08 19:37:27 +02:00
4751fb5582 fix: change to btrfs and fix an error 2025-10-08 19:37:10 +02:00
34e56a13ea Update fleet.nix 2025-10-08 13:53:13 +02:00
c3f2603702 feat: nb add scana11y address and change firefox config 2025-10-02 19:46:19 +02:00
15f6b2edd0 feat: nb change sway config to nautilus 2025-10-02 19:45:58 +02:00
6339b733c4 feat: nb update coding config 2025-10-02 19:45:37 +02:00
305ce21e41 feat: add modularity to scana11y 2025-10-02 19:45:08 +02:00
8ab1c91b38 feat: scana11y changes 2025-09-29 15:59:48 +02:00
bf5c7a74cb feat: esphome updates 2025-09-29 15:59:12 +02:00
b48ec98cb3 feat: web-arm change to docker and install scana11y 2025-09-09 17:55:43 +02:00
58089e558e feat: auto restart foundry-vtt 2025-09-09 10:39:45 +02:00
97b6874258 feat: nb add scana11y repo 2025-09-09 10:39:20 +02:00
8ad0c4d336 feat: web change site handling, add php to scana11y, add ssh deploy key for gitea 2025-09-09 10:39:00 +02:00
536fc2b463 feat: change dovecot2 sieve 2025-09-08 17:15:37 +02:00
b7287b0d51 feat: change gpd win 4 wireguard 2025-09-08 17:15:20 +02:00
a0ffb52f98 feat: add foundry vtt to allerting 2025-09-08 17:13:02 +02:00
eb40b7ff06 feat: add webmail to webhost 2025-09-08 17:12:53 +02:00
b3a71cb9bc feat: nb remove old stuff and add cursor 2025-08-12 12:20:28 +02:00
16594b3e7d feat: remove ghetto.at domain 2025-08-12 12:20:06 +02:00
7937e00018 feat: remove and add dovecot domains 2025-08-07 13:07:37 +02:00
0e91e1e7f5 feat: add scana11y to ldap 2025-08-07 12:08:47 +02:00
99b387fe8b feat: install swayimg 2025-08-07 12:08:39 +02:00
fe53ea7551 add nb-new to fleet 2025-08-07 12:08:28 +02:00
541f9b3776 feat: change iso to btrfs 2025-08-07 12:08:19 +02:00
1c9302c773 feat: add scana11y website 2025-08-07 12:08:09 +02:00
ba9ef3913d feat: change iso to btrfs 2025-08-05 19:52:58 +02:00
79b4a615f0 fix: ldap auth 2025-08-05 18:31:16 +02:00
7225a5e787 fix: ldap auth 2025-08-01 23:11:42 +02:00
467ade9340 fix: ldap auth 2025-08-01 22:16:01 +02:00
619136674e feat: updata phpldapadmin, add linuxbind secret 2025-08-01 20:24:40 +02:00
3990566fe5 feat: many changes 2025-08-01 19:48:49 +02:00
7f01dc4cac feat: many changes 2025-07-11 11:19:42 +02:00
da95b2fa71 feat: add dialog-relations.at website 2025-06-25 08:19:32 +02:00
9b628caaef feat: add copilot instructions symlink 2025-06-22 14:26:57 +02:00
4ec924b736 fix: disable not working and not needed mcps 2025-06-22 14:26:07 +02:00
2712bd2197 feat: add new bed switch and a new scene 2025-06-22 14:25:50 +02:00
03d3ff5712 feat: refactor mcp configuration to separate programs and custom servers 2025-06-20 14:37:53 +02:00
6aeb0c9f89 many changes 2025-06-17 16:46:01 +02:00
91394ef68a feat: add support for pgpPublicKey in OpenLDAP configuration 2025-06-08 13:08:22 +02:00
a7d304cc5b feat: add ldap2vcard repository to project history and clone configuration 2025-06-08 12:05:54 +02:00
0b8619bf64 feat: update configuration files to streamline imports and enhance package management 2025-06-08 09:36:44 +02:00
30e75d0ad5 feat: add different rustdesks for configs 2025-06-05 19:29:00 +02:00
a18a0e913d feat: update MCP configuration to include additional permissions for nixos and puppeteer modules 2025-06-05 15:06:18 +02:00
ecf3e03e81 feat: add Ollama and Qdrant service modules to configuration 2025-06-04 16:13:22 +02:00
934471bd88 feat: add MCP global configuration module, manage Brave Search API key, and set up systemd service for deployment 2025-06-04 15:47:05 +02:00
0fff2f87a5 feat: update environment variables for Wayland support, adjust font sizes in Sway and Waybar configurations, and refine Thunderbird settings 2025-06-04 08:07:27 +02:00
e8bf13275e feat: add metrics exporters for Dovecot and Postfix, update Signal execution command, and improve configuration management 2025-06-03 23:06:40 +02:00
436903543b feat: update Signal desktop execution command for hardware acceleration and modify Sway terminal configuration 2025-06-02 21:04:51 +02:00
c47f678220 feat: add Firefox to system packages in desktop configuration 2025-06-02 12:10:14 +02:00
d4438c8585 refactor: notebook configration 2025-06-02 01:04:43 +02:00
0df4a4c1ec fix: update Firefox Sync configuration and proxy settings for improved functionality 2025-06-01 22:10:04 +02:00
365d15767b feat: add Firefox Sync module and update DNS settings for sync.cloonar.com 2025-06-01 17:01:12 +02:00
4969520222 feat: enhance Blackbox Exporter configuration with domain blacklist and update Grafana alerting rules 2025-06-01 11:40:04 +02:00
9cfd7f5052 fix: correct syntax for extraScrapeConfigs in VictoriaMetrics configuration 2025-06-01 09:37:16 +02:00
faad280aa0 fix: update Blackbox Exporter scrape config and Grafana alert expressions for improved monitoring accuracy 2025-06-01 09:08:36 +02:00
f1ea4b9b20 feat: implement website alerting plan with Blackbox Exporter and VictoriaMetrics integration 2025-06-01 00:47:43 +02:00
b6b90bca7d refactor: Grafana alerting rules: consolidate and reorganize alert definitions
- Deleted individual alert files for host down, inode usage, and RAM usage.
- Merged service down alerts into a new structure with separate files for each service (Gitea, Postfix, Dovecot, OpenLDAP, WireGuard).
- Introduced a new system alert structure consolidating CPU, disk, host down, inode, and RAM usage alerts.
- Updated alert conditions to use 'D' for thresholds and adjusted expressions accordingly.
- Improved annotations and labels for clarity and consistency across alerts.
2025-05-31 21:14:36 +02:00
39b9726be7 feat: add Loki datasource configuration for Grafana 2025-05-31 19:30:04 +02:00
7fc3c3db63 feat: add VictoriaMetrics module, update Dovecot Sieve extensions, and fix Grafana service expression 2025-05-31 19:21:56 +02:00
89b2a1cf45 feat: add service monitoring alerts for Gitea, Postfix, Dovecot, OpenLDAP, and WireGuard, and consolidate alerting rules in Grafana 2025-05-31 15:53:26 +02:00
94ee6bc9a4 feat: implement comprehensive service monitoring and alerting plan for OpenLDAP, Postfix, Dovecot, Gitea, and WireGuard using Grafana and VictoriaMetrics 2025-05-31 13:37:35 +02:00
81f04c6c51 refactor: remove unused MAC address entry from dnsmasq configuration, update gitea-vm to include network settings, enhance grafana-monitor with internet connectivity check, and clean up web module imports 2025-05-31 12:53:02 +02:00
d0c67baeb8 feat: add Grafana online status monitoring module with Pushover notifications 2025-05-31 11:35:17 +02:00
35fa61ef34 feat: refactor Grafana alerting rules into a consolidated system module and update individual alert files 2025-05-31 09:57:03 +02:00
8b5fb0861d feat: restructure Grafana configuration, migrate alert rules to new format and add VictoriaMetrics datasource 2025-05-31 09:27:25 +02:00
17a3602d3c feat: implement centralized alerting with vmalert and Grafana, add alert rules for CPU, disk, inode, RAM usage, and host status 2025-05-30 21:39:58 +02:00
fa42667c2a fix: update NixOS channel references to version 25.05 and adjust netdata configuration 2025-05-30 18:32:47 +02:00
d161d5f421 fix: correct API calls in lspconfig and utils, ensure proper setup for none-ls 2025-05-30 00:31:36 +02:00
a36b1e8310 fix: update AI Mailer configuration, adjust polling interval, and modify logging level
feat: update NixOS channel to 25.05 and remove unused unstable imports
fix: correct keyboard layout configuration in sway
feat: update ai-mailer package source and hash
2025-05-30 00:21:07 +02:00
640ad93684 fix: update AI Mailer configuration for Gmail and adjust logging level 2025-05-30 00:20:59 +02:00
51a3a10701 feat: add fingerprint reader setup and management instructions 2025-05-29 08:36:25 +02:00
cf340ca277 feat: add set-nix-channel module to manage nix-channel automatically 2025-05-29 00:38:12 +02:00
c0d51ee06d feat: remove unused hosts 2025-05-29 00:37:45 +02:00
53d73142ae Add a11ywatch and related configurations for Podman and Nginx
- Introduced a new module for a11ywatch with Podman support, creating a bridge network and defining backend and frontend containers.
- Configured Nginx to serve the a11ywatch application with SSL and ACME support.
- Added user and group configurations for a11ywatch.
- Created a systemd service to ensure the Podman network exists on boot.

Implement Firefox Container Controller extension and host

- Added a module for the Firefox Container Controller extension, allowing installation via Nix.
- Created a native messaging host for the extension to communicate with the container controller.
- Included CLI helpers to enqueue commands for showing and hiding containers.

Enable fingerprint authentication in PAM

- Configured fingerprint authentication for login, sudo, and swaylock services.

Setup Raspberry Pi OS image creation script

- Developed a script to create a read-only Raspberry Pi OS Lite image with Snapcast client.
- Included configuration for Wi-Fi, hostname, and Snapcast server.
- Implemented user and group setup for Snapcast client and ensured necessary services are enabled.

Document Raspberry Pi Zero W setup instructions

- Added detailed instructions for configuring Raspberry Pi OS on Zero W, including disabling unused services and setting up Snapcast client.

Create test configuration script for NixOS

- Implemented a script to perform dry-builds for NixOS configurations, allowing for easy validation of host configurations.
2025-05-29 00:10:07 +02:00
8e52274edd fix: picoreplayer remove device as no longer needed 2025-05-24 11:18:47 +02:00
cbde498ae8 fix: picoreplayer remove config param 2025-05-24 11:05:10 +02:00
9feace9558 fix: picoreplayer script 2025-05-24 10:12:51 +02:00
2a5496118b feat: add postfix to web server 2025-05-24 10:12:39 +02:00
f362b2ab77 feat: add hs-cloud to collabora 2025-05-24 10:12:23 +02:00
7a8cd490d5 feat: update nextcloud 2025-05-24 10:12:12 +02:00
5a20d97084 feat: add a firefox container 2025-05-24 10:11:48 +02:00
8def0af08f feat: add lms 2025-05-24 10:11:18 +02:00
348d8e1d03 feat: changes to home-assistant 2025-05-24 10:10:51 +02:00
a078503a89 feat: add picoreplayer script 2025-05-24 09:58:22 +02:00
bc57914131 many changes 2025-05-08 22:46:20 +02:00
3b01625f7d feat: changes to esphome 2025-05-08 22:45:53 +02:00
8cf4762a65 feat: kea unbound sync remove old leases 2025-05-01 21:28:58 +02:00
6f9b384caa fix: cloonar assistant config server 2025-04-30 15:54:45 +02:00
7ac54dd987 feat: add test to updns 2025-04-30 15:54:18 +02:00
57684db260 fix: sway display layout 2025-04-30 15:54:01 +02:00
c20998d365 fix: cloonar assistant config server 2025-04-28 22:40:36 +02:00
2f1d88b001 feat: add cloonar-assistant-customers repo 2025-04-28 22:40:17 +02:00
b8453eaf43 fix: home assistant multimedia off automation 2025-04-28 22:39:51 +02:00
87d22fba6d fix: electricity sensor home assistant 2025-04-28 22:39:37 +02:00
e4eb5c80fc fix: create the config files for ca config server the right way 2025-04-28 10:54:03 +02:00
c8e3542fe8 feat: add cloonar assistant config server 2025-04-28 10:41:06 +02:00
0ac30a5190 fix: electricity pricing 2025-04-28 10:40:44 +02:00
c02651e65a feat: add updns 2025-04-25 22:35:42 +02:00
9a5a28098c changes 2025-04-25 20:35:33 +02:00
9cfc423a38 add ai mailer 2025-03-02 03:41:42 +01:00
3b043eaf6d add vscode server microvm and update user configurations 2025-03-01 15:31:17 +01:00
386b70314d many changes 2025-02-23 16:00:33 +01:00
e2add63337 add vscode 2025-02-04 11:52:44 +01:00
7de9b583d5 add local mysql and postgresql server 2025-02-04 11:52:38 +01:00
406c0f539e add secrets for cyberghost vp 2025-02-04 11:52:23 +01:00
1651b8a550 add cyberghost vpn for chatgpt 2025-02-04 11:52:12 +01:00
ff2fdd3c08 add new projects 2025-02-04 11:52:02 +01:00
35ad68fbbe add go to lsp and update chatgpt.vim 2025-02-04 11:51:54 +01:00
bd4503c035 fix ldap logging and add sleep to certificate renewal postRun 2025-02-04 11:51:38 +01:00
c423af5498 add host to wireguard 2025-02-04 11:51:20 +01:00
a2d482e16d many changes 2025-01-26 10:55:38 +01:00
12ef36af33 changes 2024-12-29 22:04:44 +01:00
6ae6c5e0e5 some changes regarding rustdesk and a new project 2024-12-26 14:13:40 +01:00
44b47ce18c changes 2024-12-21 13:47:00 +01:00
c96c24f864 many changes and more modularizing 2024-12-12 22:30:24 +01:00
df50e70f3e refactor folder structure 2024-12-01 12:35:59 +01:00
da669efee2 feat: changes for notebook 2024-12-01 11:44:50 +01:00
776346ca19 fix: secret for runner 2024-12-01 11:44:38 +01:00
af8dd30afe feat: add another gitea runner 2024-12-01 11:44:26 +01:00
5599bfad67 feat: static ip for rmproplus 2024-12-01 11:44:06 +01:00
83d1e7677a feat: add foundry-vtt 2024-12-01 11:43:47 +01:00
16d91bac8f feat: changes to matri 2024-12-01 11:43:01 +01:00
1c4cc1e393 feat: home-assistant changes 2024-12-01 11:42:34 +01:00
03eaa38a08 add esphome devices 2024-12-01 11:42:03 +01:00
640d2affa8 remove old hosts 2024-11-15 02:30:37 +01:00
bd9f1ce260 many changes 2024-11-15 02:30:04 +01:00
1746412a11 change chromium extensions 2024-11-11 01:06:41 +01:00
7ec31696fc nb config 2024-11-11 00:28:50 +01:00
96d26c5431 home assistant and matrix changes 2024-11-11 00:28:41 +01:00
21d2e34025 changes to home-assistant and nb 2024-11-10 03:22:29 +01:00
5941526a5e change gitignore 2024-11-09 20:51:00 +01:00
e15cb70bdc add git-lfs 2024-11-09 20:50:48 +01:00
18312e12a9 change ungoogled chromium 2024-11-09 20:50:41 +01:00
033fe672df make nvim fzf wider 2024-11-09 20:50:28 +01:00
b46fed0624 changes for esphome 2024-11-09 20:50:03 +01:00
c3d40022df add esphome 2024-11-09 20:49:47 +01:00
0e81fa3bc9 feat: update to nextcloud 30.0.2 2024-11-07 13:10:07 +01:00
cdbe1f1083 feat: change destktop design 2024-11-07 13:09:52 +01:00
c0e2d93c49 add website 2024-11-06 13:15:38 +01:00
c9a024840b changes 2024-11-05 12:48:30 +01:00
d8db7df64e add web.social-grow.tech 2024-10-24 00:26:32 +02:00
ef8f774f4f update ddev 2024-10-24 00:25:44 +02:00
fa0a61f581 change nvim config 2024-10-24 00:25:39 +02:00
addb5d7383 add borgbackup 2024-10-24 00:25:22 +02:00
3aa2d3d3c8 some fixes for mail server 2024-10-24 00:25:14 +02:00
7bbd895115 new shelly bulbs 2024-10-24 00:24:52 +02:00
3eb9ce0e89 changes 2024-10-18 15:24:20 +02:00
c681eb3139 changes 2024-10-16 20:24:40 +02:00
b7bfb0f62a add fw-new 2024-09-27 23:10:58 +02:00
92099bd1e9 many changes 2024-09-03 14:47:06 +02:00
fb32b88798 many changes 2024-09-03 14:47:01 +02:00
f86996cd28 add zammad to fw vm, add web-arm machine 2024-08-16 22:42:00 +02:00
d46990b7fb change multimedia switch trigger 2024-07-28 16:26:13 +02:00
a54a56ca6a changes 2024-07-24 11:55:00 +02:00
fdda6d3caa add new git projects 2024-07-15 17:06:20 +02:00
b92b9b963a some changes 2024-07-12 22:14:20 +02:00
4a183af66c many changes 2024-07-08 17:36:11 +02:00
213101f8cd fix wol 2024-07-07 16:38:34 +02:00
ad8090f8f8 nb changes, add wol script to fw 2024-07-07 16:33:22 +02:00
84cd8fa1cc change address book 2024-07-06 14:29:35 +02:00
66dcb2a9f2 add known_hosts file to persist 2024-07-06 14:21:59 +02:00
9db05facea fix waybar icons, add project, add fido token 2024-07-06 12:43:59 +02:00
b3f80e0818 only create symlink if not present 2024-07-05 13:16:42 +02:00
53fc65d4fb change sddm theme 2024-07-05 13:03:10 +02:00
5f11d8d5e5 remove old nb host, switch to sddm 2024-07-05 02:45:55 +02:00
a20751002e change wallpaper 2024-07-05 01:03:17 +02:00
99e6f5e476 fix gtk2 theme 2024-07-04 22:44:56 +02:00
b0f3174ed0 fix missing semilcon 2024-07-04 22:43:55 +02:00
c7df114378 add dark gtk theme 2024-07-04 22:43:35 +02:00
2e55d24791 firefox disable password manager 2024-07-04 22:36:32 +02:00
cc9c66ba1b fix signature 2024-07-04 17:45:08 +02:00
2dcde1da86 add email signature 2024-07-04 17:34:40 +02:00
65619f81b0 link Downloads Vault 2024-07-04 11:56:32 +02:00
c927ac6478 add copilot folder and cryptomator vault 2024-07-04 11:55:57 +02:00
6b4dd0c291 add rustdesk and docker to persist 2024-07-04 11:08:41 +02:00
51534cc80f remove sops key 2024-07-04 01:05:21 +02:00
157eaefa95 add networkmanager 2024-07-04 01:04:25 +02:00
b2fe9fed11 add password 2024-07-04 01:00:06 +02:00
8facc35331 add stuff 2024-07-04 00:50:08 +02:00
66288470f9 add project_history differt 2024-07-03 22:49:55 +02:00
2b440d88f7 add persistence folder 2024-07-03 21:50:29 +02:00
a1907c8adb some changes 2024-07-03 21:37:42 +02:00
30f5ca374f add bind mount 2024-07-03 20:08:50 +02:00
51c2636c42 add nb-new 2024-07-03 20:08:09 +02:00
982a12ba08 many changes 2024-07-02 23:03:24 +02:00
972084cd65 change domain 2024-06-11 01:01:43 +02:00
3c7a9b3eae add myhidden.life scheduler 2024-06-10 21:45:22 +02:00
45f1713443 changes 2024-06-10 18:52:00 +02:00
5d0827848e many changes 2024-06-03 13:49:35 +02:00
c9e4ab6af0 changes to home assistant, docker images, rustdesk relay 2024-02-28 23:38:15 +01:00
8650c3f6ee fix ip typo in dhcpd 2024-02-18 22:42:17 +01:00
802fcbd47f change to firewall and dns 2024-02-18 22:39:34 +01:00
57a215fec4 change to lights and multimedia home-assistant 2024-02-18 22:39:03 +01:00
e6baa25011 remove not needed stuff 2024-02-18 22:38:47 +01:00
5ebcd0818b many changes 2024-02-16 22:24:54 +01:00
b4bf0ee486 new changes 2024-02-02 12:40:23 +01:00
270880c4f2 some fixes 2024-01-29 19:46:40 +01:00
b622a620be remove testing amz entries 2024-01-18 22:22:03 +01:00
b1ec7c6d73 change deployment keys for paraclub 2023-12-28 16:34:46 +01:00
46d1483880 fix internet for guest network, changes to authelia 2023-12-15 14:46:10 +01:00
8b20f2b13c changes for home assistang, add browsers to nb 2023-12-14 18:01:46 +01:00
3b207db752 fix dhcp lease to unbount, git runner and openconnect keepalive 2023-12-13 17:51:04 +01:00
82bda66d24 add deconz 2023-12-10 18:05:49 +01:00
b330d4610e initial deconz implementation 2023-12-10 10:03:51 +01:00
027be96f9c add home-assistant nix configuration 2023-12-09 22:55:41 +01:00
bdca649697 allow acces to web proxy 2023-12-09 18:08:35 +01:00
06c876eba5 initial home assistant change 2023-12-09 15:16:49 +01:00
9db6404ee7 add ssh key to gitea 2023-12-09 13:06:00 +01:00
7a5c217c9d gitea changes 2023-12-09 12:45:12 +01:00
8adb0328ab fix fleet 2023-12-09 11:26:53 +01:00
8db6e53f51 install inotify for testing 2023-12-09 11:26:08 +01:00
277b20f687 fix git host to just host config files 2023-12-08 17:03:14 +01:00
b8bc7ed40f add key to sftp 2023-12-08 17:02:11 +01:00
ded214a0e6 try 2023-12-08 14:28:43 +01:00
dd0c8a7b99 add gitea user 2023-12-08 14:28:03 +01:00
52b57a125b fix path 2023-12-08 14:12:22 +01:00
df8c5a9dbe add git and bento to git container 2023-12-08 14:12:02 +01:00
b08bdf8499 fix import path 2023-12-08 14:01:36 +01:00
cd8b5b8d3e add fleet and bento to git 2023-12-08 14:01:00 +01:00
317a574583 change php package 2023-12-08 13:59:32 +01:00
e8f16a7cce remove nextcloud 2023-12-08 13:58:06 +01:00
de318cde63 remove old hosts 2023-12-08 13:56:58 +01:00
c512a56c11 change runner token 2023-12-08 00:58:58 +01:00
6141537816 change network to server 2023-12-07 11:45:27 +01:00
8613adba86 remove host network from gitea runner 2023-12-07 11:43:24 +01:00
82a49c4728 fix vpnc 2023-12-07 11:37:00 +01:00
59fd6b7d3f try openconnect again 2023-12-07 11:35:10 +01:00
301b263993 try lib 2023-12-07 11:32:19 +01:00
ca3dbf7bc4 fix 2023-12-07 11:29:52 +01:00
7ee23f5571 add missing lib 2023-12-07 11:29:40 +01:00
c7a2de295a fix semilcon 2023-12-07 11:29:21 +01:00
35b1126a97 try vpnc script 2023-12-07 11:28:48 +01:00
458f6ff0a4 change dns 2023-12-07 11:00:04 +01:00
3d57315867 fix resolv 2023-12-07 10:32:11 +01:00
9a1db71073 enable resolved again 2023-12-07 10:27:03 +01:00
51eb78429c change container runner 2023-12-07 10:18:41 +01:00
a5322ef788 change container network to host 2023-12-07 10:09:33 +01:00
7e85907150 remove resolved 2023-12-07 10:06:37 +01:00
42f8c287ed add containers conf 2023-12-07 10:04:19 +01:00
cf1bf90dc8 try dns stub extra 2023-12-07 09:32:33 +01:00
1260d88dc2 try dns stub extra 2023-12-07 09:32:20 +01:00
b733a98a67 fix dnsstup 2023-12-07 09:29:23 +01:00
686e9f3ac3 resolved on every ip 2023-12-07 09:26:05 +01:00
dc29de6da6 add dns 2023-12-07 09:17:53 +01:00
71191632d4 firewall changes 2023-12-07 09:09:31 +01:00
83a2a9cd46 allow dns from everywhere 2023-12-07 09:01:36 +01:00
40fb010825 add firewall for resolved 2023-12-07 08:40:51 +01:00
3ea51364e2 add resolved 2023-12-07 08:40:11 +01:00
dffa1d96cf try with env 2023-12-07 08:04:38 +01:00
ba0ec44434 try gitea runner with network 2023-12-07 07:52:16 +01:00
934a4874a5 just add dns 2023-12-07 07:46:43 +01:00
2924d613a2 change secret 2023-12-06 21:26:19 +01:00
50bd3d9e17 change docker image 2023-12-06 21:23:19 +01:00
364268aa7f make options to string 2023-12-06 21:19:41 +01:00
9fd574468a fix container options for gitea 2023-12-06 21:17:56 +01:00
2201e054b9 also add dns option 2023-12-06 21:12:15 +01:00
81d90636f5 try to change options 2023-12-06 21:11:04 +01:00
31f54d9de2 fix semilcon 2023-12-06 21:04:13 +01:00
c48e5aa581 try gitea option 2023-12-06 21:03:47 +01:00
6ef2b4ae41 allow git runner to wan 2023-12-06 20:37:04 +01:00
c8ebc7eff5 change firewall 2023-12-06 20:33:47 +01:00
9ced007c27 dhcp for git static 2023-12-06 20:12:48 +01:00
47cdc1d854 allow traffic to dns from everywhere 2023-12-06 20:10:32 +01:00
783e0840c9 change gitea runner 2023-12-06 19:03:58 +01:00
fa82522895 remove podman user 2023-12-06 18:57:06 +01:00
405372e9d5 try to fis uid and gid 2023-12-06 18:54:31 +01:00
cd4be108c4 add user to podman group 2023-12-06 18:50:08 +01:00
552766ec99 add user to docker group 2023-12-06 18:45:36 +01:00
b9f1322690 change runner token 2023-12-06 18:34:34 +01:00
dabbf0e91a fix podman 2023-12-06 18:30:44 +01:00
c8a715bb67 try to fix gitea runner 2023-12-06 18:29:18 +01:00
02aa59a001 add podman 2023-12-06 18:27:36 +01:00
45d4a62af2 try more host packages 2023-12-06 18:24:58 +01:00
6956db456d change runner token 2023-12-06 18:10:52 +01:00
2035e6be96 change gitea runner 2023-12-06 18:07:30 +01:00
7767dabc47 change gitea runner 2023-12-06 18:06:26 +01:00
96b52f7bd8 add nodejs to gitea 2023-12-06 18:00:24 +01:00
a19a73d743 enable podman at runner 2023-12-06 17:54:02 +01:00
5785169d43 fix firewall rule 2023-12-06 17:41:25 +01:00
97198e7404 add nodejs to gitea runner 2023-12-06 17:36:55 +01:00
847ae4a2db make git and bento publicly available 2023-12-06 17:08:05 +01:00
6cfaa64fd2 remove wan from firewall, combine rule 2023-12-06 15:20:48 +01:00
a45efc80dd fix dns 2023-12-06 15:09:51 +01:00
c658e237e2 fix dot forward 2023-12-06 14:58:00 +01:00
5ec76883c7 unbound move forward zones up 2023-12-06 14:47:28 +01:00
140020c217 allow server to vpn 2023-12-06 14:41:52 +01:00
2375a00002 fix dns stuff 2023-12-06 14:37:14 +01:00
1a6a8aa584 forward all established 2023-12-06 14:36:06 +01:00
3958b1891c add firewall rule 2023-12-06 14:33:34 +01:00
8ba21ec498 set omada autostart to false 2023-12-06 14:06:24 +01:00
5d69b79790 change firewall 2023-12-06 12:50:41 +01:00
8ffefca044 try to fix nat 2023-12-06 12:39:45 +01:00
ff0dab4b03 add podman sock to gitea runner 2023-12-06 10:27:29 +01:00
f3cea82f12 fix secret 2023-12-06 09:55:29 +01:00
7c759b702f add mount for gitea runner 2023-12-06 09:55:11 +01:00
4d6118a021 upgrade to 23.11 2023-12-06 09:19:30 +01:00
84321167f8 siwtch to fonts.packages 2023-12-06 01:46:16 +01:00
9b797bfdc2 add borg-delete 2023-12-06 01:42:45 +01:00
15bb5f5351 add comments to borg 2023-12-06 01:38:45 +01:00
9eca272e46 dont backup containers 2023-12-06 01:25:59 +01:00
772353bd71 fix storage box user 2023-12-06 01:15:30 +01:00
dc112c97c9 fix home of gitea-runner 2023-12-06 00:41:26 +01:00
7bc17f648b fix secret 2023-12-06 00:15:31 +01:00
6cc1f011f7 fix secret name 2023-12-06 00:01:39 +01:00
63baa26bce fix user for sops 2023-12-05 23:43:12 +01:00
c02140d91d missing semilcon 2023-12-05 23:40:36 +01:00
62e9541d42 add gitea runner labels 2023-12-05 23:40:22 +01:00
ef176a800b fix typo 2023-12-05 23:35:57 +01:00
38631545f1 add gitea runner uid gid 2023-12-05 23:35:19 +01:00
528c030588 add gitea runner 2023-12-05 23:34:41 +01:00
fdd00af834 enable gitea actions 2023-12-05 22:55:40 +01:00
bf03d3a3a8 add git 2023-12-05 22:32:51 +01:00
5547534e6c fix changing ssh key at git 2023-12-05 22:31:33 +01:00
31521248b8 enable openconnect 2023-12-05 22:23:18 +01:00
d8ebc6d1cf disable resolvconf 2023-12-05 22:21:06 +01:00
ca6ab23403 disable openconnect because of dns 2023-12-05 20:39:45 +01:00
0eead50afd switch bento config 2023-12-05 20:31:03 +01:00
d4a5d45f68 add fleet and gitea unsecure 2023-12-05 20:11:40 +01:00
f3d64c7249 disable currently unused stuff 2023-12-05 19:50:45 +01:00
fe7a61e848 add openssh t git 2023-12-05 19:03:25 +01:00
f721a2f969 add nameserver 2023-12-05 18:56:03 +01:00
b61734c4c5 change gitea user 2023-12-05 17:50:57 +01:00
35fe864a8f add old git 2023-12-05 17:44:58 +01:00
008ca8b5b4 remove git from dns 2023-12-05 17:44:19 +01:00
532c7d926f remove resolved 2023-12-05 17:11:31 +01:00
fb75780712 fix remote control unbound 2023-12-05 16:57:47 +01:00
3a04928079 fix unbound 2023-12-05 16:53:05 +01:00
b4fe570ee4 fix control-enable 2023-12-05 16:50:13 +01:00
679c86fc4f add control enable 2023-12-05 16:46:45 +01:00
7d87c8ed75 git domain keep old 2023-12-05 16:39:10 +01:00
3a8628cdd0 add packages 2023-12-05 16:24:21 +01:00
d602ce42ee add unbound-sync 2023-12-05 16:23:36 +01:00
e902b96e08 kea 2023-12-05 14:31:23 +01:00
1fa79a5474 add qualified suffy kea 2023-12-05 14:13:37 +01:00
bb5294e890 change container names 2023-12-05 13:21:06 +01:00
23b62a83c4 add ip for git 2023-12-05 13:17:46 +01:00
76e8ef8428 try 2023-12-05 12:34:41 +01:00
7bbca7d2ae try 2023-12-05 12:32:24 +01:00
a14e17f92a try 2023-12-05 12:31:32 +01:00
b43cdd98f3 try 2023-12-05 12:29:55 +01:00
3d5e94c2a4 try 2023-12-05 12:28:56 +01:00
2c8bd2e098 try 2023-12-05 12:28:29 +01:00
9e0624eaf1 try 2023-12-05 12:27:09 +01:00
85cdde777b test 2023-12-05 12:21:03 +01:00
51f934f57c try 2023-12-05 12:20:32 +01:00
699b5cc422 try 2023-12-05 12:19:53 +01:00
e4a5915c5b fix 2023-12-05 12:17:38 +01:00
aede371ff1 fix 2023-12-05 12:17:03 +01:00
cb8e2526e3 fix cids 2023-12-05 12:11:46 +01:00
855bd4d3ec try 2023-12-05 11:53:38 +01:00
bc6e70971c change cids to readonly 2023-12-05 11:51:37 +01:00
280dea226c fix staticids 2023-12-05 11:42:08 +01:00
b2d71564fe try 2023-12-05 11:34:36 +01:00
96138e0099 try 2023-12-05 11:33:13 +01:00
1d42a1c405 test 2023-12-05 11:31:23 +01:00
4832fcea2f try to fix ids 2023-12-05 11:19:28 +01:00
1030766305 fix ids 2023-12-05 11:14:31 +01:00
2be2aa013d change staticids 2023-12-05 11:13:20 +01:00
560c3967aa fix semilcon 2023-12-05 11:10:51 +01:00
28ff135610 add static ids 2023-12-05 11:08:50 +01:00
d29a421cc7 fix semilcon 2023-12-05 10:53:19 +01:00
846119ebfe fix missing semilcon 2023-12-05 10:52:43 +01:00
4509664a10 try to change unbound uid gid 2023-12-05 10:51:35 +01:00
10460ca8b2 add gitea cert to nginx group 2023-12-05 10:39:15 +01:00
49d8907853 add gitea 2023-12-05 10:34:25 +01:00
2748929e66 fix server ips 2023-12-05 10:30:02 +01:00
46278f9f72 try different interface 2023-12-05 09:42:09 +01:00
b45bf60e69 add netavark 2023-12-05 09:21:41 +01:00
2ff59533a0 add nameservers 2023-12-05 09:14:56 +01:00
5d60630606 podman network 2023-12-05 09:09:21 +01:00
94e5d8ef86 add server network 2023-12-05 09:08:48 +01:00
83f2a219c4 change network 2023-12-05 09:03:31 +01:00
e039fa91da add network interface 2023-12-05 08:48:18 +01:00
ea8768931f fix podman 2023-12-05 08:43:41 +01:00
4f3b06dcdf add omada 2023-12-05 08:42:44 +01:00
29952a822a fix omada hash 2023-12-04 19:23:59 +01:00
6e0b29bbcd add lib 2023-12-04 17:52:21 +01:00
a96451a797 add mongodb unfree 2023-12-04 17:51:54 +01:00
7b50808621 add omada 2023-12-04 17:49:43 +01:00
2a5c40103a missing semilcon 2023-12-04 17:17:09 +01:00
d6d0e2d734 change dns 2023-12-04 17:14:00 +01:00
b3c2b620b8 fix unbound 2023-12-04 17:01:34 +01:00
8b096a23cc add route 2023-12-04 16:50:23 +01:00
f8d7fc77a9 add unbound default gateway 2023-12-04 16:30:55 +01:00
a5d438d3c8 fix dns 2023-12-04 16:16:12 +01:00
947d929d67 switch all dns to ns container 2023-12-04 16:14:59 +01:00
e55094da3b try to fix unbound cert group 2023-12-04 16:04:47 +01:00
0e4ba6ba5f add state version 2023-12-04 15:48:41 +01:00
7a5344a6b2 fix 2023-12-04 15:39:09 +01:00
67490acd66 add git acme 2023-12-04 15:27:15 +01:00
8f53cd9867 try again acme dir 2023-12-04 15:25:59 +01:00
0eed1991d8 fix missing semilcon 2023-12-04 15:23:55 +01:00
431e301673 give unbound fixed ip address 2023-12-04 15:23:12 +01:00
cb01ec7e4c change unbound 2023-12-04 15:22:32 +01:00
1dbba8eac6 make unbound listen on all interfaces 2023-12-04 13:55:13 +01:00
0353156163 change gitea container 2023-12-04 13:49:38 +01:00
807dd5124e allow dns from everywhere 2023-12-04 13:46:09 +01:00
35c8bbb1ac add vserver 2023-12-04 13:11:05 +01:00
70e9e79717 remove resolved 2023-12-04 13:02:38 +01:00
52109abbc0 add ephemeral 2023-12-04 12:59:17 +01:00
6ca4ad7ce4 resolv 2023-12-04 12:55:11 +01:00
f619b5536b fix gitea 2023-12-04 12:50:22 +01:00
c314da240e add kea to server interface 2023-12-04 12:47:19 +01:00
f5a2793533 try with dhcp 2023-12-04 12:44:58 +01:00
3befd4ebb8 try again gitea 2023-12-04 12:42:50 +01:00
ffec38c03c try again 2023-12-04 12:25:06 +01:00
5ba076ecdd fix interface 2023-12-04 12:17:00 +01:00
886db8a070 fix firewall 2023-12-04 12:12:11 +01:00
56d613b570 try different interface 2023-12-04 11:56:30 +01:00
c68f86d904 gitea 2023-12-04 11:53:17 +01:00
906725fb9b try macvlan again 2023-12-04 11:50:24 +01:00
5daf793143 remove all podman stuff 2023-12-04 11:35:50 +01:00
ed14fb9b0e try to change fw 2023-12-04 11:33:51 +01:00
8db9d3382e add gitea insecure 2023-12-04 11:20:50 +01:00
1f008042ac fix 2023-12-04 11:17:55 +01:00
520979d85b try firewall change 2023-12-04 11:16:44 +01:00
56a35728c1 revert 23.11 2023-12-04 09:17:09 +01:00
add183ed8b disable deconz 2023-12-04 08:29:04 +01:00
518d043faf firewall for 23.05 2023-12-04 08:28:38 +01:00
4436dad725 firewall 2023-12-04 08:22:57 +01:00
4c91007286 change firewall rules 2023-12-04 08:22:15 +01:00
76cd48e6af change fw rule 2023-12-03 22:56:12 +01:00
1a4956af6e fix firewall 2023-12-03 22:48:56 +01:00
5d58ae7904 remove bindmounts 2023-12-03 22:41:59 +01:00
70fd15c5dd add nat 2023-12-03 22:34:58 +01:00
38d5a26e78 fix firewall for bridge interface 2023-12-03 22:17:06 +01:00
18747fe129 remove podman ip for testing 2023-12-03 22:07:28 +01:00
e3e09db610 fix ip 2023-12-03 22:00:36 +01:00
d764cbde57 fix firewall 2023-12-03 22:00:07 +01:00
5da0671fc0 add gitea to firewall 2023-12-03 21:50:19 +01:00
31e3b526f1 use ip 2023-12-03 21:45:19 +01:00
09379f901a add privatenetwork 2023-12-03 21:41:09 +01:00
d8a94d3e5c try again with bridge 2023-12-03 21:37:53 +01:00
75daf49c98 add vserver interface to fw 2023-12-03 21:29:52 +01:00
bae3bb97fd fix ip 2023-12-03 21:26:50 +01:00
22a59d1028 remove sysbox 2023-12-03 21:23:40 +01:00
646c909612 fix interface name 2023-12-03 21:22:35 +01:00
7b6008a6c4 try to fix networking 2023-12-03 21:18:51 +01:00
57543e5386 remove firewall from container 2023-12-03 21:12:24 +01:00
893e5bc1da remove flag 2023-12-03 21:07:57 +01:00
59ee7435b2 change to mcvlans 2023-12-03 20:58:44 +01:00
aac55293a4 add server to dhcp 2023-12-03 20:49:12 +01:00
7e41b61bac disable acme 2023-12-03 20:45:11 +01:00
d6028880e7 fix container 2023-12-03 20:44:06 +01:00
729e626326 add nginx 2023-12-03 20:43:30 +01:00
8e373cec3f gitea container 2023-12-03 20:37:32 +01:00
f3263cda61 try gitea container 2023-12-03 20:36:48 +01:00
cac9721b0c fix gitea 2023-12-03 19:54:46 +01:00
10bb263fb3 ip to bridgeserver 2023-12-03 19:49:17 +01:00
fce723169d fix networking 2023-12-03 19:48:23 +01:00
5ace56169a change to server bridge 2023-12-03 19:46:35 +01:00
0bae524940 try lan interface in container 2023-12-03 19:35:21 +01:00
787903f299 try container with infrastructure vlan 2023-12-03 19:31:00 +01:00
62d6e85e5a try to fix 2023-12-03 19:28:10 +01:00
a1bbf635d3 try to run gitea in container 2023-12-03 19:27:13 +01:00
a4ce928926 fix sysbox service file 2023-12-03 16:51:29 +01:00
9e291aea76 add kmod to sysbox 2023-12-03 16:22:39 +01:00
68d1456b45 fix sysbox service 2023-12-03 16:19:46 +01:00
52b6eddb40 fix systemd file 2023-12-03 16:18:52 +01:00
7dba4938e6 fix service 2023-12-03 16:17:45 +01:00
100268f4a7 change service ype 2023-12-03 16:15:48 +01:00
b4e285c00c fix sysbox services 2023-12-03 16:12:32 +01:00
6390ace14c fix typo 2023-12-03 16:11:31 +01:00
9891fb3f35 add sysbox services 2023-12-03 16:11:07 +01:00
b074b8dff7 fix flattening 2023-12-03 15:46:00 +01:00
44ce69444d fix wrap 2023-12-03 15:41:40 +01:00
601b031d44 fix hash 2023-12-03 15:38:54 +01:00
e72cf1585a try sysbox 2023-12-03 15:37:34 +01:00
6ebd768107 fix hash 2023-12-03 15:23:13 +01:00
efb6bb2c56 change license 2023-12-03 15:20:33 +01:00
641b2b0edc sysbox 2023-12-03 15:17:04 +01:00
02f73c8ee2 add sysbox 2023-12-03 15:15:29 +01:00
4b80ae9b9b change home-assistand dns and ip 2023-12-02 23:47:05 +01:00
dc80bb1a46 dont pull drone image each launch 2023-12-02 21:46:47 +01:00
6041684856 change to gitea 2023-12-02 20:03:02 +01:00
21733a4b12 cast to string 2023-12-02 19:54:42 +01:00
db516ef0b7 add uid and gid to gitea 2023-12-02 19:48:08 +01:00
e67fefa995 try uid again 2023-12-02 19:45:23 +01:00
1d8d6b6de7 try only user id 2023-12-02 19:43:51 +01:00
c7260cce60 try to fix gitea 2023-12-02 19:41:03 +01:00
2ea53aa3ea change uid and gid of gitea 2023-12-02 19:26:32 +01:00
7c5cf501d5 fix gitea config 2023-12-02 19:18:32 +01:00
297e0441bb fix gitea db 2023-12-02 19:09:26 +01:00
47b76ec980 fix header 2023-12-02 19:00:11 +01:00
eb80b95d15 fix proxy set header 2023-12-02 18:30:53 +01:00
7f7c4ffa1b try gitea again with docker 2023-12-02 18:19:02 +01:00
2f48c81e1a add secrets 2023-12-02 12:29:38 +01:00
d8dac4e2de try to fix secret 2023-12-02 12:19:15 +01:00
c00d3087a5 fix typo in firewall rule 2023-12-02 11:38:52 +01:00
641ebc81e2 dhcp server on infrastructure 2023-12-02 11:20:24 +01:00
bf6a9d31a9 remove unneeded rule 2023-12-02 11:18:16 +01:00
f9d4f9ad5f allow infrastructure to podman 2023-12-02 11:11:39 +01:00
1718f4db11 fix firewall rules 2023-12-02 00:26:54 +01:00
69dacf6d30 fix gitea 2023-12-02 00:17:14 +01:00
81f6846cf9 add modules 2023-12-02 00:15:59 +01:00
13aa3b6dc1 host gitea on firewall 2023-12-02 00:10:36 +01:00
c8c72bcb0c fix app.ini 2023-12-02 00:06:22 +01:00
e8f76a82cc fix container name 2023-12-02 00:04:35 +01:00
76d009d5df remove acme because proxy is already doing it 2023-12-02 00:03:51 +01:00
33c5971929 add gitea 2023-12-02 00:02:37 +01:00
58befac8b9 nftables 2023-12-01 23:40:17 +01:00
9fe8c38772 try again with nftables 2023-12-01 23:38:45 +01:00
6af562cc73 change networking 2023-12-01 22:27:42 +01:00
4158730c6a missing semilcon 2023-12-01 21:12:29 +01:00
d47ecc9ceb add omada ip 2023-12-01 21:11:24 +01:00
6ebf7e7f23 remove server from dhcp 2023-12-01 20:57:47 +01:00
5ce972a635 change networking of server interface 2023-12-01 20:55:28 +01:00
26beae17a9 allow podman0 network 2023-12-01 20:46:21 +01:00
d407f35d5d change podman networking 2023-12-01 20:45:24 +01:00
4c98785f39 change omada 2023-12-01 20:43:16 +01:00
cfa0121853 make omada network host 2023-12-01 20:42:30 +01:00
d0cb65965d allow server-shim to wan 2023-12-01 20:28:45 +01:00
7050b90fca fix 2023-12-01 20:26:09 +01:00
da33caa374 try to change network 2023-12-01 20:25:45 +01:00
baf796dcd7 change gateway 2023-12-01 20:18:48 +01:00
00dec8a068 make dns enables 2023-12-01 20:14:04 +01:00
709c848813 try podman again 2023-12-01 20:11:02 +01:00
93e768487a fix 2023-12-01 19:34:15 +01:00
e59d39a2ba fix 2023-12-01 19:34:00 +01:00
23d4ce282f fix 2023-12-01 19:32:15 +01:00
f3fc94f0cb qemu 2023-12-01 19:31:32 +01:00
b419bdb1fe fix typo 2023-12-01 19:27:33 +01:00
d6756bd94b add lib 2023-12-01 19:27:09 +01:00
160f16e35f add args 2023-12-01 19:26:35 +01:00
5acea13591 add hypervisor 2023-12-01 19:25:01 +01:00
aed7c73032 fix firewall rules 2023-12-01 18:19:41 +01:00
579b768230 try iptables instead of nftables 2023-12-01 17:46:47 +01:00
db26c82ebd add dhcp proxy 2023-12-01 17:10:15 +01:00
b1a4dfc578 try macvlan again 2023-12-01 17:07:54 +01:00
7368a44d0d add podman to firewall 2023-12-01 16:43:10 +01:00
7109987091 remove container proxy 2023-12-01 16:39:42 +01:00
172f36c465 disable drone 2023-12-01 14:10:58 +01:00
500b2c6982 change macvlan to bridge 2023-12-01 13:50:37 +01:00
4a5851457f add dhcp driver again 2023-12-01 13:25:37 +01:00
e750862680 change network 2023-12-01 13:22:44 +01:00
d52c70df51 try to fix network 2023-12-01 13:19:21 +01:00
b72910e8b4 change podman interface to lan 2023-12-01 13:11:26 +01:00
f69bcce5ef rollback log 2023-12-01 13:04:39 +01:00
5791df402d add debug logging 2023-12-01 13:00:56 +01:00
51f6f0e016 netavark 2023-12-01 12:44:22 +01:00
66a29ff5d3 change nv-proxy 2023-12-01 12:33:06 +01:00
e0a558527d change nv proxy 2023-12-01 12:32:33 +01:00
aa75095654 change dhcp proxy 2023-12-01 12:28:29 +01:00
750d8e1596 change ipam to dhcp 2023-12-01 12:15:51 +01:00
4b1ef58992 add podman dhcp 2023-12-01 12:02:38 +01:00
361e93b136 change omada network 2023-12-01 11:59:58 +01:00
b12eeef06d try to fix network 2023-12-01 11:57:45 +01:00
f277fb8953 try podman network 2023-12-01 11:42:22 +01:00
140b1d793a fix servernet 2023-12-01 11:39:21 +01:00
b4ebe4d3f8 fix json 2023-12-01 11:37:20 +01:00
e4559816d0 add servernet 2023-12-01 11:36:12 +01:00
404845872b remove old podman config 2023-12-01 11:28:38 +01:00
98facac514 fix podman dhcp socket 2023-12-01 11:17:04 +01:00
eb135c1031 remove network name 2023-12-01 11:07:39 +01:00
9e5e253168 fix service 2023-12-01 11:00:44 +01:00
c3f87ce990 change podman 2023-12-01 10:58:24 +01:00
3ebbe5d7d4 change podman config 2023-12-01 10:56:35 +01:00
7580f897c2 add omada 2023-12-01 10:38:26 +01:00
66aac3ac19 add allow to unbound 2023-12-01 00:47:06 +01:00
6cab771a30 change unbound interface 2023-12-01 00:40:36 +01:00
370d31dc5e add dhcp option 2023-12-01 00:31:50 +01:00
6b06713a08 add router to dhcp server 2023-12-01 00:26:58 +01:00
4bebf95f11 remove config 2023-12-01 00:15:24 +01:00
4f22eeeaa3 fix typo 2023-12-01 00:14:22 +01:00
addb063cee try some fw stuff 2023-12-01 00:13:21 +01:00
83ac3fea42 try policy accept 2023-11-30 23:59:02 +01:00
fc0ea1d622 disable standard firewall 2023-11-30 23:52:11 +01:00
460a901633 fix 2023-11-30 23:03:15 +01:00
ced81c2e89 enable forwarding 2023-11-30 23:02:16 +01:00
9810882b95 try only wan masquerade 2023-11-30 22:57:58 +01:00
4d38581dad change fw rule 2023-11-30 22:36:00 +01:00
0ec9252419 add wan to allowed everywhere 2023-11-30 22:31:32 +01:00
55c2869bac fix semilcon 2023-11-30 22:18:17 +01:00
1674dd0ec2 change networking 2023-11-30 22:17:25 +01:00
6235f34a3b fix option-data 2023-11-28 21:49:54 +01:00
67559f02ea remove ddns from dhcp 2023-11-28 21:45:58 +01:00
a4175263a4 change dhcpddns 2023-11-28 21:41:07 +01:00
fea6d863d3 fix cert path and add tls to cert 2023-11-28 21:27:08 +01:00
30fe42e857 disable tls 2023-11-28 21:22:48 +01:00
4517d8f207 try to fix unbound 2023-11-28 21:21:15 +01:00
7e1640b3e8 change git server to old ip and add tls 2023-11-28 21:10:58 +01:00
3617bf22be move local data to server block unbound 2023-11-28 21:06:03 +01:00
cc243d4c4d add local-data 2023-11-28 20:58:12 +01:00
83a2c7848d try local-zone 2023-11-28 20:54:03 +01:00
6ad5b8c98a change to internal dns 2023-11-28 20:52:05 +01:00
885660c4e4 fix unbound for local traffic 2023-11-28 20:48:21 +01:00
da256dadaa fix secrets file 2023-11-28 20:32:28 +01:00
45598f92e5 change fw 2023-11-28 19:17:34 +01:00
be99f1c89a update fleet ssh key 2023-11-28 18:49:09 +01:00
87b3c81e2f update secrets 2023-11-28 18:48:04 +01:00
08731a72a3 changes to fw and unbound 2023-11-28 17:57:32 +01:00
017be187eb allow wan access to fw temporarily 2023-11-28 17:01:46 +01:00
4d95309ed6 comment out flowtable 2023-11-28 16:55:58 +01:00
b0282c3013 disable flow offload 2023-11-28 16:54:08 +01:00
e0d314fe3a comment out mdns fw rule 2023-11-28 16:52:16 +01:00
fb41a82c31 fix name of epicenter 2023-11-28 16:50:12 +01:00
d07e0d8ec5 update ssh key 2023-11-28 15:56:53 +01:00
3da0233861 change secrets key 2023-11-28 15:55:38 +01:00
a11e5b97f3 add missing lib 2023-11-28 15:52:57 +01:00
bc7b3c059c add lib 2023-11-28 15:52:33 +01:00
c45fb4d230 add iso, change networking for fw 2023-11-28 15:44:54 +01:00
d1437de4b1 fix drone to podman and add dovecot secret 2023-11-27 00:48:55 +01:00
41c343c336 add sieve-spam-filter fix nb hardware 2023-11-27 00:39:54 +01:00
0e57b505bc fix wireguard sops 2023-11-27 00:34:14 +01:00
cf5b1d32bc mail fix secret 2023-11-27 00:31:44 +01:00
8be0cce54a many changes to fw, small fixes to nb 2023-11-27 00:29:16 +01:00
ef97530433 change steamdeck 2023-11-26 17:51:57 +01:00
1c174baf5c fix version 2023-11-26 16:35:01 +01:00
9bc84699de change config 2023-11-26 16:32:24 +01:00
ba6ed4c5a8 fix hash for steamdeck 2023-11-26 16:26:17 +01:00
2f3831683b update steamdeck 2023-11-26 16:24:49 +01:00
64dab4fdf3 change luks 2023-11-23 00:49:24 +01:00
33aa510335 try fido 2023-11-23 00:36:19 +01:00
407dfd5d3a try fido instead of yk 2023-11-23 00:35:21 +01:00
648a643252 fix ykfde_enroll 2023-11-22 23:53:36 +01:00
e02320fb07 add sleep 2023-11-22 23:40:00 +01:00
f0493aa05d fix ykfde 2023-11-22 21:54:36 +01:00
12c05e146c fix ykfde_enroll 2023-11-22 17:50:59 +01:00
bfdff27021 ykfde 2023-11-22 16:58:32 +01:00
c5032b4e95 fix ykfde_enroll 2023-11-22 16:51:13 +01:00
e76c1eaf77 add pbkdf2-sha512 2023-11-22 16:20:39 +01:00
9d88cb16fc try fix 2023-11-22 16:15:37 +01:00
3f1ba57d29 fix 2023-11-22 16:06:33 +01:00
3f66618dea fix 2023-11-22 16:01:53 +01:00
92afa38c2e fix nb overlay 2023-11-22 16:00:43 +01:00
9850e02bda fix app name 2023-11-22 15:57:30 +01:00
2591118a5d fix ykfde if file exists 2023-11-22 15:54:19 +01:00
dba986fadc change ykfde to wrap with all needed path 2023-11-22 15:35:17 +01:00
6ec1378c97 add unsupported gpu to sway 2023-11-20 20:28:13 +01:00
42c009af19 try nvidia again 2023-11-20 19:58:01 +01:00
0774fe0c5a remove nvidia 2023-11-20 19:43:10 +01:00
fb328941d8 add nvidia kernel module 2023-11-20 19:32:21 +01:00
84ca75ef59 add nvidia kernel package 2023-11-20 18:39:48 +01:00
9252bdda07 fix 2023-11-20 18:04:49 +01:00
04d696be64 add steam 2023-11-20 17:44:07 +01:00
a598d28959 add gpu offload 2023-11-20 17:38:03 +01:00
8530ee662b add gaming specialisation 2023-11-20 17:21:15 +01:00
38d4da83c8 add nvidia gpu 2023-11-20 16:02:20 +01:00
b81504eb62 add paraclub api vhost 2023-11-16 21:37:00 +01:00
7999721e1b add live system for paraclub 2023-11-16 18:37:44 +01:00
a63b679b66 remove lspconfig for lua 2023-11-16 15:42:50 +01:00
c24d7fb468 change terminal size 2023-11-16 15:36:40 +01:00
f92a108579 change terminal size 2023-11-16 15:31:53 +01:00
d54ced97ae change term to vertical in nvim 2023-11-16 15:12:23 +01:00
f82c463df5 change hidpi 2023-11-16 14:28:19 +01:00
d0ca72f089 change hardware for notebook to new frame.work 2023-11-16 14:17:49 +01:00
b5487c1783 remove unbound acme user 2023-11-11 10:39:44 +01:00
43ad01fb1f fix unbound config 2023-11-11 10:38:21 +01:00
45678e4216 add missing lib 2023-11-11 10:35:48 +01:00
1342fe12c7 add missing lib 2023-11-11 10:35:03 +01:00
bd50971827 fix forward-addr type 2023-11-11 10:34:04 +01:00
b1025e5dc0 fix missing semilcon 2023-11-11 10:33:10 +01:00
d53ed53527 add missing semilcon 2023-11-11 10:32:37 +01:00
eddea2ad49 fix typo 2023-11-11 10:32:04 +01:00
a8e4d55e22 add ddns, wireguard server 2023-11-11 10:30:01 +01:00
629c2abe16 add unbound 2023-11-10 20:27:39 +01:00
3e6c4d98e6 fix kea 2023-11-10 19:54:59 +01:00
795b3e2f99 change dhcp server to kea, add static leases 2023-11-10 19:53:27 +01:00
7c7e3b67b0 change to renamed property 2023-11-10 19:30:48 +01:00
a6553a27e2 add insecure package 2023-11-10 19:29:47 +01:00
f16086963b add missing lib 2023-11-10 19:28:24 +01:00
d0ddc3f8be add wrwks secret to fw 2023-11-10 19:27:52 +01:00
3d7c7e41b3 fix typo 2023-11-10 19:12:37 +01:00
ff6e8beab4 add pkgs to fw 2023-11-10 19:11:46 +01:00
3260eaf3a3 add initial fw configs 2023-11-10 18:40:26 +01:00
aaf92c8953 fix missing semilcon 2023-11-06 14:33:26 +01:00
56282c8ba6 add automatic gc to servers 2023-11-06 14:28:40 +01:00
f081efd17e change loki index period 2023-11-06 14:03:11 +01:00
ed8b99d709 change loki index period 2023-11-06 12:11:26 +01:00
0b3c4dfc08 change loki retention 2023-11-06 11:36:04 +01:00
d3178949f1 add git-filter-repo, remove filezilla 2023-11-04 22:42:45 +01:00
6b06f2740b fix yaml lsp 2023-11-04 16:52:15 +01:00
0af4903072 remove keyordering warning from vim 2023-11-04 16:31:56 +01:00
3553f77bd1 change drone version 2023-11-02 00:16:16 +01:00
339a9c20e8 fix missing semilcon 2023-11-01 16:16:37 +01:00
b10fff353c add tandem.paraclub site 2023-11-01 16:09:48 +01:00
999010495e add wkhtmltopdf 2023-11-01 15:37:35 +01:00
1b2c631684 change ssh key 2023-11-01 15:26:32 +01:00
3615be8dbb add paraclub api vhost 2023-11-01 12:31:36 +01:00
702ab238d7 add paraclub site 2023-10-29 15:50:18 +01:00
f92df32f6f remove webp support 2023-10-29 15:46:13 +01:00
161fac357d change paraclub host for new website 2023-10-29 15:10:16 +01:00
b83b2149d1 add electron unsecure 2023-10-28 15:18:42 +02:00
a62b258322 add filezilla 2023-10-28 15:10:13 +02:00
7f5d893898 change nginx conf 2023-10-27 19:00:21 +02:00
b33cbf963d add insecure package for authelia 2023-10-27 18:04:51 +02:00
131542bc1d add paraclub module site 2023-10-27 17:09:20 +02:00
f3a37fcff8 remofe old programs 2023-10-18 21:34:33 +02:00
104db7b032 add publii 2023-10-18 21:22:30 +02:00
7f8d2c8a3b remove epicenter from hosts file 2023-10-18 21:20:57 +02:00
986d6531a9 change hosts file 2023-10-18 19:05:42 +02:00
c3362128bb add correct wine 2023-10-18 01:18:06 +02:00
0291b0be30 add wine 2023-10-17 23:39:27 +02:00
4c2cbc7355 add lutris 2023-10-17 22:25:08 +02:00
283eca1c85 add chiaki to steamdeck 2023-10-15 22:22:14 +02:00
5d730c338e remove package 2023-10-11 21:23:12 +02:00
8c0c542dac add unfree 2023-10-11 20:59:27 +02:00
6ea8ae80e7 add xone 2023-10-11 20:57:15 +02:00
9404b920af remove hosts 2023-10-10 12:02:51 +02:00
1896c629b3 change hosts 2023-10-10 11:56:28 +02:00
b2d7038a6c remove epicenter.works domain 2023-10-10 11:13:32 +02:00
3cea85349f add config for new website 2023-10-10 10:15:21 +02:00
c663c24d8e change steamdeck 2023-10-06 17:00:03 +02:00
429709d559 try steamdeck hw support with latest kernel 2023-10-06 16:40:27 +02:00
5992595fb1 add wine fonts 2023-10-04 12:29:54 +02:00
d05f38e270 add wine 2023-10-04 11:41:23 +02:00
55ae74077e upgrade home assistant 2023-10-02 19:29:41 +02:00
79f4e067f0 change libreoffice 2023-10-02 13:56:38 +02:00
8a2ead3698 add cage 2023-10-01 22:22:18 +02:00
cbbefd6923 add wayfire 2023-10-01 22:03:08 +02:00
64514421a3 remove hardware 2023-10-01 16:25:58 +02:00
3ec95fba7b enable steamdeck kernel 2023-10-01 16:16:27 +02:00
1b1b6e11ac add wow addon 2023-10-01 01:01:06 +02:00
5a81312ef4 fix git dl 2023-10-01 00:06:21 +02:00
bc321cedc1 add wow addon 2023-09-30 20:02:00 +02:00
834b103210 create addon path if not exists 2023-09-30 19:58:19 +02:00
48a8a92232 change wow addon 2023-09-30 18:11:35 +02:00
a6abeeb2c5 add addon 2023-09-30 18:05:39 +02:00
0169176ea7 add adibags 2023-09-30 17:48:51 +02:00
35e371f2a6 steamdeck enable bluetooth 2023-09-30 14:46:14 +02:00
7b72717d23 add wow addon 2023-09-30 14:16:35 +02:00
80d70d8aec fix path 2023-09-30 13:24:30 +02:00
278288a4a4 change wow addon manager 2023-09-30 13:18:13 +02:00
9ee5c1ebc4 fix overlay 2023-09-30 11:59:26 +02:00
37a657bc32 fix semilcon 2023-09-30 11:57:57 +02:00
94c3b37096 add lib 2023-09-30 11:57:23 +02:00
4d44d7b960 fix semilcon 2023-09-30 11:56:42 +02:00
4e3bf001b4 add wow-addon-manager 2023-09-30 11:53:05 +02:00
b6d07d4142 remove steamdeck kernel 2023-09-29 21:20:38 +02:00
b22ebcd59e try steamdeck again 2023-09-29 21:08:42 +02:00
a5774454b3 change ykfde_enroll 2023-09-29 20:46:09 +02:00
1f596f833f remove steamdeck kernel 2023-09-29 20:37:42 +02:00
a548bd08ac remove steamdeck modules 2023-09-29 20:24:54 +02:00
61d659989f change steamdeck 2023-09-29 20:04:14 +02:00
413a7370db try to change kernel modules 2023-09-29 19:39:15 +02:00
0d57967369 kernel modules 2023-09-29 19:20:11 +02:00
8d3e070007 add kernel modules 2023-09-29 19:19:51 +02:00
261a5ded0b add kernel modules 2023-09-29 18:52:10 +02:00
9f243b89a8 load kernel modules 2023-09-29 18:46:02 +02:00
180215ef46 add kernel module 2023-09-29 18:41:17 +02:00
6ce1c882f6 change kernel module 2023-09-29 18:28:23 +02:00
450a4a3879 add hid_generic to initrd 2023-09-29 18:20:27 +02:00
90a97abfdd remove stemdeck hardware 2023-09-29 18:05:20 +02:00
8040c59a51 add devices steamdeck 2023-09-29 16:27:26 +02:00
b73763c6f8 change steamdeck jovian version 2023-09-29 15:40:55 +02:00
eb3e3972f3 change config 2023-09-29 12:30:14 +02:00
4baf791e21 change strongbox 2023-09-29 12:24:25 +02:00
8934f20baf add hash 2023-09-29 12:17:05 +02:00
b01e2661c7 fix version 2023-09-29 12:12:12 +02:00
0f0687cad7 add version 2023-09-29 12:08:50 +02:00
b7769e46a9 add lib 2023-09-29 12:06:13 +02:00
c58fcd0af6 add missing semilcon 2023-09-29 12:03:28 +02:00
7807c9b817 add strongbox 2023-09-29 12:00:47 +02:00
d665c931d3 change hash 2023-09-29 11:44:39 +02:00
4a1ccb1710 change revision 2023-09-29 11:39:23 +02:00
57050089d3 change hash 2023-09-29 11:27:39 +02:00
d3c15a40dd change hash 2023-09-29 11:17:32 +02:00
3525235f35 change to name 2023-09-29 11:12:46 +02:00
426761d852 switch to fetchgit 2023-09-29 11:08:58 +02:00
862b920e21 add vendorhash 2023-09-29 10:57:25 +02:00
ffd19d46d2 change vendorhash 2023-09-29 10:52:44 +02:00
6604bdcb8e missing lib 2023-09-29 10:45:20 +02:00
0bce2bf6fd fix lib, remove old openldap 2023-09-29 10:42:19 +02:00
b00b09f139 add wow-addon-manager 2023-09-29 10:34:12 +02:00
d8245f197c try to fix addon manager 2023-09-29 10:31:14 +02:00
c2832cf812 add lib 2023-09-29 10:25:59 +02:00
68edee4e90 add wow-addon-manager 2023-09-29 10:24:24 +02:00
e6f44e9b21 change ykfde 2023-09-28 20:30:20 +02:00
52f2aba4d7 change ykfde 2023-09-28 20:20:04 +02:00
ed88e082b9 change chmod of ykfde_enroll 2023-09-28 20:10:00 +02:00
3e35cde009 change ykfde 2023-09-28 20:09:35 +02:00
0ffbfb61fc remove sdcard at steamdeck 2023-09-28 20:04:30 +02:00
cee5ed5f88 add makeWrapper 2023-09-28 19:34:52 +02:00
6d47e49918 fix boot devices steamdeck, add ykfde 2023-09-28 19:29:50 +02:00
a82b2fac68 change ssh key 2023-09-28 18:48:05 +02:00
df57a56c16 change sway conf 2023-09-27 12:11:55 +02:00
3609174d67 change fonts 2023-09-27 12:04:36 +02:00
0ca94f96d9 remove not needed stuff 2023-09-27 11:54:47 +02:00
5ed197549d change to new fonts attribute 2023-09-27 11:45:57 +02:00
9e1fd9293c change steamdeck hardware config for yubikey 2023-09-27 10:57:22 +02:00
d588727fbb change import 2023-09-27 10:55:04 +02:00
e1d3ab538a add lib 2023-09-27 10:54:15 +02:00
14efa66936 change config 2023-09-27 10:52:19 +02:00
471204ad86 change config 2023-09-27 10:46:44 +02:00
232621e155 change 2023-09-27 10:45:25 +02:00
5157ff97e2 change sway config 2023-09-27 10:43:00 +02:00
a4eb21471b add desktop session 2023-09-26 21:32:50 +02:00
41fa14358b enable normal steam 2023-09-26 21:02:05 +02:00
c305ef0e83 add unfree package 2023-09-26 18:44:01 +02:00
7f15a8f213 add unfree pacakge 2023-09-26 18:42:12 +02:00
26ba2f4ddf remove teamviewer 2023-09-26 18:40:10 +02:00
0edfa742bd change sway config 2023-09-26 18:33:28 +02:00
cfb4f767df add bento to steamdeck 2023-09-26 17:54:17 +02:00
1722a479c3 change steamdeck 2023-09-26 17:53:11 +02:00
4a3aac6419 add unfree package 2023-09-26 15:01:59 +02:00
b5b2ce0236 add unfree package 2023-09-26 15:01:01 +02:00
8c37ee4eaf add unfree package 2023-09-26 14:59:59 +02:00
813be14942 add unfree 2023-09-26 14:59:09 +02:00
2d5a1a68eb add i3 2023-09-26 14:57:12 +02:00
de7dd1089b add steam user 2023-09-26 14:52:15 +02:00
7d7c8a6a0b remove duplucate 2023-09-26 14:51:17 +02:00
22e1efa377 change hash 2023-09-26 14:50:35 +02:00
45545dff05 add steamdeck 2023-09-26 14:36:08 +02:00
76f56cc263 rm phone 2023-09-24 15:09:16 +02:00
ae9ec45bd4 fix ssh key 2023-09-24 15:04:35 +02:00
f0775355f4 add ssh key 2023-09-24 14:42:02 +02:00
93bd456d62 autostart terminal 2023-09-24 10:31:39 +02:00
38fb866a4f add psi kernel param 2023-09-24 10:22:42 +02:00
8cc3783614 change phone 2023-09-24 02:18:16 +02:00
58c174a1fc add psi kernel param 2023-09-24 01:45:10 +02:00
ab950494c9 add wlroots 2023-09-24 01:23:53 +02:00
5edd121651 phone change sway config, nb add waydroid 2023-09-24 01:06:31 +02:00
efa8fd7b9b fix terminal phone 2023-09-23 23:58:01 +02:00
2eab0bc0e6 change sway conf phone 2023-09-23 19:57:28 +02:00
4880d08c76 try to fix phone 2023-09-23 19:40:37 +02:00
a04658af9b add sway config 2023-09-23 19:19:23 +02:00
ac3fac8369 change phone 2023-09-23 18:54:37 +02:00
b9a6a7df68 change bento 2023-09-23 18:42:42 +02:00
e20599f71e change bento 2023-09-23 18:39:21 +02:00
50c0d396d6 phone autologin, fix bento sha 2023-09-23 18:31:45 +02:00
33af4a02e4 change bento to own fork 2023-09-23 18:17:53 +02:00
29b33d73dd change phone 2023-09-23 18:01:39 +02:00
4aba370004 change phone 2023-09-23 17:59:05 +02:00
c69e0e2c7c change phone config 2023-09-23 17:39:34 +02:00
2ec5d2e743 change to default config 2023-09-23 17:29:34 +02:00
20e95c50de add waydrium 2023-09-23 16:47:38 +02:00
69085b22d0 add sway to phone 2023-09-23 16:47:07 +02:00
d34ba2d59a add phone config 2023-09-23 00:15:32 +02:00
05d9aa0be2 add sane 2023-09-20 10:07:34 +02:00
1a32dd6b4c add ripgrep 2023-09-12 11:08:42 +02:00
36c6cdd901 setup todo-comments 2023-09-12 11:02:05 +02:00
90c09f99ff add whichkey for todo 2023-09-12 10:49:14 +02:00
bb0dfbd1f1 add todo to nvim 2023-09-12 10:46:49 +02:00
179f295245 add 1password 2023-09-11 14:04:31 +02:00
b21192977f remove cryptomodules 2023-09-07 12:19:29 +02:00
d7a21c5c72 change cryptomodules 2023-09-07 12:12:39 +02:00
9dcc69e510 add luks 2023-09-07 11:49:57 +02:00
f8cc06cb6a ensure printers 2023-09-07 11:21:19 +02:00
b4c9ff653a change printer 2023-09-07 11:11:19 +02:00
a28935f261 remove yubikey 2023-09-07 11:05:42 +02:00
ea774e4463 change printer 2023-09-07 10:25:26 +02:00
030af881ff remove yubikey storage 2023-09-07 10:21:06 +02:00
92c3981b4b remove duplicate 2023-09-07 09:54:47 +02:00
f96d446124 printer 2023-09-07 09:54:15 +02:00
3566c4acb8 change for yubikey 2023-09-07 09:52:06 +02:00
bd0a2b3db2 change efi part 2023-09-07 09:34:29 +02:00
8ed337d9a1 change luks 2023-09-07 09:25:41 +02:00
aa38b2b1ee add yubikey to luks 2023-09-07 09:24:17 +02:00
49e571c3d4 remove printer 2023-09-07 09:02:41 +02:00
8bc67465f1 add yubikey 2023-09-07 08:55:56 +02:00
653657122e remove epicenter host entries 2023-09-06 09:40:40 +02:00
f968ab5d1b remove virtualbox 2023-09-05 10:10:14 +02:00
67947bf60c add password reset to authelia 2023-09-03 20:15:58 +02:00
056eeb6657 add totp 2023-09-03 19:58:29 +02:00
6e624127ea add smtp to authelia 2023-09-03 19:36:59 +02:00
61c4f93bba add two_factor to authelia 2023-09-03 19:25:41 +02:00
e071e24275 add webauthn to authelia 2023-09-03 19:00:21 +02:00
a714c0b680 add bitwarden hosts entry 2023-08-30 11:06:43 +02:00
c607abcbf5 remove typo3 sso 2023-08-29 09:41:19 +02:00
3e9de29a97 remove downloader test 2023-08-25 12:50:57 +02:00
817d965c54 fix nur path 2023-08-25 11:05:44 +02:00
feb17342d8 add downloader test 2023-08-25 09:29:40 +02:00
016db1d7ed add downloader hosts entry 2023-08-24 17:57:54 +02:00
fc58ce98cb remove printer with everywhere driver 2023-08-22 11:29:07 +02:00
8403c92792 add lib 2023-08-22 09:58:57 +02:00
653b503676 add printer with ipp 2023-08-22 09:57:40 +02:00
f1d0ea2cda remove old printing 2023-08-22 09:29:30 +02:00
2673727654 open firewall for printer 2023-08-22 08:59:54 +02:00
1b0aab8d8f add printer 2023-08-21 20:47:07 +02:00
13fc6e9cfd change libreoffice to still 2023-08-21 16:22:56 +02:00
f3ec0914de add onlyoffice 2023-08-21 15:06:30 +02:00
fe0aed764a add intel libva 2023-08-21 12:20:16 +02:00
c9dee50372 change libre office 2023-08-21 12:06:37 +02:00
9b9d1b18e5 add nixos luks to boot 2023-08-21 10:44:24 +02:00
0f6341949b remove not available touch key from foot.ini 2023-08-20 22:26:23 +02:00
ff0960ef0a fix sway etc path 2023-08-20 22:23:04 +02:00
3faf185914 change sway config 2023-08-20 22:22:21 +02:00
a118bcbfe2 change etc to readfile because bento is not readable 2023-08-20 22:19:55 +02:00
a93726053b fix typo 2023-08-20 22:15:52 +02:00
4572975219 change etc file 2023-08-20 22:14:04 +02:00
e637a44278 fix etc symlink to bento 2023-08-20 22:09:33 +02:00
472e12e053 add foot config 2023-08-20 22:05:10 +02:00
ada3ae27d9 add foot 2023-08-20 21:57:45 +02:00
311a9144c6 remove old metrics from git 2023-08-20 17:17:43 +02:00
2fc72c5dfc fix service name for fw metrics 2023-08-20 17:09:08 +02:00
d1ea9498c8 add fw metrics to git 2023-08-20 17:08:04 +02:00
445ee05632 add secrets to notebook 2023-08-20 14:46:23 +02:00
7a0d60c17c add pkgs and overlays to nb config 2023-08-20 14:41:04 +02:00
e2353a4f97 fix nb-01 config 2023-08-20 14:38:11 +02:00
affc03de22 fix fleet conf 2023-08-20 14:22:05 +02:00
e238280cfa add nb config 2023-08-20 14:14:14 +02:00
e1447458d7 add nb to fleet file 2023-08-20 14:06:08 +02:00
2e4f4ad5d9 move modules to mail host 2023-08-19 14:53:32 +02:00
5ea365955d move modules to hass 2023-08-19 14:43:39 +02:00
993aef1ece move modules to git 2023-08-19 14:31:22 +02:00
edb55af964 move modules to web host 2023-08-19 14:19:04 +02:00
1890173440 remove ldap auth from grafana 2023-08-19 12:17:21 +02:00
99a920306c change grafana oauth config 2023-08-19 12:04:10 +02:00
93793616c0 change grafana oauth config 2023-08-19 12:03:26 +02:00
22fef6fca8 change grafana oauth config 2023-08-19 11:56:37 +02:00
784f450002 change grafana oauth config 2023-08-19 11:55:48 +02:00
0212469963 fix authelia grafana client url 2023-08-19 11:43:00 +02:00
d79a6491c3 fix typo 2023-08-19 11:26:54 +02:00
1d2da78329 add oauth to grafana 2023-08-19 11:24:46 +02:00
1871feebdb add promtail to other hosts 2023-08-19 11:05:07 +02:00
ec513e106e add metrics to web 2023-08-19 10:55:30 +02:00
c356c4dce9 add victoriametrics to mail and ha host 2023-08-19 10:40:53 +02:00
89096b4d2c fix env for victoriametrics 2023-08-19 10:05:33 +02:00
be4fc2676e change victoriametrics 2023-08-19 09:54:27 +02:00
64455b070a remove envflag 2023-08-19 09:06:20 +02:00
bd7f68b4a3 try victoriametrics without proxy 2023-08-19 09:05:56 +02:00
4921dfb6f7 change victoriametrics 2023-08-19 08:35:52 +02:00
e413146d7c change victoriametrics user 2023-08-19 08:02:45 +02:00
e836852257 try to change secret 2023-08-19 07:51:40 +02:00
11cd9ce28a try to get victoria running 2023-08-19 07:44:39 +02:00
e3dbd18235 test vicoria metrics 2023-08-19 07:42:02 +02:00
931e5b4801 update secret 2023-08-19 07:26:40 +02:00
3a77a1bf54 try to fix sops 2023-08-19 06:34:32 +02:00
dd976ab3bc add sops 2023-08-19 06:33:21 +02:00
272ade9527 fix serviceconfig 2023-08-19 06:23:24 +02:00
7d125d54b2 add victoriametrics 2023-08-19 06:19:53 +02:00
26f49c0ac1 try to fix loki bug 2023-08-19 02:54:27 +02:00
8be5263ecb web change timezone 2023-08-19 02:48:24 +02:00
076a5c6602 change loki lifecycler 2023-08-19 02:38:23 +02:00
42ece6a873 change loki interface name 2023-08-19 02:12:44 +02:00
6d42a0ecac add loki and promtail to web host 2023-08-19 02:10:37 +02:00
9f48ac2f3c change grafana ldap 2023-08-19 01:55:57 +02:00
9296314a1b change grafana ldap filter 2023-08-19 01:47:05 +02:00
490c681aed add ssl to grafana ldap auth 2023-08-19 01:43:54 +02:00
92c383debf change grafana filter 2023-08-19 01:31:23 +02:00
228d0d334b add default database to grafana 2023-08-19 01:27:46 +02:00
6dc3798dc7 add grafana admin password 2023-08-19 01:20:07 +02:00
255896cb9f add grafana and postgresql to web host, fix sops keys 2023-08-19 01:10:27 +02:00
5651351d68 add hetzner nextcloud to authelia 2023-08-18 23:02:12 +02:00
859eee40fa add port to proxmox redirect url 2023-08-18 22:36:18 +02:00
7d2819cafb add authelia hv client 2023-08-18 22:09:53 +02:00
58e7ad2080 add groups to nextcloud authelia 2023-08-18 20:21:13 +02:00
c6e471febf add nextcloud oidc 2023-08-18 20:15:53 +02:00
82021e93b4 change nextcloud pass 2023-08-18 19:47:53 +02:00
f3323924cb remove broken ciphers from nextcloud 2023-08-18 19:40:47 +02:00
69d8cab82a change nextcloud 2023-08-18 19:36:59 +02:00
7e11ad0029 fix nextcloud config 2023-08-18 19:23:52 +02:00
c05ba67bd7 change nextcloud to mariadb 2023-08-18 19:21:06 +02:00
d9977599fc remove news app from nextcloud 2023-08-18 19:14:44 +02:00
9474c4cf2a fix missing import for nextcloud 2023-08-18 19:05:48 +02:00
74dddaaa1d add nextcloud 2023-08-18 19:03:01 +02:00
bf19ab1c33 test typo3 sso 2023-08-18 15:37:17 +02:00
b4dab8dc32 fix typo3 sso auth 2023-08-18 15:03:15 +02:00
e45c1b4ab1 try to fix nginx error 2023-08-18 14:08:11 +02:00
d63100d838 fix nginx 2023-08-18 14:03:27 +02:00
dbed2df22b fix error 2023-08-18 13:59:21 +02:00
0a423be786 try to add authelia to nginx php rule 2023-08-18 13:54:45 +02:00
444e843ce1 test nginx stuff 2023-08-18 13:44:45 +02:00
5b51ca1591 test nginx stuff 2023-08-18 13:37:31 +02:00
fca2eaf581 try typo3 nginx stuff 2023-08-18 13:19:35 +02:00
46d27d5199 typo3 add fastcgi auth user 2023-08-18 12:42:54 +02:00
db48fbdd97 add php parsing for sso 2023-08-18 12:32:04 +02:00
741a69ea3f remove proxypass from typo3 2023-08-18 12:23:50 +02:00
b672d5e47c change authella to typo3/sso 2023-08-18 11:21:25 +02:00
cffc6352e0 add domain alias till authelia 4.38 2023-08-18 08:48:28 +02:00
bb719bc176 remove authelia multi domain 2023-08-18 08:47:55 +02:00
7a056a6c5a change authelia cookies 2023-08-18 08:39:52 +02:00
9dc702932b add domain alias for gbv dev 2023-08-18 08:32:41 +02:00
1ce0f54d5e remove same site none authelia 2023-08-18 08:31:05 +02:00
a96a27a89b fix typo3 extraconfig 2023-08-18 08:26:14 +02:00
2ceda342e7 fix missing semilcon 2023-08-18 08:22:21 +02:00
5dddbbbb04 authelia change cookie policy, deny ips, add authelia to typo3 2023-08-18 08:19:30 +02:00
f0945efff9 change port of zammad proxy 2023-08-17 22:51:17 +02:00
21c984d35c add proxy pass to zammad auth/sso 2023-08-17 22:45:22 +02:00
4a716a8fd2 change zammad sso header 2023-08-17 22:31:05 +02:00
12274240b6 change authelia session 2023-08-17 22:21:43 +02:00
4f14fb971b remove proxy version 2023-08-17 20:51:32 +02:00
9e420cd183 add authelia nginx proxy config 2023-08-17 20:43:34 +02:00
38398a4cc9 edit policy rules 2023-08-17 20:35:18 +02:00
d2d3b29140 change default redirection url 2023-08-17 20:24:11 +02:00
a6bfdc9167 change to zammad sso 2023-08-17 19:19:16 +02:00
fadf1a5a10 add zammad sso header 2023-08-17 19:04:09 +02:00
1da565f82f change consent duration to 1y 2023-08-17 03:53:03 +02:00
89aff6c7e4 change secrets 2023-08-17 03:43:34 +02:00
6b1385f557 add oidc key 2023-08-17 03:37:17 +02:00
106c83e2b0 change gitea secret 2023-08-17 03:21:35 +02:00
26e20340d3 add gitea to authelia 2023-08-17 03:12:43 +02:00
232ce326a5 authelia change login to mail 2023-08-17 02:49:00 +02:00
758b075645 change authelia user 2023-08-17 02:39:33 +02:00
fb9ab56b9b change authelia to sqlite 2023-08-17 02:27:52 +02:00
652f31e2f1 add authelia user 2023-08-17 02:14:31 +02:00
d14ee7fa5f add authelia group 2023-08-17 02:08:18 +02:00
a833f47a84 change authelia notifications path 2023-08-17 02:04:07 +02:00
1055714683 change authelia user 2023-08-17 02:03:09 +02:00
12f0c9bb1e change database for authelia 2023-08-17 01:56:10 +02:00
ed1c28c1fd fix authelia configuration 2023-08-17 01:45:46 +02:00
cbd5d2644d change owner of authelia secrets 2023-08-17 01:40:17 +02:00
e34b5f499b add autoupgrade to web host 2023-08-17 01:37:46 +02:00
190c03ae2e add openssl 1.1 to unsecure for web 2023-08-17 01:25:25 +02:00
0b2a92fcf1 move authelia ldap password file 2023-08-17 01:15:44 +02:00
9f88466440 fix authelia config 2023-08-17 01:10:16 +02:00
cb1baa15fc fix missing semilcon 2023-08-17 01:07:07 +02:00
7f05bc88e7 initial authelia config 2023-08-17 01:04:31 +02:00
819c34ee7d add bento.nix to mail host 2023-08-17 00:14:59 +02:00
908a348803 add mail.cloonar.com host 2023-08-17 00:06:25 +02:00
aff39fca6f change runtime dir size, add vaultwarden ldap back 2023-08-16 23:55:16 +02:00
a7be64ec8e remove vaultwarden ldap 2023-08-16 23:34:34 +02:00
c4d3c030ee remove paraclub config 2023-08-16 23:20:06 +02:00
8a295e54ea try to fix error at build 2023-08-16 23:17:20 +02:00
6685dd21ac remove old gbv dev site 2023-08-16 23:11:55 +02:00
9d0b5079b1 remove diabetes austria dev version 2023-08-16 23:09:20 +02:00
2c175a324b add web-01 host 2023-08-16 22:31:33 +02:00
0e1cd46b45 remove shiarport mqtt 2023-08-03 16:35:08 +02:00
47111140f4 shaiport dependencies 2023-08-03 16:20:37 +02:00
c1321f4564 add popt to snapserver 2023-08-03 16:10:39 +02:00
c92095f68f snapserver 2023-08-03 16:04:10 +02:00
e767299be4 add mosquitto to build input 2023-08-03 16:01:57 +02:00
4ad8f0a4ea change shairport sync 2023-08-03 15:52:45 +02:00
1aa7dfc787 add vim to home-assistant 2023-08-03 15:31:46 +02:00
8ba9af9c7b change snapserver config 2023-08-03 15:30:16 +02:00
7390d109b2 change snapserver params 2023-08-03 15:20:21 +02:00
4f01bddd8b change mqtt user for snapserver 2023-08-03 15:14:00 +02:00
a78e3b0813 change snapserver 2023-08-03 15:03:43 +02:00
371e4e131d add mqtt to shairport-sync 2023-08-03 14:14:00 +02:00
df965d90ac add user to mosquitto 2023-08-03 14:06:04 +02:00
f156120464 add mqtt client to shairport-sync 2023-08-03 13:58:13 +02:00
6ed4cd7415 add coiot port to hass fw 2023-08-02 23:53:46 +02:00
099a00fd5b allow direct access to hass 2023-08-02 12:33:56 +02:00
63da8aa6fb change version of hass 2023-08-02 12:21:04 +02:00
3f7c2cc163 add nginx to new home assistant 2023-08-02 12:12:32 +02:00
39eff80ba9 fix nix 2023-08-02 11:52:21 +02:00
518300e28b try to fix nix error 2023-08-02 11:50:26 +02:00
dcf83b2e97 try ha container 2023-08-02 11:46:36 +02:00
02c2873ba9 change multimedia 2023-08-02 10:20:24 +02:00
1ca10e4422 add roborock automation 2023-07-27 23:50:40 +02:00
0244dcb281 add roborock 2023-07-27 21:01:29 +02:00
7ddd0bae05 pin docker only for git 2023-07-25 21:07:11 +02:00
64f92d84ec fix missing : 2023-07-25 21:05:15 +02:00
c06d6e3b11 add pkgs to import 2023-07-25 21:04:41 +02:00
e5d05c1a2d pin docker 2023-07-25 21:03:47 +02:00
fad7a9223d add nixpath to git.cloonar.com 2023-07-25 20:50:10 +02:00
96840bb17a remove nixpath 2023-07-25 20:37:31 +02:00
6044d2da4c remove playactor from home-assistant 2023-07-23 11:23:22 +02:00
eee540b359 add home-assistant host 2023-07-23 11:15:46 +02:00
1bf9eb4f4e add bento.nix to git 2023-07-23 11:07:56 +02:00
975db4ae26 add home-assistant user 2023-07-23 11:06:03 +02:00
036f2fa76e fix docker problem 2023-07-23 11:04:16 +02:00
33dd1fa571 remove old stuff 2023-07-23 10:56:05 +02:00
8e428771c1 update gite to new options 2023-07-23 10:55:00 +02:00
22620a747e git add vim to host 2023-07-23 10:48:36 +02:00
e797eb40e0 revert test 2023-07-23 10:38:05 +02:00
34289a34a4 test hook 2 2023-07-23 10:37:38 +02:00
1c0f69c213 test hook 2023-07-23 10:36:11 +02:00
2fed1e626e test hook 2023-07-23 10:35:42 +02:00
78c070d7a8 test git hook for sops 2023-07-23 09:06:08 +02:00
b32c7d72b1 add git.cloonar.com, remove old stuff 2023-07-23 09:05:13 +02:00
511 changed files with 29399 additions and 14122 deletions

106
.chatgpt_config.yaml Normal file
View File

@@ -0,0 +1,106 @@
project_name: "cloonar-nixos"
default_prompt_blocks:
- "basic-prompt"
- "secure-coding"
initial_prompt: |
You are helping me build or refine a NixOS configuration (potentially with Nix Flakes). Please keep the following points in mind when generating or explaining code:
1. **Project & Directory Structure**
- For single-host configurations, you may have a simple structure like:
```
/etc/nixos/
├── configuration.nix
├── hardware-configuration.nix
└── other-module.nix
```
- For multi-host setups or more complex deployments, consider **modules** in a dedicated folder:
```
my-nix-config/
├── flake.nix # (if using Flakes)
├── hosts/
│ ├── hostname1/
│ │ └── configuration.nix
│ └── hostname2/
│ └── configuration.nix
├── modules/
│ ├── networking.nix
│ ├── services.nix
│ ├── users.nix
│ └── ...
└── hardware/
└── hardware-configuration-<machine>.nix
```
- Split large configurations into multiple `.nix` files or modules for clarity. Import them in a top-level `configuration.nix` or `flake.nix`.
2. **Nix Flakes (Optional)**
- If using Flakes, include a top-level `flake.nix` defining your outputs:
- `outputs.nixosConfigurations.<hostname> = { ... }`
- Reference your system with something like `nixos-rebuild switch --flake .#<hostname>`.
- Keep pinned inputs (e.g., `nixpkgs` at a particular commit) in your `flake.lock` to ensure reproducibility.
3. **System Configuration & Modules**
- Place typical NixOS settings (e.g., `networking.hostName`, `time.timeZone`, `environment.systemPackages`, etc.) in `configuration.nix` or a modular file structure.
- Use [NixOS modules](https://nixos.org/manual/nixos/stable/index.html#sec-writing-modules) to separate concerns. For example:
- `networking.nix` for network settings,
- `users.nix` for user/group management,
- `services.nix` for enabling/configuring system services.
- If you have custom logic or package overlays, keep them in separate files (e.g., `overlays.nix`).
4. **Home Manager Integration (Optional)**
- For user-level configuration (e.g., dotfiles, user-specific packages), consider integrating [Home Manager](https://nix-community.github.io/home-manager/) either as a standalone or via Flakes.
- Keep Home Manager configs in a separate `home.nix` file, referencing it in your main configuration or flake outputs.
5. **Security & Secrets Management**
- Avoid committing plain-text secrets (passwords, tokens) to version control.
- Consider using [sops-nix](https://github.com/Mic92/sops-nix) or other secret management solutions to encrypt sensitive files.
- Enable recommended security settings, such as:
- `security.sudo.wheelNeedsPassword = true`
- `security.rtkit.enable = true`
- `users.users.<name>.extraGroups` to limit privileges.
- Regularly update your `nixpkgs` channel or flake inputs for the latest security patches.
6. **System Services & Daemons**
- Use built-in NixOS modules for services (e.g., `services.nginx`, `services.postgresql`, etc.) instead of manual configuration whenever possible.
- For each service, ensure you:
- Set `enable = true;` if its needed,
- Provide configuration in the same module file or a dedicated file if its complex.
- Keep service-specific secrets (e.g., database passwords) out of the main config by referencing environment variables or a secret management solution.
7. **Package Management & Overlays**
- Place packages you need system-wide into `environment.systemPackages`.
- For overriding or extending packages from `nixpkgs`, use the [overlays](https://nixos.wiki/wiki/Overlays) mechanism:
```nix
self: super: {
myPackage = super.callPackage ./pkgs/my-package { };
}
```
- Maintain a dedicated `overlays/` folder if you have multiple custom overlays.
8. **Customization & Extensions**
- Use `environment.etc` or NixOS options to create or manage custom config files in `/etc/`.
- For advanced use cases, you can define your own modules to unify logic for related settings or services.
- Document each module with comments about what it configures and why.
9. **Testing & Deployment**
- Use the `nixos-rebuild test` command to evaluate changes without fully switching.
- If using Flakes, run `nixos-rebuild test --flake .#<hostname>`.
- Test critical services after switching (e.g., `systemctl status service-name`).
- Consider building virtual machines via `nixos-rebuild build-vm` or [NixOS tests](https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests) to validate complex changes.
10. **Output Format**
- Present any generated Nix configuration as well-structured `.nix` files, referencing them in a central place (`configuration.nix` or `flake.nix`).
- When explaining your reasoning, describe which modules or options you chose and why (e.g., “I separated `networking.nix` to isolate network settings from system services.”).
- If you modify existing files, specify precisely which lines or sections have changed, and why you made those changes.
Please follow these guidelines to ensure the generated or explained NixOS configuration adheres to best practices for maintainability, modularity, and security.
debug: false
improved_debug: false
preview_changes: false
interactive_file_selection: false
partial_acceptance: false
enable_debug_commands: false
prompt_char_limit: 300000
enable_step_by_step: true

1
.github/copilot-instructions.md vendored Symbolic link
View File

@@ -0,0 +1 @@
../.roo/rules/rules.md

7
.gitignore vendored
View File

@@ -1 +1,8 @@
.null*.nix
.commit
raspberry/.env
raspberry/result
esphome/trash
esphome/.esphome

8
.mcp.json Normal file
View File

@@ -0,0 +1,8 @@
{
"mcpServers": {
"nixos": {
"command": "uvx",
"args": ["mcp-nixos"]
}
}
}

84
.roo/rules/rules.md Normal file
View File

@@ -0,0 +1,84 @@
# RULES.md
## Overview
This repository manages NixOS configurations for multiple systems, structured to promote modularity, security, and maintainability.
### Directory Structure
Each host has its own directory under `hosts/`, containing:
```
hosts/
└── hostname/
├── configuration.nix
├── modules/
└── secrets.yaml
```
* `configuration.nix`: Main configuration file for the host.
* `modules/`: Custom NixOS modules specific to the host.
* `secrets.yaml`: Encrypted secrets file (see [Secrets Management](#secrets-management)).
## Configuration Management
### Modularization
* Break down configurations into reusable modules placed in the `modules/` directory.
* Use the `imports` directive in `configuration.nix` to include necessary modules.
* Avoid monolithic configurations; modularity enhances clarity and reusability.
### Version Control
* Track all configuration files using Git.
* Exclude sensitive files like `secrets.yaml` from version control.
* Use descriptive commit messages to document changes.
## Deployment with Bento
Bento is utilized for deploying configurations across systems.
* Centralize configurations on a management server.
* Ensure each host accesses only its specific configuration files.
* Leverage Bento's features to manage deployments efficiently.([NixOS Discourse][1], [Reddit][2], [cbiit.github.io][3])
## Security Best Practices
### Secrets Management
* Never store plain-text secrets in the Nix store or configuration files.
* Use tools like [sops-nix](https://github.com/Mic92/sops-nix) to encrypt `secrets.yaml`.
* Restrict access to decrypted secrets using appropriate file permissions.([Reddit][4], [dade][5])
### System Hardening
* Disable unnecessary services to minimize attack surfaces.
* Configure firewalls to allow only essential traffic.
* Regularly update systems to apply security patches.
### User Management
* Implement the principle of least privilege for user accounts.
* Use SSH keys for authentication; disable password-based logins.
* Monitor user activities and access logs for suspicious behavior.
## Maintenance Guidelines
* Regularly review and refactor modules for efficiency and clarity.
* Document all modules and configurations for future reference.
* Test configurations in a controlled environment before deploying to production systems.([NixOS & Flakes][6])
* After developing a feature, delete the corresponding development plan.
---
Adhering to these guidelines will help maintain a secure, organized, and efficient NixOS configuration across multiple systems.
[1]: https://discourse.nixos.org/t/introducing-bento-a-nixos-deployment-framework/21446?utm_source=chatgpt.com "Introducing bento, a NixOS deployment framework"
[2]: https://www.reddit.com/r/NixOS/comments/1e95b69/how_do_you_guys_organize_your_nix_config_files_i/?utm_source=chatgpt.com "How do you guys organize your .nix config files? I have a ... - Reddit"
[3]: https://cbiit.github.io/bento-docs/master/installation/bento-quick-start.html?utm_source=chatgpt.com "1. Quick Start Tutorial — Bento release-4.1.0 documentation"
[4]: https://www.reddit.com/r/NixOS/comments/1cnhx6z/best_security_practices_for_nixos_devices_exposed/?utm_source=chatgpt.com "Best Security practices for NixOS devices exposed to the Internet"
[5]: https://0xda.de/blog/2024/07/framework-and-nixos-sops-nix-secrets-management/?utm_source=chatgpt.com "Framework and NixOS - Sops-nix Secrets Management - dade"
[6]: https://nixos-and-flakes.thiscute.world/nixos-with-flakes/modularize-the-configuration?utm_source=chatgpt.com "Modularize Your NixOS Configuration | NixOS & Flakes Book"

View File

@@ -3,81 +3,154 @@
# Also see https://github.com/Mic92/dotfiles/blob/master/nixos/.sops.yaml
# for a more complex example.
keys:
- &dominik age16veg3fmvpfm7a89a9fc8dvvsxmsthlm70nfxqspr6t8vnf9wkcwsvdq38d
- &tuxedo age17c4swm58zt07axl5u6kkxrwtr5haqkvu4ye4t98qdph98qdclgtq2cyzkq
- &bitwarden age14grjcxaq4h55yfnjxvnqhtswxhj9sfdcvyas4lwvpa8py27pjy2sv3g6v7 # nixos age key
- &dominik age1exny8unxynaw03yu8ppahu5z28uermghr8ag34e7kdqnaduq9stsyettzz
- &dominik2 age1v6p8dan2t3w9h94fz4flldl32082j3s9x6zqq7u5j66keth9aphsd6pvch
- &git-server age106n5n3rrrss45eqqzz8pq90la3kqdtnw63uw0sfa2mahk5xpe30sxs5x58
- &web-01-server age1y6lvl5jkwc47p5ae9yz9j9kuwhy7rtttua5xhygrgmr7ehd49svsszyt42
- &home-assistant-server age1ezq2j34qngky22enhnslx6hzh4ekwk8dtmn6c9us0uqxqpn7hgpsspjz58
- &ldap-server-test age1azmxsw5llmp2nnsv3yc2l8paelmq9rfepxd8jvmswgsmax0qyyxqdnsc7t
- &testmodules age1zkzpnfeakyvg3fqtyay32sushjx2hqe28y6hs6ss7plemzqjqa5s6s5yu3
- &web-02 age1gjm4c3swt8u88e36gf2qlg3syxfc0ly94u64c42f2tsf24npw4csa6e4fw
- &web-arm age1ylrpaytkm0k5kcecsxvyv5xd9ts4md0uap48g6wsmj9pwm4lf5esffu0gw
- &ldap-server-arm age1jyeppc8yl2twnv8fwcewutd5gjewnxl59lmhev6ygds9qel8zf8syt7zz4
- &fw age1wq82xjyj80htz33x7agxddjfumr3wkwh3r24tasagepxw7ka893sau68df
- &fw-new age12msc2c6drsaw0yk2hjlaw0q0lyq0emjx5e8rq7qc7ql689k593kqfmhss2
- &netboot age14uarclad0ty5supc8ep09793xrnwkv8a4h9j0fq8d8lc92n2dadqkf64vw
- &gpd-win4 age1ceg548u5ma6rgu3xgvd254y5xefqrdqfqhcjsjp3255q976fgd2qaua53d
- &nb age1exny8unxynaw03yu8ppahu5z28uermghr8ag34e7kdqnaduq9stsyettzz
- &amzebs-01 age1xcgc6u7fmc2trgxtdtf5nhrd7axzweuxlg0ya9jre3sdrg6c6easecue9w
- &nas age1x3elhtccp4u8ha5ry32juj9fkpg0qg7qqx4gduuehgwwnnhcxp8s892hek
creation_rules:
- path_regex: ^[^/]+\.yaml$
key_groups:
- age:
- *tuxedo
- *bitwarden
- *dominik
- path_regex: computers/git.cloonar.com/[^/]+\.yaml$
- *dominik2
- *nb
- path_regex: hosts/nb/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *git-server
- path_regex: computers/web-01.cloonar.com/[^/]+\.yaml$
- *dominik2
- *nb
- path_regex: hosts/gpd-win4/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *web-01-server
- path_regex: computers/home-assistant.cloonar.com/[^/]+\.yaml$
- *dominik2
- *gpd-win4
- *nb
- path_regex: hosts/fw/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *home-assistant-server
- path_regex: computers/ldap.cloonar.com/[^/]+\.yaml$
- *dominik2
- *nb
- *fw
- path_regex: hosts/fw-new/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *dominik2
- *nb
- *fw
- *fw-new
- path_regex: hosts/fw-new/modules/web/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *dominik2
- *web-02
- path_regex: hosts/web-arm/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *dominik2
- *nb
- *web-arm
- path_regex: hosts/amzebs-01/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *dominik2
- *nb
- *amzebs-01
- path_regex: hosts/nas/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *dominik2
- *nb
- *nas
- path_regex: hosts/mail/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *dominik2
- *nb
- *ldap-server-arm
- *ldap-server-test
- path_regex: modules/lego/[^/]+\.yaml$
- path_regex: hosts/fw/modules/web/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *dominik2
- *nb
- *web-02
- path_regex: utils/modules/lego/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *dominik2
- *nb
- *git-server
- *web-01-server
- *home-assistant-server
- *web-02
- *web-arm
- *ldap-server-arm
- *ldap-server-test
- *testmodules
- *netboot
- path_regex: modules/bitwarden/[^/]+\.yaml$
- *fw
- *fw-new
- path_regex: utils/modules/attic-cache/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *web-01-server
- path_regex: modules/drone/[^/]+\.yaml$
key_groups:
- age:
- *dominik
- *git-server
- path_regex: modules/zammad/[^/]+\.yaml$
key_groups:
- age:
- *dominik
- *web-01-server
- path_regex: modules/plausible/[^/]+\.yaml$
key_groups:
- age:
- *dominik
- *web-01-server
- path_regex: modules/openldap/[^/]+\.yaml$
- *dominik2
- *nb
- path_regex: utils/modules/promtail/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *dominik2
- *nb
- *web-arm
- *ldap-server-arm
- *ldap-server-test
- path_regex: modules/home-assistant/[^/]+\.yaml$
- *netboot
- *fw
- *fw-new
- *nas
- *amzebs-01
- path_regex: utils/modules/victoriametrics/[^/]+\.yaml$
key_groups:
- age:
- *bitwarden
- *dominik
- *home-assistant-server
- *dominik2
- *nb
- *web-arm
- *ldap-server-arm
- *netboot
- *fw
- *fw-new
- *nas
- *amzebs-01

31
AGENTS.md Normal file
View File

@@ -0,0 +1,31 @@
# Repository Guidelines
## Project Structure & Module Organization
- `hosts/<host>/configuration.nix` defines each machine; host modules, packages, and site configs live alongside for composability.
- Shared building blocks sit in `utils/` (`modules/`, `overlays/`, `pkgs/`, `bento.nix`), while `fleet.nix` centralizes cross-host user provisioning.
- Provisioning assets (ISO profiles, Raspberry Pi imaging, helper scripts) live under `iso/`, `raspberry*/`, and `scripts/`—refer to them before reinventing steps.
## Build, Test, and Development Commands
- Enter the dev shell via `nix-shell` (uses `shell.nix`) to populate MCP helper configs and standard tooling.
- Dry-run any change with `./scripts/test-configuration <host>`; append `-v` to mirror `nixos-rebuild --show-trace` for deeper diagnostics.
- Deployment relies on the Git runner—once reviewed changes merge to main, the runner rebuilds and switches the relevant host automatically; treat a clean dry-run as the gate before pushing.
## Coding Style & Naming Conventions
- Format Nix files with two-space indentation; run `nixpkgs-fmt` (via `nix run nixpkgs#nixpkgs-fmt .`) before committing complex edits.
- Keep module and derivation names in lower kebab-case (`web-arm`, `home-assistant.nix`) and align attribute names with actual host or service identifiers.
- Use comments sparingly to justify non-obvious decisions (open ports, unusual service options) and prefer explicit imports over wildcard includes.
## Testing Guidelines
- Always run `./scripts/test-configuration <host>` before raising a PR; it ensures evaluation succeeds and secrets are present.
- For service changes, confirm activation with `nixos-rebuild test` (or `switch`) on a staging machine and capture any notable logs.
- Document manual smoke checks (e.g., URLs defined in `hosts/web-arm/sites/`) in the PR so reviewers can repeat them quickly.
## Commit & Pull Request Guidelines
- Follow the Conventional Commits pattern used in `git log` (`fix:`, `chore:`, `update:`) and scope by host when helpful (`fix(mail):`).
- Split refactors, secrets rotations, and package bumps into distinct commits to simplify review and rollback.
- PRs should call out affected hosts, link dry-build output (and confirm the runner result after merge), and tag the owners noted in `hosts/<host>/users/*.nix`; attach screenshots for UI-facing updates.
## Security & Configuration Tips
- Configure `config.sh` before provisioning SFTP users so the values consumed by `fleet.nix` stay in sync with the chroot layout.
- Store API keys referenced in `shell.nix` (such as the Brave Search token) under `~/.config/mcp-servers/` and keep real secrets out of version control.
- Rotate and edit encrypted `hosts/<host>/secrets.yaml` via `nix-shell -p sops --run 'sops hosts/<host>/secrets.yaml'`; commit only the encrypted output.

100
CLAUDE.md Normal file
View File

@@ -0,0 +1,100 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Repository Overview
This is a NixOS infrastructure repository managing multiple hosts (servers and personal machines) using a modular Nix configuration approach with SOPS for secrets management and Bento for deployment.
## Build and Test Commands
```bash
# Enter development shell (sets up MCP configs)
nix-shell
# Test configuration before deployment (required before PRs)
./scripts/test-configuration <hostname>
./scripts/test-configuration -v <hostname> # with --show-trace
# Edit encrypted secrets
nix-shell -p sops --run 'sops hosts/<hostname>/secrets.yaml'
# Update secrets keys after adding new age keys
./scripts/update-secrets-keys
# Format Nix files
nix run nixpkgs#nixpkgs-fmt .
# Compute hash for new packages
nix hash to-sri --type sha256 $(nix-prefetch-url https://example.com/file.tar.gz)
```
## Architecture
### Host Structure
Each host in `hosts/<hostname>/` contains:
- `configuration.nix` - Main entry point importing modules
- `hardware-configuration.nix` - Machine-specific hardware config
- `secrets.yaml` - SOPS-encrypted secrets
- `modules/` - Host-specific service configurations
- `fleet.nix` → symlink to root `fleet.nix` (SFTP user provisioning)
- `utils/` → symlink to root `utils/` (shared modules)
Current hosts: `fw` (firewall/router), `nb` (notebook), `web-arm`, `mail`, `amzebs-01`, `nas`
### Shared Components (`utils/`)
- `modules/` - Reusable NixOS modules (nginx, sops, borgbackup, lego, promtail, etc.)
- `overlays/` - Nixpkgs overlays
- `pkgs/` - Custom package derivations
- `bento.nix` - Deployment helper module
### Secrets Management
- SOPS with age encryption; keys defined in `.sops.yaml`
- Each host has its own age key derived from SSH host key
- Host secrets in `hosts/<hostname>/secrets.yaml`
- Shared module secrets in `utils/modules/<module>/secrets.yaml`
**IMPORTANT: Never modify secrets files directly.** Instead, tell the user which secrets need to be added and where, so they can edit the encrypted files themselves using:
```bash
nix-shell -p sops --run 'sops hosts/<hostname>/secrets.yaml'
```
### Deployment
The Git runner handles deployment automatically when changes merge to main. A successful `./scripts/test-configuration <host>` dry-build is the gate before pushing.
## Custom Packages
When creating a new package in `utils/pkgs/`, always include an `update.sh` script to automate version updates. See `utils/pkgs/claude-code/update.sh` for the pattern:
1. Fetch latest version from upstream (npm, GitHub, etc.)
2. Update version string in `default.nix`
3. Update source hash using `nix-prefetch-url`
4. Update dependency hashes (e.g., `npmDepsHash`) by triggering a build with a fake hash
5. Verify the final build succeeds
Example structure:
```
utils/pkgs/<package-name>/
├── default.nix
├── update.sh # Always include this
└── (other files like patches, lock files)
```
**IMPORTANT: When modifying a custom package** (patches, version updates, etc.), always test by building the package directly, not just running `test-configuration`. The configuration test only checks that the Nix expression evaluates, but doesn't verify the package actually builds:
```bash
# Build a custom package directly to verify it works
nix-build -E 'with import <nixpkgs> { overlays = [ (import ./utils/overlays/packages.nix) ]; config.allowUnfree = true; }; <package-name>'
```
## Workflow
**IMPORTANT: Always run `./scripts/test-configuration <hostname>` after making any changes** to verify the NixOS configuration builds successfully. This is required before committing.
## Conventions
- Nix files: two-space indentation, lower kebab-case naming
- Commits: Conventional Commits format (`fix:`, `feat:`, `chore:`), scope by host when relevant (`fix(mail):`). Do not add "Generated with Claude Code" or "Co-Authored-By: Claude" footers.
- Modules import via explicit paths, not wildcards
- Comments explain non-obvious decisions (open ports, unusual service options)
- **Never update `system.stateVersion`** - it should remain at the original installation version. To upgrade NixOS, update the `channel` file instead.

101
README.md
View File

@@ -2,22 +2,28 @@
- install ubuntu 20.04
- get age key from SSH
```console
$ nix-shell -p ssh-to-age --run 'ssh-keyscan example.com | ssh-to-age'
curl https://raw.githubusercontent.com/elitak/nixos-infect/master/nixos-infect | PROVIDER=hetznercloud NIX_CHANNEL=nixos-25.05 bash 2>&1 | tee /tmp/infect.log
nix-shell -p ssh-to-age --run 'ssh-keyscan install.cloonar.com | ssh-to-age'
```
- fix secrets files
```console
$ sops': nix-shell -p sops --run "sops updatekeys -y secrets.yaml"
nix-shell -p sops --run "sops updatekeys -y secrets.yaml"
```
- run install command
```console
$ ./install.sh example.com
./install.sh example.com
```
# 2. Sops command
```console
nix-shell -p sops --run 'sops hosts/cloonar.com/secrets.yaml'
```
# 2. Web Server specific
- change the permissions for /var/www
```console
$ chown nginx:nginx /var/www
$ chmod 755 /var/www
chown nginx:nginx /var/www
chmod 755 /var/www
```
# 3. Net data
@@ -26,3 +32,88 @@ $ chmod 755 /var/www
- create /var/lib/netdata/cloud.d/token and write the token in it
- run nix-shell -p netdata --run "netdata-claim.sh -id=$(uuidgen)" as root
- your node should be registered in Netdata cloud
# Borg Backup
add ssh key to hetzner
cat ~/.ssh/id_rsa.pub | ssh -p23 u149513-subx@u149513-subx.your-backup.de install-ssh-key
# 4. Add new Host
```console
sftp host@git.cloonar.com:/config/bootstrap.sh ./
```
# 5. Yubikey
```console
ykman fido access change-pin --new-pin 654321
systemd-cryptenroll --fido2-device=auto --fido2-with-client-pin=yes /dev/nvme0n1p2
```
# 6. Wireguard
```console
wg genkey | (umask 077 && tee privatekey) | wg pubkey > publickey
umask 0077; wg genpsk > psk
```
# 7. Hash for new packages
```console
nix hash to-sri --type sha256 $(nix-prefetch-url https://tar.gz)
```
# 8. Fingerprint Reader Setup (e.g., on Framework Laptop with Goodix reader)
This section assumes you have configured fingerprint support in your NixOS configuration, for example, by creating and importing a module like `hosts/nb/modules/fingerprint.nix` with the following content:
```nix
# hosts/nb/modules/fingerprint.nix
{ config, pkgs, ... }:
{
services.fprintd.enable = true;
security.pam.services.login.fprintAuth = true;
security.pam.services.sudo.fprintAuth = true;
# Add other services like swaylock if needed
# security.pam.services.swaylock.fprintAuth = true;
}
```
After rebuilding your NixOS configuration (`sudo nixos-rebuild switch`), you can enroll fingerprints for a user.
## Enrolling Fingerprints
To enroll a fingerprint for the current user:
```console
fprintd-enroll
```
Or for a specific user (e.g., `dominik`):
```console
fprintd-enroll dominik
```
Follow the on-screen prompts to scan your fingerprint multiple times.
## Verifying Enrollment
You can verify enrolled fingerprints:
```console
fprintd-verify
```
## Listing Enrolled Fingerprints
To see which fingers are enrolled for the current user:
```console
fprintd-list $(whoami)
```
Or for a specific user:
```console
fprintd-list dominik
```
## Deleting Fingerprints
To delete all fingerprints for the current user:
```console
fprintd-delete $(whoami)
```
Or for a specific user:
```console
fprintd-delete dominik
```
You can also delete specific fingerprints by their ID if you know it.

2
buchhaltung.md Normal file
View File

@@ -0,0 +1,2 @@
Bei EU Rechnungen das Hakerl machen bei "Nicht im Inland steuerbare Leistung (außerhalb EU, z.B. Schweiz)"
VXEhGveIHdSj7JKq6zof48vLhKaCo0RJea6DhVqopA8=

5
esphome/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
# Gitignore settings for ESPHome
# This is an example and may include too much for your use-case.
# You can modify this file to suit your needs.
/.esphome/
/secrets.yaml

9
esphome/README.md Normal file
View File

@@ -0,0 +1,9 @@
# Installation
OTA Update Shelly Device to tasmota:
https://github.com/arendst/mgos-to-tasmota
On gen 3 devices just download zip file from below and upload it over the web interface to shelly:
https://github.com/tasmota/mgos32-to-tasmota32/releases
In Tasmota make OTA Update to minimal:
http://ota.tasmota.com/tasmota/release/tasmota-minimal.bin.gz
Make ESPHome Configuration in Dashboard:
docker run --rm --network host -e ESPHOME_DASHBOARD_USE_PING=true -v "${PWD}":/config -it ghcr.io/esphome/esphome:latest

View File

@@ -0,0 +1,19 @@
substitutions:
device_name: "install"
friendly_name: "Esphome Install"
esphome:
name: ${device_name}
comment: ${friendly_name}
platform: ESP8266
board: esp01_1m
web_server:
port: 80
ota:
platform: esphome
wifi:
ssid: Cloonar-Smart
password: 0m6sY7Ue3G31

View File

@@ -0,0 +1,80 @@
substitutions:
device_name: "bathroom-bulb-1"
friendly_name: "Bathroom Bulb 1"
esphome:
name: ${device_name}
comment: ${friendly_name}
on_boot:
priority: 300
then:
- light.turn_on:
id: my_light
- delay: 100ms
- light.turn_on:
id: my_light
brightness: 30%
- delay: 100ms
- light.turn_on:
id: my_light
red: 100%
green: 50%
blue: 0%
white: 100%
esp8266:
board: esp01_1m
interval:
- interval: 15s
then:
- if:
condition:
api.connected: # check if api connected
else:
- light.turn_on:
id: my_light
brightness: 100%
# Enable Home Assistant API
api:
batch_delay: 0ms
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
light:
- platform: rgbw
id: my_light
name: ${friendly_name}
red: pwm_r
green: pwm_g
blue: pwm_b
white: pwm_w
output:
- platform: esp8266_pwm
pin: GPIO13
frequency: 1000 Hz
id: pwm_r
- platform: esp8266_pwm
pin: GPIO12
frequency: 1000 Hz
id: pwm_g
- platform: esp8266_pwm
pin: GPIO14
frequency: 1000 Hz
id: pwm_b
- platform: esp8266_pwm
pin: GPIO5
frequency: 1000 Hz
id: pwm_w

View File

@@ -0,0 +1,80 @@
substitutions:
device_name: "bathroom-bulb-2"
friendly_name: "Bathroom Bulb 2"
esphome:
name: ${device_name}
comment: ${friendly_name}
on_boot:
priority: 300
then:
- light.turn_on:
id: my_light
- delay: 100ms
- light.turn_on:
id: my_light
brightness: 30%
- delay: 100ms
- light.turn_on:
id: my_light
red: 100%
green: 50%
blue: 0%
white: 100%
esp8266:
board: esp01_1m
interval:
- interval: 15s
then:
- if:
condition:
api.connected: # check if api connected
else:
- light.turn_on:
id: my_light
brightness: 100%
# Enable Home Assistant API
api:
batch_delay: 0ms
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
light:
- platform: rgbw
id: my_light
name: ${friendly_name}
red: pwm_r
green: pwm_g
blue: pwm_b
white: pwm_w
output:
- platform: esp8266_pwm
pin: GPIO13
frequency: 1000 Hz
id: pwm_r
- platform: esp8266_pwm
pin: GPIO12
frequency: 1000 Hz
id: pwm_g
- platform: esp8266_pwm
pin: GPIO14
frequency: 1000 Hz
id: pwm_b
- platform: esp8266_pwm
pin: GPIO5
frequency: 1000 Hz
id: pwm_w

View File

@@ -0,0 +1,143 @@
substitutions:
devicename: bathroom-switch-1
# Name for the relays
channel_1: Light
channel_2: Air
max_power: "2000.0" # watt
max_temp: "80.0" # °C
esphome:
name: ${devicename}
platform: ESP8266
board: esp01_1m
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable Home Assistant API
api:
i2c:
sda: GPIO12
scl: GPIO14
sensor:
- platform: ade7953_i2c
voltage:
name: ${devicename} voltage
current_a:
name: ${channel_2} current
internal: true
current_b:
name: ${channel_1} current
internal: true
active_power_a:
name: ${channel_2} power
id: power_channel_2
filters:
- multiply: 1
on_value_range:
- above: ${max_power}
then:
- output.turn_off: shelly_25_relay_2
- homeassistant.service:
service: persistent_notification.create
data:
title: Message from ${devicename}
data_template:
message: Switch turned off because power exceeded ${max_power}W
active_power_b:
name: ${channel_1} power
id: power_channel_1
filters:
- multiply: -1
on_value_range:
- above: ${max_power}
then:
- output.turn_off: shelly_25_relay_1
- homeassistant.service:
service: persistent_notification.create
data:
title: Message from ${devicename}
data_template:
message: Switch turned off because power exceeded ${max_power}W
update_interval: 30s
# NTC Temperature
- platform: ntc
sensor: temp_resistance_reading
name: ${devicename} temperature
unit_of_measurement: "°C"
accuracy_decimals: 1
icon: "mdi:thermometer"
calibration:
b_constant: 3350
reference_resistance: 10kOhm
reference_temperature: 298.15K
on_value_range:
- above: ${max_temp}
then:
- output.turn_off: shelly_25_relay_1
- output.turn_off: shelly_25_relay_2
- homeassistant.service:
service: persistent_notification.create
data:
title: Message from ${devicename}
data_template:
message: Switch turned off because temperature exceeded ${max_temp}°C
- platform: resistance
id: temp_resistance_reading
sensor: temp_analog_reading
configuration: DOWNSTREAM
resistor: 32kOhm
- platform: adc
id: temp_analog_reading
pin: A0
status_led:
pin:
number: GPIO0
inverted: yes
output:
- platform: gpio
pin: GPIO4
id: shelly_25_relay_1
- platform: gpio
pin: GPIO15
id: shelly_25_relay_2
light:
- platform: binary
name: "${channel_1}"
output: shelly_25_relay_1
id: lightid
- platform: binary
name: "${channel_2}"
output: shelly_25_relay_2
id: airid
binary_sensor:
- platform: gpio
pin:
number: GPIO13
name: "${channel_1} input"
internal: true
on_state:
then:
- light.toggle: lightid
- platform: gpio
pin:
number: GPIO5
name: "${channel_2} input"
internal: true
on_state:
then:
- light.toggle: airid
# Prevent short circuit with "floating" pin!
- platform: gpio
pin: GPIO16
name: "ade7953 IRQ pin"
internal: true

View File

@@ -0,0 +1,80 @@
substitutions:
device_name: "bedroom-bulb-1"
friendly_name: "Bedroom Bulb 1"
esphome:
name: ${device_name}
comment: ${friendly_name}
on_boot:
priority: 300
then:
- light.turn_on:
id: my_light
- delay: 100ms
- light.turn_on:
id: my_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: my_light
red: 100%
green: 50%
blue: 0%
white: 100%
esp8266:
board: esp01_1m
interval:
- interval: 15s
then:
- if:
condition:
api.connected: # check if api connected
else:
- light.turn_on:
id: my_light
brightness: 100%
# Enable Home Assistant API
api:
batch_delay: 0ms
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: true
domain: .cloonar.smart
light:
- platform: rgbw
id: my_light
name: ${friendly_name}
red: pwm_r
green: pwm_g
blue: pwm_b
white: pwm_w
output:
- platform: esp8266_pwm
pin: GPIO13
frequency: 1000 Hz
id: pwm_r
- platform: esp8266_pwm
pin: GPIO12
frequency: 1000 Hz
id: pwm_g
- platform: esp8266_pwm
pin: GPIO14
frequency: 1000 Hz
id: pwm_b
- platform: esp8266_pwm
pin: GPIO5
frequency: 1000 Hz
id: pwm_w

View File

@@ -0,0 +1,80 @@
substitutions:
device_name: "bedroom-bulb-2"
friendly_name: "Bedroom Bulb 2"
esphome:
name: ${device_name}
comment: ${friendly_name}
on_boot:
priority: 300
then:
- light.turn_on:
id: my_light
- delay: 100ms
- light.turn_on:
id: my_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: my_light
red: 100%
green: 50%
blue: 0%
white: 100%
esp8266:
board: esp01_1m
interval:
- interval: 15s
then:
- if:
condition:
api.connected: # check if api connected
else:
- light.turn_on:
id: my_light
brightness: 100%
# Enable Home Assistant API
api:
batch_delay: 0ms
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
light:
- platform: rgbw
id: my_light
name: ${friendly_name}
red: pwm_r
green: pwm_g
blue: pwm_b
white: pwm_w
output:
- platform: esp8266_pwm
pin: GPIO13
frequency: 1000 Hz
id: pwm_r
- platform: esp8266_pwm
pin: GPIO12
frequency: 1000 Hz
id: pwm_g
- platform: esp8266_pwm
pin: GPIO14
frequency: 1000 Hz
id: pwm_b
- platform: esp8266_pwm
pin: GPIO5
frequency: 1000 Hz
id: pwm_w

View File

@@ -0,0 +1,80 @@
substitutions:
device_name: "bedroom-bulb-3"
friendly_name: "Bedroom Bulb 3"
esphome:
name: ${device_name}
comment: ${friendly_name}
on_boot:
priority: 300
then:
- light.turn_on:
id: my_light
- delay: 100ms
- light.turn_on:
id: my_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: my_light
red: 100%
green: 50%
blue: 0%
white: 100%
esp8266:
board: esp01_1m
interval:
- interval: 15s
then:
- if:
condition:
api.connected: # check if api connected
else:
- light.turn_on:
id: my_light
brightness: 100%
# Enable Home Assistant API
api:
batch_delay: 0ms
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
light:
- platform: rgbw
id: my_light
name: ${friendly_name}
red: pwm_r
green: pwm_g
blue: pwm_b
white: pwm_w
output:
- platform: esp8266_pwm
pin: GPIO13
frequency: 1000 Hz
id: pwm_r
- platform: esp8266_pwm
pin: GPIO12
frequency: 1000 Hz
id: pwm_g
- platform: esp8266_pwm
pin: GPIO14
frequency: 1000 Hz
id: pwm_b
- platform: esp8266_pwm
pin: GPIO5
frequency: 1000 Hz
id: pwm_w

View File

@@ -0,0 +1,80 @@
substitutions:
device_name: "bedroom-bulb-4"
friendly_name: "Bedroom Bulb 4"
esphome:
name: ${device_name}
comment: ${friendly_name}
on_boot:
priority: 300
then:
- light.turn_on:
id: my_light
- delay: 100ms
- light.turn_on:
id: my_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: my_light
red: 100%
green: 50%
blue: 0%
white: 100%
esp8266:
board: esp01_1m
interval:
- interval: 15s
then:
- if:
condition:
api.connected: # check if api connected
else:
- light.turn_on:
id: my_light
brightness: 100%
# Enable Home Assistant API
api:
batch_delay: 0ms
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
light:
- platform: rgbw
id: my_light
name: ${friendly_name}
red: pwm_r
green: pwm_g
blue: pwm_b
white: pwm_w
output:
- platform: esp8266_pwm
pin: GPIO13
frequency: 1000 Hz
id: pwm_r
- platform: esp8266_pwm
pin: GPIO12
frequency: 1000 Hz
id: pwm_g
- platform: esp8266_pwm
pin: GPIO14
frequency: 1000 Hz
id: pwm_b
- platform: esp8266_pwm
pin: GPIO5
frequency: 1000 Hz
id: pwm_w

View File

@@ -0,0 +1,80 @@
substitutions:
device_name: "hallway-bulb-1"
friendly_name: "Hallway Bulb 1"
esphome:
name: ${device_name}
comment: ${friendly_name}
on_boot:
priority: 300
then:
- light.turn_on:
id: my_light
- delay: 100ms
- light.turn_on:
id: my_light
brightness: 30%
- delay: 100ms
- light.turn_on:
id: my_light
red: 100%
green: 50%
blue: 0%
white: 100%
esp8266:
board: esp01_1m
interval:
- interval: 15s
then:
- if:
condition:
api.connected: # check if api connected
else:
- light.turn_on:
id: my_light
brightness: 100%
# Enable Home Assistant API
api:
batch_delay: 0ms
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
light:
- platform: rgbw
id: my_light
name: ${friendly_name}
red: pwm_r
green: pwm_g
blue: pwm_b
white: pwm_w
output:
- platform: esp8266_pwm
pin: GPIO13
frequency: 1000 Hz
id: pwm_r
- platform: esp8266_pwm
pin: GPIO12
frequency: 1000 Hz
id: pwm_g
- platform: esp8266_pwm
pin: GPIO14
frequency: 1000 Hz
id: pwm_b
- platform: esp8266_pwm
pin: GPIO5
frequency: 1000 Hz
id: pwm_w

View File

@@ -0,0 +1,80 @@
substitutions:
device_name: "hallway-bulb-2"
friendly_name: "Hallway Bulb 2"
esphome:
name: ${device_name}
comment: ${friendly_name}
on_boot:
priority: 300
then:
- light.turn_on:
id: my_light
- delay: 100ms
- light.turn_on:
id: my_light
brightness: 30%
- delay: 100ms
- light.turn_on:
id: my_light
red: 100%
green: 50%
blue: 0%
white: 100%
esp8266:
board: esp01_1m
interval:
- interval: 15s
then:
- if:
condition:
api.connected: # check if api connected
else:
- light.turn_on:
id: my_light
brightness: 100%
# Enable Home Assistant API
api:
batch_delay: 0ms
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
light:
- platform: rgbw
id: my_light
name: ${friendly_name}
red: pwm_r
green: pwm_g
blue: pwm_b
white: pwm_w
output:
- platform: esp8266_pwm
pin: GPIO13
frequency: 1000 Hz
id: pwm_r
- platform: esp8266_pwm
pin: GPIO12
frequency: 1000 Hz
id: pwm_g
- platform: esp8266_pwm
pin: GPIO14
frequency: 1000 Hz
id: pwm_b
- platform: esp8266_pwm
pin: GPIO5
frequency: 1000 Hz
id: pwm_w

View File

@@ -0,0 +1,340 @@
substitutions:
# Default name
name: "hallway-light-switch"
# Default friendly name
friendly_name: "Hallway Light Switch"
# Allows ESP device to be automatically linked to an 'Area' in Home Assistant. Typically used for areas such as 'Lounge Room', 'Kitchen' etc
room: "Hallway"
# Description as appears in ESPHome & top of webserver page
device_description: "Hallway Light Switch"
# Project Name
project_name: "Athom Technology.Mini Relay V2"
# Projection version denotes the release version of the yaml file, allowing checking of deployed vs latest version
project_version: "v2.0.4"
# Restore the relay (GPO switch) upon reboot to state:
light_restore_mode: RESTORE_DEFAULT_OFF
# Set the update interval for sensors
sensor_update_interval: 10s
# Current Limit in Amps.
current_limit : "10"
# Define a domain for this device to use. i.e. iot.home.lan (so device will appear as athom-smart-plug-v2.iot.home.lan in DNS/DHCP logs)
dns_domain: ".cloonar.smart"
# Set timezone of the smart plug. Useful if the plug is in a location different to the HA server. Can be entered in unix Country/Area format (i.e. "Australia/Sydney")
timezone: ""
# Set the duration between the sntp service polling ntp.org servers for an update
sntp_update_interval: 6h
# Network time servers for your region, enter from lowest to highest priority. To use local servers update as per zones or countries at: https://www.ntppool.org/zone/@
sntp_server_1: "0.pool.ntp.org"
sntp_server_2: "1.pool.ntp.org"
sntp_server_3: "2.pool.ntp.org"
# Enables faster network connections, with last connected SSID being connected to and no full scan for SSID being undertaken
wifi_fast_connect: "false"
# Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE
log_level: "WARN"
# Hide the ENERGY sensor that shows kWh consumed, but with no time period associated with it. Resets when device restarted and reflashed.
hide_energy_sensor: "true"
# Enable or disable the use of IPv6 networking on the device
ipv6_enable: "false"
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
comment: "${device_description}"
area: "${room}"
name_add_mac_suffix: false
min_version: 2024.5.0
project:
name: "${project_name}"
version: "${project_version}"
platformio_options:
board_build.mcu: esp32c3
board_build.variant: esp32c3
board_build.flash_mode: dio
esp32:
board: esp32-c3-devkitm-1
flash_size: 4MB
variant: ESP32C3
framework:
type: arduino
version: recommended
preferences:
flash_write_interval: 5min
api:
ota:
- platform: esphome
mdns:
disabled: false
web_server:
port: 80
network:
enable_ipv6: ${ipv6_enable}
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: ${dns_domain}
esp32_improv:
authorizer: none
uart:
rx_pin: GPIO20
baud_rate: 4800
data_bits: 8
stop_bits: 1
parity: EVEN
globals:
- id: total_energy
type: float
restore_value: yes
initial_value: '0.0'
binary_sensor:
- platform: status
name: "Status"
entity_category: diagnostic
- platform: gpio
pin:
number: GPIO3
mode: INPUT_PULLUP
inverted: true
name: "Power Button"
disabled_by_default: true
on_multi_click:
- timing:
- ON for at most 1s
- OFF for at least 0.2s
then:
- light.toggle: mini_relay
- timing:
- ON for at least 4s
then:
- button.press: Reset
- platform: gpio
id: the_switch
name: "Power Switch"
pin:
number: GPIO4
mode: INPUT_PULLUP
inverted: true
on_multi_click:
- timing:
- ON for at most 1s
then:
- light.toggle: mini_relay
sensor:
- platform: uptime
name: "Uptime Sensor"
id: uptime_sensor
entity_category: diagnostic
internal: true
- platform: wifi_signal
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
entity_category: "diagnostic"
- platform: copy
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "Signal %"
entity_category: "diagnostic"
device_class: ""
- platform: cse7766
id: athom_cse7766
current:
name: "Current"
filters:
- throttle_average: ${sensor_update_interval}
- lambda: if (x < 0.060) return 0.0; else return x; #For the chip will report less than 3w power when no load is connected
on_value_range:
- above: ${current_limit}
then:
- light.turn_off: mini_relay
voltage:
name: "Voltage"
filters:
- throttle_average: ${sensor_update_interval}
power:
name: "Power"
id: power_sensor
filters:
- throttle_average: ${sensor_update_interval}
- lambda: if (x < 3.0) return 0.0; else return x; #For the chip will report less than 3w power when no load is connected
energy:
name: "Energy"
id: energy
unit_of_measurement: kWh
filters:
- throttle: ${sensor_update_interval}
# Multiplication factor from W to kW is 0.001
- multiply: 0.001
on_value:
then:
- lambda: |-
static float previous_energy_value = 0.0;
float current_energy_value = id(energy).state;
id(total_energy) += current_energy_value - previous_energy_value;
previous_energy_value = current_energy_value;
id(total_energy_sensor).update();
apparent_power:
name: "Apparent Power"
filters:
- throttle_average: ${sensor_update_interval}
reactive_power:
name: "Reactive Power"
filters:
- throttle_average: ${sensor_update_interval}
power_factor:
name: "Power Factor"
filters:
- throttle_average: ${sensor_update_interval}
- platform: template
name: "Total Energy"
id: total_energy_sensor
unit_of_measurement: kWh
device_class: "energy"
state_class: "total_increasing"
icon: "mdi:lightning-bolt"
accuracy_decimals: 3
lambda: |-
return id(total_energy);
update_interval: ${sensor_update_interval}
- platform: total_daily_energy
name: "Total Energy Today"
restore: true
power_id: power_sensor
unit_of_measurement: kWh
accuracy_decimals: 3
filters:
- multiply: 0.001
button:
- platform: restart
name: "Restart"
entity_category: config
- platform: factory_reset
name: "Factory Reset"
id: Reset
entity_category: config
- platform: safe_mode
name: "Safe Mode"
internal: false
entity_category: config
output:
- platform: gpio
id: relay_output
pin: GPIO6
light:
- platform: status_led
id: led
name: "Blue LED"
disabled_by_default: true
pin:
number: GPIO7
inverted: true
- platform: binary
id: mini_relay
output: relay_output
name: "Mini Switch"
restore_mode: ${light_restore_mode}
on_turn_on:
- light.turn_on: led
on_turn_off:
- light.turn_off: led
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
entity_category: diagnostic
ssid:
name: "Connected SSID"
entity_category: diagnostic
mac_address:
name: "Mac Address"
entity_category: diagnostic
# Creates a sensor showing when the device was last restarted
- platform: template
name: 'Last Restart'
id: device_last_restart
icon: mdi:clock
entity_category: diagnostic
# device_class: timestamp
# Creates a sensor of the uptime of the device, in formatted days, hours, minutes and seconds
- platform: template
name: "Uptime"
entity_category: diagnostic
lambda: |-
int seconds = (id(uptime_sensor).state);
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
if ( days > 3650 ) {
return { "Starting up" };
} else if ( days ) {
return { (String(days) +"d " + String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
} else if ( hours ) {
return { (String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
} else if ( minutes ) {
return { (String(minutes) +"m "+ String(seconds) +"s").c_str() };
} else {
return { (String(seconds) +"s").c_str() };
}
icon: mdi:clock-start
time:
- platform: sntp
id: sntp_time
# Define the timezone of the device
timezone: "${timezone}"
# Change sync interval from default 5min to 6 hours (or as set in substitutions)
update_interval: ${sntp_update_interval}
# Set specific sntp servers to use
servers:
- "${sntp_server_1}"
- "${sntp_server_2}"
- "${sntp_server_3}"
# Publish the time the device was last restarted
on_time_sync:
then:
# Update last restart time, but only once.
- if:
condition:
lambda: 'return id(device_last_restart).state == "";'
then:
- text_sensor.template.publish:
id: device_last_restart
state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'

100
esphome/hallway-switch.yaml Normal file
View File

@@ -0,0 +1,100 @@
substitutions:
devicename: hallway-switch
max_power: "2000.0" # watt
max_temp: "80.0" # °C
esphome:
name: ${devicename}
#esp32:
# board: esp32-c3-devkitm-1
# flash_size: 8MB
# framework:
# type: esp-idf
# variant: esp32c3
esp32:
board: esp32-c3-devkitm-1
flash_size: 8MB
framework:
type: esp-idf
version: recommended
sdkconfig_options:
COMPILER_OPTIMIZATION_SIZE: y
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
logger:
api:
ota:
platform: esphome
sensor:
- platform: ntc
sensor: temp_resistance_reading
name: "Temperature"
unit_of_measurement: "°C"
accuracy_decimals: 1
icon: "mdi:thermometer"
calibration:
b_constant: 3350
reference_resistance: 10kOhm
reference_temperature: 298.15K
on_value_range:
- above: ${max_temp}
then:
- output.turn_off: relay_output
- homeassistant.service:
service: persistent_notification.create
data:
title: Message from ${devicename}
data_template:
message: Switch turned off because temperature exceeded ${max_temp}°C
- platform: resistance
id: temp_resistance_reading
sensor: temp_analog_reading
configuration: DOWNSTREAM
resistor: 10kOhm
- platform: adc
id: temp_analog_reading
pin: GPIO3
attenuation: 12db
output:
- platform: gpio
id: "relay_output"
pin: 7
switch:
- platform: output
id: "relay"
name: "Relay"
output: "relay_output"
binary_sensor:
- platform: gpio
name: "Switch"
pin: 10
on_press:
then:
- switch.toggle: "relay"
filters:
- delayed_on_off: 50ms
- platform: gpio
name: "Button"
pin:
number: 1
inverted: yes
mode:
input: true
pullup: true
status_led:
pin:
number: 0
inverted: true

View File

@@ -0,0 +1,214 @@
substitutions:
name: "livingroom-bulb-1"
friendly_name: "Living Room Bulb 1"
room: "Living Room"
device_description: "athom 7w rgbcw light bulb"
project_name: "Athom Technology.Athom RGBCW Bulb"
dns_domain: ".cloonar.smart"
timezone: ""
sntp_update_interval: 6h
sntp_server_1: "0.pool.ntp.org"
sntp_server_2: "1.pool.ntp.org"
sntp_server_3: "2.pool.ntp.org"
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
comment: "${device_description}"
area: "${room}"
name_add_mac_suffix: false
min_version: 2024.6.0
project:
name: "${project_name}"
version: "${project_version}"
on_boot:
then:
- light.turn_on:
id: rgbww_light
- delay: 100ms
- light.turn_on:
id: rgbww_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: rgbww_light
red: 100%
green: 50%
blue: 0%
white: 100%
interval:
- interval: 15s
then:
- if:
condition:
api.connected:
else:
- light.turn_on:
id: rgbww_light
brightness: 100%
esp8266:
board: esp8285
restore_from_flash: true
preferences:
flash_write_interval: 1min
api:
batch_delay: 0ms
ota:
- platform: esphome
wifi:
# Disable fast_connect so we do a full scan (required for hidden SSIDs)
fast_connect: True
domain: "${dns_domain}"
# Your hidden network
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
channel: 1
hidden: true
manual_ip:
static_ip: 10.42.100.11
gateway: 10.42.100.1
subnet: 255.255.255.0
dns1: 8.8.8.8
dns2: 1.1.1.1
# Fallback access point if Wi-Fi fails
ap:
ssid: "${name}_AP"
password: "bulb_fallback_pw"
ap_timeout: 2min # after 2 min of failed join, enable AP
binary_sensor:
- platform: status
name: "Status"
entity_category: diagnostic
sensor:
- platform: uptime
name: "Uptime Sensor"
id: uptime_sensor
entity_category: diagnostic
internal: true
- platform: wifi_signal
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
entity_category: diagnostic
- platform: copy
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "Signal %"
entity_category: diagnostic
output:
- platform: esp8266_pwm
id: red_output
pin: GPIO4
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: green_output
pin: GPIO12
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: blue_output
pin: GPIO14
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: warm_white_output
pin: GPIO13
min_power: 0.000499
max_power: 0.9
- platform: esp8266_pwm
id: white_output
pin: GPIO5
min_power: 0.000499
max_power: 0.9
light:
- platform: rgbww
id: rgbww_light
name: "RGBCW_Bulb"
red: red_output
green: green_output
blue: blue_output
warm_white: warm_white_output
cold_white: white_output
cold_white_color_temperature: 6000 K
warm_white_color_temperature: 3000 K
color_interlock: true
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
entity_category: diagnostic
ssid:
name: "Connected SSID"
entity_category: diagnostic
mac_address:
name: "Mac Address"
entity_category: diagnostic
- platform: template
name: 'Last Restart'
id: device_last_restart
icon: mdi:clock
entity_category: diagnostic
- platform: template
name: "Uptime"
entity_category: diagnostic
lambda: |-
int seconds = (id(uptime_sensor).state);
int days = seconds / (24 * 3600);
seconds %= (24 * 3600);
int hours = seconds / 3600;
seconds %= 3600;
int minutes = seconds / 60;
seconds %= 60;
if (days > 3650) {
return { "Starting up" };
} else if (days) {
return { (String(days) + "d " + String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (hours) {
return { (String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (minutes) {
return { (String(minutes) + "m " + String(seconds) + "s").c_str() };
} else {
return { (String(seconds) + "s").c_str() };
}
icon: mdi:clock-start
time:
- platform: sntp
id: sntp_time
timezone: "${timezone}"
update_interval: ${sntp_update_interval}
servers:
- "${sntp_server_1}"
- "${sntp_server_2}"
- "${sntp_server_3}"
on_time_sync:
then:
- if:
condition:
lambda: 'return id(device_last_restart).state == "";'
then:
- text_sensor.template.publish:
id: device_last_restart
state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'

View File

@@ -0,0 +1,214 @@
substitutions:
name: "livingroom-bulb-2"
friendly_name: "Living Room Bulb 2"
room: "Living Room"
device_description: "athom 7w rgbcw light bulb"
project_name: "Athom Technology.Athom RGBCW Bulb"
dns_domain: ".cloonar.smart"
timezone: ""
sntp_update_interval: 6h
sntp_server_1: "0.pool.ntp.org"
sntp_server_2: "1.pool.ntp.org"
sntp_server_3: "2.pool.ntp.org"
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
comment: "${device_description}"
area: "${room}"
name_add_mac_suffix: false
min_version: 2024.6.0
project:
name: "${project_name}"
version: "${project_version}"
on_boot:
then:
- light.turn_on:
id: rgbww_light
- delay: 100ms
- light.turn_on:
id: rgbww_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: rgbww_light
red: 100%
green: 50%
blue: 0%
white: 100%
interval:
- interval: 15s
then:
- if:
condition:
api.connected:
else:
- light.turn_on:
id: rgbww_light
brightness: 100%
esp8266:
board: esp8285
restore_from_flash: true
preferences:
flash_write_interval: 1min
api:
batch_delay: 0ms
ota:
- platform: esphome
wifi:
# Disable fast_connect so we do a full scan (required for hidden SSIDs)
fast_connect: True
domain: "${dns_domain}"
# Your hidden network
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
channel: 1
hidden: true
manual_ip:
static_ip: 10.42.100.12
gateway: 10.42.100.1
subnet: 255.255.255.0
dns1: 8.8.8.8
dns2: 1.1.1.1
# Fallback access point if Wi-Fi fails
ap:
ssid: "${name}_AP"
password: "bulb_fallback_pw"
ap_timeout: 2min # after 2 min of failed join, enable AP
binary_sensor:
- platform: status
name: "Status"
entity_category: diagnostic
sensor:
- platform: uptime
name: "Uptime Sensor"
id: uptime_sensor
entity_category: diagnostic
internal: true
- platform: wifi_signal
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
entity_category: diagnostic
- platform: copy
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "Signal %"
entity_category: diagnostic
output:
- platform: esp8266_pwm
id: red_output
pin: GPIO4
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: green_output
pin: GPIO12
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: blue_output
pin: GPIO14
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: warm_white_output
pin: GPIO13
min_power: 0.000499
max_power: 0.9
- platform: esp8266_pwm
id: white_output
pin: GPIO5
min_power: 0.000499
max_power: 0.9
light:
- platform: rgbww
id: rgbww_light
name: "RGBCW_Bulb"
red: red_output
green: green_output
blue: blue_output
warm_white: warm_white_output
cold_white: white_output
cold_white_color_temperature: 6000 K
warm_white_color_temperature: 3000 K
color_interlock: true
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
entity_category: diagnostic
ssid:
name: "Connected SSID"
entity_category: diagnostic
mac_address:
name: "Mac Address"
entity_category: diagnostic
- platform: template
name: 'Last Restart'
id: device_last_restart
icon: mdi:clock
entity_category: diagnostic
- platform: template
name: "Uptime"
entity_category: diagnostic
lambda: |-
int seconds = (id(uptime_sensor).state);
int days = seconds / (24 * 3600);
seconds %= (24 * 3600);
int hours = seconds / 3600;
seconds %= 3600;
int minutes = seconds / 60;
seconds %= 60;
if (days > 3650) {
return { "Starting up" };
} else if (days) {
return { (String(days) + "d " + String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (hours) {
return { (String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (minutes) {
return { (String(minutes) + "m " + String(seconds) + "s").c_str() };
} else {
return { (String(seconds) + "s").c_str() };
}
icon: mdi:clock-start
time:
- platform: sntp
id: sntp_time
timezone: "${timezone}"
update_interval: ${sntp_update_interval}
servers:
- "${sntp_server_1}"
- "${sntp_server_2}"
- "${sntp_server_3}"
on_time_sync:
then:
- if:
condition:
lambda: 'return id(device_last_restart).state == "";'
then:
- text_sensor.template.publish:
id: device_last_restart
state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'

View File

@@ -0,0 +1,214 @@
substitutions:
name: "livingroom-bulb-3"
friendly_name: "Living Room Bulb 3"
room: "Living Room"
device_description: "athom 7w rgbcw light bulb"
project_name: "Athom Technology.Athom RGBCW Bulb"
dns_domain: ".cloonar.smart"
timezone: ""
sntp_update_interval: 6h
sntp_server_1: "0.pool.ntp.org"
sntp_server_2: "1.pool.ntp.org"
sntp_server_3: "2.pool.ntp.org"
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
comment: "${device_description}"
area: "${room}"
name_add_mac_suffix: false
min_version: 2024.6.0
project:
name: "${project_name}"
version: "${project_version}"
on_boot:
then:
- light.turn_on:
id: rgbww_light
- delay: 100ms
- light.turn_on:
id: rgbww_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: rgbww_light
red: 100%
green: 50%
blue: 0%
white: 100%
interval:
- interval: 15s
then:
- if:
condition:
api.connected:
else:
- light.turn_on:
id: rgbww_light
brightness: 100%
esp8266:
board: esp8285
restore_from_flash: true
preferences:
flash_write_interval: 1min
api:
batch_delay: 0ms
ota:
- platform: esphome
wifi:
# Disable fast_connect so we do a full scan (required for hidden SSIDs)
fast_connect: True
domain: "${dns_domain}"
# Your hidden network
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
channel: 1
hidden: true
manual_ip:
static_ip: 10.42.100.13
gateway: 10.42.100.1
subnet: 255.255.255.0
dns1: 8.8.8.8
dns2: 1.1.1.1
# Fallback access point if Wi-Fi fails
ap:
ssid: "${name}_AP"
password: "bulb_fallback_pw"
ap_timeout: 2min # after 2 min of failed join, enable AP
binary_sensor:
- platform: status
name: "Status"
entity_category: diagnostic
sensor:
- platform: uptime
name: "Uptime Sensor"
id: uptime_sensor
entity_category: diagnostic
internal: true
- platform: wifi_signal
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
entity_category: diagnostic
- platform: copy
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "Signal %"
entity_category: diagnostic
output:
- platform: esp8266_pwm
id: red_output
pin: GPIO4
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: green_output
pin: GPIO12
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: blue_output
pin: GPIO14
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: warm_white_output
pin: GPIO13
min_power: 0.000499
max_power: 0.9
- platform: esp8266_pwm
id: white_output
pin: GPIO5
min_power: 0.000499
max_power: 0.9
light:
- platform: rgbww
id: rgbww_light
name: "RGBCW_Bulb"
red: red_output
green: green_output
blue: blue_output
warm_white: warm_white_output
cold_white: white_output
cold_white_color_temperature: 6000 K
warm_white_color_temperature: 3000 K
color_interlock: true
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
entity_category: diagnostic
ssid:
name: "Connected SSID"
entity_category: diagnostic
mac_address:
name: "Mac Address"
entity_category: diagnostic
- platform: template
name: 'Last Restart'
id: device_last_restart
icon: mdi:clock
entity_category: diagnostic
- platform: template
name: "Uptime"
entity_category: diagnostic
lambda: |-
int seconds = (id(uptime_sensor).state);
int days = seconds / (24 * 3600);
seconds %= (24 * 3600);
int hours = seconds / 3600;
seconds %= 3600;
int minutes = seconds / 60;
seconds %= 60;
if (days > 3650) {
return { "Starting up" };
} else if (days) {
return { (String(days) + "d " + String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (hours) {
return { (String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (minutes) {
return { (String(minutes) + "m " + String(seconds) + "s").c_str() };
} else {
return { (String(seconds) + "s").c_str() };
}
icon: mdi:clock-start
time:
- platform: sntp
id: sntp_time
timezone: "${timezone}"
update_interval: ${sntp_update_interval}
servers:
- "${sntp_server_1}"
- "${sntp_server_2}"
- "${sntp_server_3}"
on_time_sync:
then:
- if:
condition:
lambda: 'return id(device_last_restart).state == "";'
then:
- text_sensor.template.publish:
id: device_last_restart
state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'

View File

@@ -0,0 +1,214 @@
substitutions:
name: "livingroom-bulb-4"
friendly_name: "Living Room Bulb 4"
room: "Living Room"
device_description: "athom 7w rgbcw light bulb"
project_name: "Athom Technology.Athom RGBCW Bulb"
dns_domain: ".cloonar.smart"
timezone: ""
sntp_update_interval: 6h
sntp_server_1: "0.pool.ntp.org"
sntp_server_2: "1.pool.ntp.org"
sntp_server_3: "2.pool.ntp.org"
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
comment: "${device_description}"
area: "${room}"
name_add_mac_suffix: false
min_version: 2024.6.0
project:
name: "${project_name}"
version: "${project_version}"
on_boot:
then:
- light.turn_on:
id: rgbww_light
- delay: 100ms
- light.turn_on:
id: rgbww_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: rgbww_light
red: 100%
green: 50%
blue: 0%
white: 100%
interval:
- interval: 15s
then:
- if:
condition:
api.connected:
else:
- light.turn_on:
id: rgbww_light
brightness: 100%
esp8266:
board: esp8285
restore_from_flash: true
preferences:
flash_write_interval: 1min
api:
batch_delay: 0ms
ota:
- platform: esphome
wifi:
# Disable fast_connect so we do a full scan (required for hidden SSIDs)
fast_connect: True
domain: "${dns_domain}"
# Your hidden network
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
channel: 1
hidden: true
manual_ip:
static_ip: 10.42.100.14
gateway: 10.42.100.1
subnet: 255.255.255.0
dns1: 8.8.8.8
dns2: 1.1.1.1
# Fallback access point if Wi-Fi fails
ap:
ssid: "${name}_AP"
password: "bulb_fallback_pw"
ap_timeout: 2min # after 2 min of failed join, enable AP
binary_sensor:
- platform: status
name: "Status"
entity_category: diagnostic
sensor:
- platform: uptime
name: "Uptime Sensor"
id: uptime_sensor
entity_category: diagnostic
internal: true
- platform: wifi_signal
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
entity_category: diagnostic
- platform: copy
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "Signal %"
entity_category: diagnostic
output:
- platform: esp8266_pwm
id: red_output
pin: GPIO4
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: green_output
pin: GPIO12
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: blue_output
pin: GPIO14
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: warm_white_output
pin: GPIO13
min_power: 0.000499
max_power: 0.9
- platform: esp8266_pwm
id: white_output
pin: GPIO5
min_power: 0.000499
max_power: 0.9
light:
- platform: rgbww
id: rgbww_light
name: "RGBCW_Bulb"
red: red_output
green: green_output
blue: blue_output
warm_white: warm_white_output
cold_white: white_output
cold_white_color_temperature: 6000 K
warm_white_color_temperature: 3000 K
color_interlock: true
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
entity_category: diagnostic
ssid:
name: "Connected SSID"
entity_category: diagnostic
mac_address:
name: "Mac Address"
entity_category: diagnostic
- platform: template
name: 'Last Restart'
id: device_last_restart
icon: mdi:clock
entity_category: diagnostic
- platform: template
name: "Uptime"
entity_category: diagnostic
lambda: |-
int seconds = (id(uptime_sensor).state);
int days = seconds / (24 * 3600);
seconds %= (24 * 3600);
int hours = seconds / 3600;
seconds %= 3600;
int minutes = seconds / 60;
seconds %= 60;
if (days > 3650) {
return { "Starting up" };
} else if (days) {
return { (String(days) + "d " + String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (hours) {
return { (String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (minutes) {
return { (String(minutes) + "m " + String(seconds) + "s").c_str() };
} else {
return { (String(seconds) + "s").c_str() };
}
icon: mdi:clock-start
time:
- platform: sntp
id: sntp_time
timezone: "${timezone}"
update_interval: ${sntp_update_interval}
servers:
- "${sntp_server_1}"
- "${sntp_server_2}"
- "${sntp_server_3}"
on_time_sync:
then:
- if:
condition:
lambda: 'return id(device_last_restart).state == "";'
then:
- text_sensor.template.publish:
id: device_last_restart
state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'

View File

@@ -0,0 +1,214 @@
substitutions:
name: "livingroom-bulb-5"
friendly_name: "Living Room Bulb 5"
room: "Living Room"
device_description: "athom 7w rgbcw light bulb"
project_name: "Athom Technology.Athom RGBCW Bulb"
dns_domain: ".cloonar.smart"
timezone: ""
sntp_update_interval: 6h
sntp_server_1: "0.pool.ntp.org"
sntp_server_2: "1.pool.ntp.org"
sntp_server_3: "2.pool.ntp.org"
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
comment: "${device_description}"
area: "${room}"
name_add_mac_suffix: false
min_version: 2024.6.0
project:
name: "${project_name}"
version: "${project_version}"
on_boot:
then:
- light.turn_on:
id: rgbww_light
- delay: 100ms
- light.turn_on:
id: rgbww_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: rgbww_light
red: 100%
green: 50%
blue: 0%
white: 100%
interval:
- interval: 15s
then:
- if:
condition:
api.connected:
else:
- light.turn_on:
id: rgbww_light
brightness: 100%
esp8266:
board: esp8285
restore_from_flash: true
preferences:
flash_write_interval: 1min
api:
batch_delay: 0ms
ota:
- platform: esphome
wifi:
# Disable fast_connect so we do a full scan (required for hidden SSIDs)
fast_connect: True
domain: "${dns_domain}"
# Your hidden network
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
channel: 1
hidden: true
manual_ip:
static_ip: 10.42.100.15
gateway: 10.42.100.1
subnet: 255.255.255.0
dns1: 8.8.8.8
dns2: 1.1.1.1
# Fallback access point if Wi-Fi fails
ap:
ssid: "${name}_AP"
password: "bulb_fallback_pw"
ap_timeout: 2min # after 2 min of failed join, enable AP
binary_sensor:
- platform: status
name: "Status"
entity_category: diagnostic
sensor:
- platform: uptime
name: "Uptime Sensor"
id: uptime_sensor
entity_category: diagnostic
internal: true
- platform: wifi_signal
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
entity_category: diagnostic
- platform: copy
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "Signal %"
entity_category: diagnostic
output:
- platform: esp8266_pwm
id: red_output
pin: GPIO4
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: green_output
pin: GPIO12
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: blue_output
pin: GPIO14
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: warm_white_output
pin: GPIO13
min_power: 0.000499
max_power: 0.9
- platform: esp8266_pwm
id: white_output
pin: GPIO5
min_power: 0.000499
max_power: 0.9
light:
- platform: rgbww
id: rgbww_light
name: "RGBCW_Bulb"
red: red_output
green: green_output
blue: blue_output
warm_white: warm_white_output
cold_white: white_output
cold_white_color_temperature: 6000 K
warm_white_color_temperature: 3000 K
color_interlock: true
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
entity_category: diagnostic
ssid:
name: "Connected SSID"
entity_category: diagnostic
mac_address:
name: "Mac Address"
entity_category: diagnostic
- platform: template
name: 'Last Restart'
id: device_last_restart
icon: mdi:clock
entity_category: diagnostic
- platform: template
name: "Uptime"
entity_category: diagnostic
lambda: |-
int seconds = (id(uptime_sensor).state);
int days = seconds / (24 * 3600);
seconds %= (24 * 3600);
int hours = seconds / 3600;
seconds %= 3600;
int minutes = seconds / 60;
seconds %= 60;
if (days > 3650) {
return { "Starting up" };
} else if (days) {
return { (String(days) + "d " + String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (hours) {
return { (String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (minutes) {
return { (String(minutes) + "m " + String(seconds) + "s").c_str() };
} else {
return { (String(seconds) + "s").c_str() };
}
icon: mdi:clock-start
time:
- platform: sntp
id: sntp_time
timezone: "${timezone}"
update_interval: ${sntp_update_interval}
servers:
- "${sntp_server_1}"
- "${sntp_server_2}"
- "${sntp_server_3}"
on_time_sync:
then:
- if:
condition:
lambda: 'return id(device_last_restart).state == "";'
then:
- text_sensor.template.publish:
id: device_last_restart
state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'

View File

@@ -0,0 +1,214 @@
substitutions:
name: "livingroom-bulb-6"
friendly_name: "Living Room Bulb 6"
room: "Living Room"
device_description: "athom 7w rgbcw light bulb"
project_name: "Athom Technology.Athom RGBCW Bulb"
dns_domain: ".cloonar.smart"
timezone: ""
sntp_update_interval: 6h
sntp_server_1: "0.pool.ntp.org"
sntp_server_2: "1.pool.ntp.org"
sntp_server_3: "2.pool.ntp.org"
esphome:
name: "${name}"
friendly_name: "${friendly_name}"
comment: "${device_description}"
area: "${room}"
name_add_mac_suffix: false
min_version: 2024.6.0
project:
name: "${project_name}"
version: "${project_version}"
on_boot:
then:
- light.turn_on:
id: rgbww_light
- delay: 100ms
- light.turn_on:
id: rgbww_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: rgbww_light
red: 100%
green: 50%
blue: 0%
white: 100%
interval:
- interval: 15s
then:
- if:
condition:
api.connected:
else:
- light.turn_on:
id: rgbww_light
brightness: 100%
esp8266:
board: esp8285
restore_from_flash: true
preferences:
flash_write_interval: 1min
api:
batch_delay: 0ms
ota:
- platform: esphome
wifi:
# Disable fast_connect so we do a full scan (required for hidden SSIDs)
fast_connect: True
domain: "${dns_domain}"
# Your hidden network
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
channel: 1
hidden: true
manual_ip:
static_ip: 10.42.100.16
gateway: 10.42.100.1
subnet: 255.255.255.0
dns1: 8.8.8.8
dns2: 1.1.1.1
# Fallback access point if Wi-Fi fails
ap:
ssid: "${name}_AP"
password: "bulb_fallback_pw"
ap_timeout: 2min # after 2 min of failed join, enable AP
binary_sensor:
- platform: status
name: "Status"
entity_category: diagnostic
sensor:
- platform: uptime
name: "Uptime Sensor"
id: uptime_sensor
entity_category: diagnostic
internal: true
- platform: wifi_signal
name: "WiFi Signal dB"
id: wifi_signal_db
update_interval: 60s
entity_category: diagnostic
- platform: copy
source_id: wifi_signal_db
name: "WiFi Signal Percent"
filters:
- lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
unit_of_measurement: "Signal %"
entity_category: diagnostic
output:
- platform: esp8266_pwm
id: red_output
pin: GPIO4
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: green_output
pin: GPIO12
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: blue_output
pin: GPIO14
min_power: 0.000499
max_power: 1
- platform: esp8266_pwm
id: warm_white_output
pin: GPIO13
min_power: 0.000499
max_power: 0.9
- platform: esp8266_pwm
id: white_output
pin: GPIO5
min_power: 0.000499
max_power: 0.9
light:
- platform: rgbww
id: rgbww_light
name: "RGBCW_Bulb"
red: red_output
green: green_output
blue: blue_output
warm_white: warm_white_output
cold_white: white_output
cold_white_color_temperature: 6000 K
warm_white_color_temperature: 3000 K
color_interlock: true
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
entity_category: diagnostic
ssid:
name: "Connected SSID"
entity_category: diagnostic
mac_address:
name: "Mac Address"
entity_category: diagnostic
- platform: template
name: 'Last Restart'
id: device_last_restart
icon: mdi:clock
entity_category: diagnostic
- platform: template
name: "Uptime"
entity_category: diagnostic
lambda: |-
int seconds = (id(uptime_sensor).state);
int days = seconds / (24 * 3600);
seconds %= (24 * 3600);
int hours = seconds / 3600;
seconds %= 3600;
int minutes = seconds / 60;
seconds %= 60;
if (days > 3650) {
return { "Starting up" };
} else if (days) {
return { (String(days) + "d " + String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (hours) {
return { (String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s").c_str() };
} else if (minutes) {
return { (String(minutes) + "m " + String(seconds) + "s").c_str() };
} else {
return { (String(seconds) + "s").c_str() };
}
icon: mdi:clock-start
time:
- platform: sntp
id: sntp_time
timezone: "${timezone}"
update_interval: ${sntp_update_interval}
servers:
- "${sntp_server_1}"
- "${sntp_server_2}"
- "${sntp_server_3}"
on_time_sync:
then:
- if:
condition:
lambda: 'return id(device_last_restart).state == "";'
then:
- text_sensor.template.publish:
id: device_last_restart
state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'

View File

@@ -0,0 +1,33 @@
esphome:
name: presense-bedroom
friendly_name: presense-bedroom
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Presense-Bedroom Fallback"
password: "jMTo5YkCC01q"
captive_portal:
bluetooth_proxy:

View File

@@ -0,0 +1,33 @@
esphome:
name: presense-hallway
friendly_name: presense-hallway
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Presense-Hallway Fallback"
password: "jMTo5YkCC01q"
captive_portal:
bluetooth_proxy:

View File

@@ -0,0 +1,33 @@
esphome:
name: presense-kitchen
friendly_name: presense-kitchen
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Presense-Kitchen Fallback"
password: "jMTo5YkCC01q"
captive_portal:
bluetooth_proxy:

View File

@@ -0,0 +1,55 @@
esphome:
name: presense-office
friendly_name: presense-office
esp32:
board: esp32dev
framework:
type: esp-idf
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Presense-Office Fallback Hotspot"
password: "jMTo5YkCC01q"
captive_portal:
bluetooth_proxy:
external_components:
- source: github://koying/esphome-ble-remote@master
components: [ ble_client_hid ]
ble_client:
- id: ble_client_1
mac_address: "90:f8:2e:f9:d7:32" # Replace with your remote's MAC address
ble_client_hid:
- id: ble_client_hid_1
ble_client_id: ble_client_1
sensor:
- platform: ble_client_hid
type: last_event_value
name: "Last Event Value"
ble_client_hid_id: ble_client_hid_1
text_sensor:
- platform: ble_client_hid
name: "Last Event Usage"
ble_client_hid_id: ble_client_hid_1

68
esphome/toilet-bulb.yaml Normal file
View File

@@ -0,0 +1,68 @@
substitutions:
device_name: "toilet-bulb"
friendly_name: "Toilet Bulb"
esphome:
name: ${device_name}
comment: ${friendly_name}
on_boot:
then:
- light.turn_on:
id: my_light
- delay: 100ms
- light.turn_on:
id: my_light
brightness: 20%
- delay: 100ms
- light.turn_on:
id: my_light
color_temperature: 2700 K
esp8266:
board: esp01_1m
interval:
- interval: 15s
then:
- if:
condition:
api.connected: # check if api connected
else:
- light.turn_on:
id: my_light
brightness: 100%
- delay: 100ms
- light.turn_on:
id: my_light
color_temperature: 6500 K
# Enable Home Assistant API
api:
batch_delay: 0ms
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: True
domain: .cloonar.smart
output:
- platform: esp8266_pwm
id: warm_white
pin: GPIO4
- platform: esp8266_pwm
id: brightness
pin: GPIO5
light:
- platform: cwww
id: my_light
name: ${friendly_name}
warm_white: warm_white
cold_white: brightness
cold_white_color_temperature: 6500 K
warm_white_color_temperature: 2700 K

View File

@@ -10,15 +10,51 @@
isNormalUser = false;
isSystemUser = true;
group = "sftp_users";
openssh.authorizedKeys.keys = [host.key];
openssh.authorizedKeys.keys = [
host.key
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7"
];
shell = null;
};
};
users = [
{
username = "nb-epicenter";
key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7";
username = "web-arm";
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGzJRWe8hsqAVnGSjPrcheloteWMzORoQ5Gj4IfhCROF";
}
{
username = "mail";
key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCfEuRazRv8zKWJSq+T3SssgOrkBFu6y/t6uoMNrD3P9WHowRDejo2rBsWFgPszhfgxLpWHiuSZFMG8z+07k5fVTdmbUwx0vXI1lmQ7AxB/CPwBef2Vpb7b8Rq6geejvP8X6UjQWP0rsCMtoX2SeBDTG8bDlyq1U3vYxVY4hery6a9Wu57OI5VbSIHhqQvExo7euz8V7ORsLyT8gi9x3r8gNaKJmvssB6QXXZ7U2sJaAUjhV/BmrZJD5qR9EwqwiMPJ2+SkZ0Vz6CFG6GLyB/ngXPEfclLKK7AzookJy7WepqojjFTzmOBMH903oR+MIpjDECKxgaFtW4xY0A/tj8ZDCBPtP8AKjediOASkAi7eUMPseQKDE0BNLSidC0hlQUe0aPaMeA8b1U86PblzpgF8ntkUPbxhO0AgHKq9fPN+f58f75fryNbhgPRRkeLet1q3hxguEMg2MIg/EqIw862YPWPtGRk0wJHwQU7jx+9BbjdptAVTJo/Cj9vM7mpZphE= root@mail";
}
{
username = "nb";
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ6g/lXONzSW1JbyXnj+/0QPWtaiNxu9A0GOCbi96603";
}
{
username = "nb-new";
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC1dDoAJUY58I+4SSfDAkO5kInsMcJT/r/mW+MYXLQVR";
}
{
username = "fw";
key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDtxpJAFohRtBaET9e7EE4I6UmeUT/h1ZTD1zeOHFiWB/AT71ooDT4/QukJOA3LqklDjtDQHH+qjGY50Wa8/oGTA/X3aBDPg5GAHN+U+kYO2UTC69VVjh4TTS35ijg+AdgegtMI4c0VIUMZB24tthV9KEbD20w6XnTzy2Q6PjbBrwsOeHYr9pkygJZDU65ZeKmLyR6yLaadHzXX1I7V2SwiakPEebhQaGipm540d+tAbirKCHcmiORkpd++e3dfwi25hC9bCQ7b3bdaFPAmuhhFEid4jpCt79X+l0qqpClgRLziBjYykNJDFKAljFBJA11/3ofPCuaBCDUuJVhAH044gtT3sbvJq1prd8ElZy6L1yc5YbfFgDMwi71Y2hef780NmDs5Opk9xUCKqdl1YfLyUDgdiiaZ8uhUMd2Ai9BAxJAXtcz/V41ngt3YkUVyGTZdTAODIKk44blGIkgs7JO4yam4UB1curbD0faIZnWLyS5pdFQ+FI05YVjoHXJdme8=";
}
{
username = "fw-new";
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILnb9todh2b+c3iCmEz72smRwL37aZf3Xs3voT7+PLTP";
}
{
username = "gpd-win4";
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILjfS2DtS8PQgkf86dU+EVu5t+r/QlCWmY7+RPYprQrO";
}
{
username = "nas";
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICS6b97LPUpr7/kWvOcI40s5e+gfbfz0I2/hAPL6zTmU";
}
{
username = "amzebs-01";
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINMkFZ60SPl8pzEtGrFq1+n6ZkDuNe3xJaccJMjr3y/q";
}
];
in {

1
fömi-tool.md Normal file
View File

@@ -0,0 +1 @@
dialogmail löscht personen die in keiner gruppe sind nach 2 wochen automatisch

57
gpd-win-4.md Normal file
View File

@@ -0,0 +1,57 @@
I want a wall-mounted docking solution for my GPD Win 4, designed in OpenSCAD 2021.1. Here are the requirements and clarifications:
Orientation & Fit
The GPD Win 4 should be inserted upside down (top facing down), with the screen facing the wall.
It slides in from the top and is guided by side rails.
There should be a small clearance so the GPD Win 4 can be easily inserted/removed without excessive friction.
Front Rail (Lip)
Side Rails:
The dock should have two side rails that run from top to bottom, guiding the GPD Win 4.
The front is open for airflow.
However, there should be a small lip (front rail) on each side, running from top to bottom and connected to the side rails. This lip prevents the GPD Win 4 from falling out forward.
Back Plate / Wall Mount
The dock has a solid back plate that mounts to the wall with two countersunk screws.
The default spacing and size of these screws can be parameterized (e.g., an M4 or M3 countersunk hole).
The back plate thickness should be sufficient for strength (e.g., 34 mm).
No special side or back vents are needed.
Cable Brackets
At the bottom, back, inside the dock, there are two brackets, one for a 90° USB-C cable (standard USB-C power) and one for a 90° Oculink flat cable.
The back plate should be open where these two brackets are, so the cables can exit the dock.
Each bracket should have:
An opening on the side facing the wall, to allow the cable to pass behind (i.e., into or through the wall).
A hole for an M3 screw that presses against the cable from the side to lock it in place.
Enough space to seat a 90° connector so it points upwards to plug into the GPD Win 4.
Parametric Design
The design should be fully parameterized in OpenSCAD, including (but not limited to) the following parameters:
device_width, device_thickness, device_length (for the GPD Win 4)
clearance_x, clearance_y, clearance_z (how much extra space around the device)
wall_plate_thickness
rail_thickness
front_rail_lip_width or front_rail_lip_thickness
wall_mount_screw_hole_diameter, wall_mount_screw_spacing (for countersunk screws)
bracket_inner_width_usbC, bracket_inner_height_usbC (for the USB-C connector dimensions)
bracket_inner_width_oculink, bracket_inner_height_oculink (for the Oculink connector dimensions)
m3_side_screw_hole_diameter (the hole that lets an M3 screw clamp the cable from the side)
Any other geometry parameters (openings for cables, bracket thickness, etc.)
Defaults
Please choose default dimensions that accurately reflect:
Approximate GPD Win 4 size (if not exact, then close estimates).
Standard 90° USB-C and 90° Oculink connector sizes.
Typical M3 screws for cable clamps.
Countersunk holes for M3 or M4 wall screws (whichever you prefer).
Version
This must render successfully in OpenSCAD 2021.1.
Summary
The final output should be an OpenSCAD file that, when the parameters are set to their defaults, produces the described wall-mounted docking station for the GPD Win 4 with side rails, minimal front lip, bracket cutouts for cables, and properly sized holes for screws.
If any additional measurements or details are needed, please ask.

View File

@@ -0,0 +1,471 @@
# Email Setup for amzebs-01 (amz.at)
This host is configured to send emails via Laravel with DKIM signing.
## Configuration Overview
- **Postfix**: Localhost-only SMTP server (no external access)
- **Rspamd**: DKIM signing with host-specific key
- **Domain**: amz.at
- **DKIM Selector**: amzebs-01
- **Secret Management**: DKIM private key stored in sops
## Initial Setup (Before First Deployment)
### 1. Generate DKIM Key Pair
You need to generate a DKIM key pair locally first. You'll need `rspamd` package installed.
#### Option A: Using rspamd (if installed locally)
```bash
# Create a temporary directory
mkdir -p /tmp/dkim-gen
# Generate the key pair
rspamadm dkim_keygen -s amzebs-01 -d amz.at -k /tmp/dkim-gen/amz.at.amzebs-01.key
```
This will output:
- **Private key** saved to `/tmp/dkim-gen/amz.at.amzebs-01.key`
- **Public key** printed to stdout (starts with `v=DKIM1; k=rsa; p=...`)
#### Option B: Using OpenSSL (alternative)
```bash
# Create temporary directory
mkdir -p /tmp/dkim-gen
# Generate private key (2048-bit RSA)
openssl genrsa -out /tmp/dkim-gen/amz.at.amzebs-01.key 2048
# Extract public key in the correct format for DNS
openssl rsa -in /tmp/dkim-gen/amz.at.amzebs-01.key -pubout -outform PEM | \
grep -v '^-----' | tr -d '\n' > /tmp/dkim-gen/public.txt
# Display the DNS record value
echo "v=DKIM1; k=rsa; p=$(cat /tmp/dkim-gen/public.txt)"
```
**Save the public key output!** You'll need it for DNS configuration later.
### 2. Add DKIM Private Key to Sops Secrets
Now you need to encrypt and add the private key to your secrets file.
#### Step 1: View the private key
```bash
cat /tmp/dkim-gen/amz.at.amzebs-01.key
```
#### Step 2: Edit the secrets file
```bash
cd /home/dominik/projects/cloonar/cloonar-nixos/hosts/amzebs-01
sops secrets.yaml
```
#### Step 3: Add the key to secrets.yaml
In the sops editor, add a new key called `rspamd-dkim-key` with the **entire private key content** including the BEGIN/END markers:
```yaml
rspamd-dkim-key: |
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
(paste the entire key content here)
...
-----END PRIVATE KEY-----
```
**Important:**
- Make sure to use the pipe `|` character for multiline content
- Keep the proper indentation (2 spaces before each line of the key)
- Include the full BEGIN/END markers
#### Step 4: Save and exit
Save the file in sops (it will be encrypted automatically).
#### Step 5: Clean up temporary files
```bash
rm -rf /tmp/dkim-gen
```
### 3. Verify Secret is Encrypted
Check that the secret is properly encrypted:
```bash
cat hosts/amzebs-01/secrets.yaml
```
You should see encrypted content, not the plain private key.
### 4. Extract Public Key for DNS (if needed later)
If you didn't save the public key earlier, you can extract it after deployment:
```bash
# On the server after deployment
sudo cat /var/lib/rspamd/dkim/amz.at.amzebs-01.key | \
openssl rsa -pubout -outform PEM 2>/dev/null | \
grep -v '^-----' | tr -d '\n'
```
Then format it as:
```
v=DKIM1; k=rsa; p=<output_from_above>
```
## Deployment
### 1. Deploy Configuration
After adding the DKIM private key to sops, deploy the configuration:
```bash
# Build and switch on the remote host
nixos-rebuild switch --flake .#amzebs-01 --target-host amzebs-01 --use-remote-sudo
```
Or if deploying locally on the server:
```bash
sudo nixos-rebuild switch
```
### 2. Verify Deployment
Check that the services are running:
```bash
# Check rspamd-dkim-setup service
systemctl status rspamd-dkim-setup
# Check that rspamd is running
systemctl status rspamd
# Check that postfix is running
systemctl status postfix
# Verify DKIM key was deployed
ls -la /var/lib/rspamd/dkim/amz.at.amzebs-01.key
```
## DNS Configuration
Add the following DNS records to ensure proper email delivery and avoid spam classification.
### Critical: PTR Record (Reverse DNS)
**This is CRITICAL for email deliverability!** Without a proper PTR record, most mail servers will reject or spam your emails.
#### What is a PTR Record?
A PTR (pointer) record is a reverse DNS entry that maps your IP address back to your hostname. Mail servers use this to verify you're a legitimate mail server.
#### Required PTR Record
```
IP Address: 23.88.38.1
Points to: amzebs-01.amz.at
```
#### How to Configure PTR Record
**Step 1: Contact Your Hosting Provider**
PTR records MUST be configured through your hosting provider (e.g., Hetzner, OVH, AWS, etc.). You cannot set PTR records through your domain registrar.
1. Log into your hosting provider's control panel
2. Find the "Reverse DNS" or "PTR Record" section
3. Set the PTR record for IP `23.88.38.1` to point to `amzebs-01.amz.at`
**Common Provider Links:**
- **Hetzner**: Robot panel → IPs → Edit reverse DNS
- **OVH**: Network → IP → ... → Modify reverse
- **AWS EC2**: Select instance → Networking → Request reverse DNS
**Step 2: Verify Forward DNS First**
Before setting the PTR record, ensure your forward DNS is correct:
```bash
# This should return 23.88.38.1
dig +short amzebs-01.amz.at A
host amzebs-01.amz.at
```
**Step 3: Verify PTR Record**
After configuring, verify the PTR record is working:
```bash
# Method 1: Using dig
dig +short -x 23.88.38.1
# Method 2: Using host
host 23.88.38.1
# Method 3: Using nslookup
nslookup 23.88.38.1
```
All commands should return: `amzebs-01.amz.at`
**Step 4: Verify FCrDNS (Forward-Confirmed Reverse DNS)**
This ensures forward and reverse DNS match properly:
```bash
# Forward lookup
dig +short amzebs-01.amz.at
# Should output: 23.88.38.1
# Reverse lookup
dig +short -x 23.88.38.1
# Should output: amzebs-01.amz.at.
```
If both work correctly, FCrDNS passes! ✓
**Why PTR Records Matter:**
- Gmail, Microsoft, Yahoo require valid PTR records
- Missing PTR = automatic spam classification or rejection
- Can add 5-10 points to spam score alone
- Required for professional email delivery
### Domain DNS Records (amz.at)
Add these records through your domain registrar's DNS management:
#### SPF Record
```
Type: TXT
Name: @
Value: v=spf1 mx a:amzebs-01.amz.at ~all
```
#### DKIM Record
```
Type: TXT
Name: amzebs-01._domainkey
Value: [Your public key from step 1 above]
```
The DKIM record will look something like:
```
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
```
#### DMARC Record
```
Type: TXT
Name: _dmarc
Value: v=DMARC1; p=quarantine; rua=mailto:postmaster@amz.at; ruf=mailto:postmaster@amz.at; fo=1
```
**Explanation:**
- `p=quarantine`: Failed messages should be quarantined (you can change to `p=reject` after testing)
- `rua=mailto:...`: Aggregate reports sent to this address
- `ruf=mailto:...`: Forensic reports sent to this address
- `fo=1`: Generate forensic reports for any failure
## Laravel Configuration
Update your Laravel application's `.env` file:
#### Option A: Using sendmail (Recommended)
```env
MAIL_MAILER=sendmail
MAIL_FROM_ADDRESS=noreply@amz.at
MAIL_FROM_NAME="${APP_NAME}"
```
#### Option B: Using SMTP
```env
MAIL_MAILER=smtp
MAIL_HOST=127.0.0.1
MAIL_PORT=25
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=noreply@amz.at
MAIL_FROM_NAME="${APP_NAME}"
```
**Note**: Laravel can use ANY email address with @amz.at domain. All will be DKIM signed automatically.
## Testing Email
### Test from Command Line
```bash
# Send a test email
echo "Test email body" | mail -s "Test Subject" test@example.com -aFrom:test@amz.at
```
### Check Postfix Queue
```bash
# View mail queue
mailq
# View logs
journalctl -u postfix -f
```
### Check Rspamd Logs
```bash
# View rspamd logs
journalctl -u rspamd -f
```
### Test DKIM Signature and Deliverability
Send an email to test your complete email configuration:
#### Email Testing Services
1. **Mail Tester** (https://www.mail-tester.com/)
- Provides a temporary email address
- Shows comprehensive spam score (0-10, higher is better)
- Checks DKIM, SPF, DMARC, PTR, blacklists, content
- **Target: 9/10 or higher**
2. **MXToolbox Email Health** (https://mxtoolbox.com/emailhealth/)
- Comprehensive deliverability check
- Checks DNS records, blacklists, configuration
3. **Google Admin Toolbox** (https://toolbox.googleapps.com/apps/messageheader/)
- Paste email headers to see how Gmail scored your email
- Shows SPF, DKIM, DMARC results
#### What to Check
- ✓ DKIM signature is valid
- ✓ SPF passes
- ✓ DMARC passes
- ✓ PTR record (reverse DNS) matches
- ✓ Not on any blacklists
- ✓ Spam score < 2.0 (lower is better)
#### Common Issues & Fixes
**High Spam Score (> 5.0)**
- Check: PTR record configured correctly? (Critical!)
- Check: HELO name matches hostname?
- Check: All headers present (To:, From:, Subject:)?
- Check: IP not blacklisted?
**Missing "To:" Header**
Your Laravel app must set a recipient. In your code:
```php
Mail::to('recipient@example.com')
->send(new YourMailable());
```
**HELO/EHLO Mismatch**
After applying this configuration, HELO should be `amzebs-01.amz.at`, not `localhost`
**Check Current HELO Name**
```bash
# On the server
echo "HELO test" | nc localhost 25
# Should see: 250 amzebs-01.amz.at
```
## Verification Commands
```bash
# Check if Postfix is running
systemctl status postfix
# Check if Rspamd is running
systemctl status rspamd
# Check if Postfix is listening on localhost only
ss -tlnp | grep master
# View DKIM public key again
systemctl start rspamd-show-dkim
journalctl -u rspamd-show-dkim
# Check if DKIM key exists
ls -la /var/lib/rspamd/dkim/
```
## Security Notes
1. **Localhost-only**: Postfix is configured to listen ONLY on 127.0.0.1
2. **No authentication**: Not needed since only local processes can connect
3. **No firewall changes**: No external ports opened for email
4. **DKIM signing**: All outgoing emails are automatically signed with DKIM
5. **Host-specific key**: Using selector "amzebs-01" allows multiple hosts to send for amz.at
## Troubleshooting
### Email not being sent
1. Check Postfix status: `systemctl status postfix`
2. Check queue: `mailq`
3. Check logs: `journalctl -u postfix -n 100`
### DKIM not signing
1. Check Rspamd status: `systemctl status rspamd`
2. Check if key exists: `ls -la /var/lib/rspamd/dkim/amz.at.amzebs-01.key`
3. Check Rspamd logs: `journalctl -u rspamd -n 100`
### Permission errors
```bash
# Ensure proper ownership
chown -R rspamd:rspamd /var/lib/rspamd/dkim/
chmod 600 /var/lib/rspamd/dkim/*.key
```
### Rotate DKIM key
```bash
# 1. Generate new key pair locally (follow "Initial Setup" steps)
# 2. Update the rspamd-dkim-key in secrets.yaml with new key
# 3. Deploy the configuration
nixos-rebuild switch
# 4. Restart the setup service to copy new key
systemctl restart rspamd-dkim-setup
# 5. Restart rspamd to use new key
systemctl restart rspamd
# 6. Update DNS with new public key
# 7. Wait for DNS propagation before removing old DNS record
```
## Related Files
- Postfix config: `hosts/amzebs-01/modules/postfix.nix`
- Rspamd config: `hosts/amzebs-01/modules/rspamd.nix`
- Main config: `hosts/amzebs-01/configuration.nix`
- Secrets file: `hosts/amzebs-01/secrets.yaml` (encrypted)
## Sops Secret Configuration
The DKIM private key is stored as a sops secret with the following configuration:
```nix
sops.secrets.rspamd-dkim-key = {
owner = "rspamd";
group = "rspamd";
mode = "0400";
};
```
This ensures:
- Only the rspamd user can read the key
- The key is decrypted at boot time by sops-nix
- The key is encrypted in version control
- The key persists across rebuilds
The key is automatically copied from the sops secret path to `/var/lib/rspamd/dkim/amz.at.amzebs-01.key` by the `rspamd-dkim-setup.service` on every boot.

1
hosts/amzebs-01/channel Normal file
View File

@@ -0,0 +1 @@
https://channels.nixos.org/nixos-25.11

View File

@@ -0,0 +1,81 @@
{ config, lib, pkgs, ... }: {
imports = [
./utils/bento.nix
./utils/modules/sops.nix
./utils/modules/nginx.nix
./utils/modules/set-nix-channel.nix
./modules/mysql.nix
./modules/web/stack.nix
./modules/laravel-storage.nix
./modules/laravel-scheduler.nix
./modules/blackbox-exporter.nix
./modules/postfix.nix
./modules/rspamd.nix
./utils/modules/autoupgrade.nix
./utils/modules/promtail
./utils/modules/victoriametrics
./utils/modules/borgbackup.nix
./hardware-configuration.nix
./sites
];
environment.systemPackages = with pkgs; [
vim
screen
php82
];
time.timeZone = "Europe/Vienna";
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
sops.defaultSopsFile = ./secrets.yaml;
nix.gc = {
automatic = true;
options = "--delete-older-than 60d";
};
boot.tmp.cleanOnBoot = true;
zramSwap.enable = true;
networking.hostName = "amzebs-01";
networking.domain = "cloonar.com";
services.openssh.enable = true;
users.users.root.openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFshMhXwS0FQFPlITipshvNKrV8sA52ZFlnaoHd1thKg"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRQuPqH5fdX3KEw7DXzWEdO3AlUn1oSmtJtHB71ICoH Generated By Termius"
];
programs.ssh = {
knownHosts = {
"git.cloonar.com" = {
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDlUj7eEfS/4+z/3IhFhOTXAfpGEpNv6UWuYSL5OAhus";
};
};
};
# backups - adjust repo for this host
borgbackup.repo = "u149513-sub10@u149513-sub10.your-backup.de:borg";
# Use HTTP-01 challenge for Let's Encrypt (not DNS)
security.acme.acceptTerms = true;
security.acme.defaults.email = "admin+acme@cloonar.com";
networking.firewall = {
enable = true;
allowedTCPPorts = [ 22 80 443 3306 ];
# Allow MariaDB access only from specific IP
extraCommands = ''
iptables -A nixos-fw -p tcp --dport 3306 -s 77.119.230.30 -j nixos-fw-accept
'';
};
system.stateVersion = "25.11";
}

View File

@@ -0,0 +1,27 @@
# Hardware configuration for amzebs-01
# This is a template - update with actual hardware configuration after installation
{ modulesPath, ... }:
{
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
boot.loader.grub = {
efiSupport = true;
efiInstallAsRemovable = true;
device = "nodev";
configurationLimit = 2;
};
# Update these with actual device UUIDs and paths after installation
fileSystems."/boot" = {
device = "/dev/sda15";
fsType = "vfat";
};
fileSystems."/" = {
device = "/dev/sda1";
fsType = "ext4";
};
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "xen_blkfront" ];
boot.initrd.kernelModules = [ "nvme" ];
}

View File

@@ -0,0 +1,83 @@
{ config, pkgs, lib, ... }:
with lib;
let
hostname = config.networking.hostName;
cfg = config.services.blackbox-exporter;
nginxVHosts = config.services.nginx.virtualHosts or {};
allDomains = lib.attrNames nginxVHosts;
filteredDomains = builtins.filter (d: !builtins.elem d cfg.blacklistDomains) allDomains;
httpsDomains = lib.map (d: "https://${d}") filteredDomains;
domainsString = builtins.concatStringsSep "\n "
(map (d: "\"${d}\",") httpsDomains);
in {
options.services.blackbox-exporter.blacklistDomains = mkOption {
type = types.listOf types.str;
default = [];
description = "List of domains to exclude from Blackbox Exporter monitoring";
};
config = {
services.blackbox-exporter = {
blacklistDomains = [
# Currently no domains blacklisted - monitoring all nginx virtualHosts
];
};
# Systemd service for Blackbox Exporter
systemd.services.blackbox-exporter = {
description = "Blackbox Exporter";
after = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = ''
${pkgs.prometheus-blackbox-exporter}/bin/blackbox_exporter \
--config.file=/etc/blackbox_exporter/blackbox.yml
'';
};
# Configuration file for Blackbox Exporter
environment.etc."blackbox_exporter/blackbox.yml".text = ''
modules:
http_200_final:
prober: http
http:
method: GET
follow_redirects: true
preferred_ip_protocol: "ip4" # avoid blanket IPv6 failures
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [200]
'';
# Add scrape config for VictoriaMetrics agent
services.victoriametrics.extraScrapeConfigs = [
''
- job_name: "blackbox_http_all_domains"
metrics_path: "/probe"
params:
module: ["http_200_final"]
static_configs:
- targets:
[
${domainsString}
]
relabel_configs:
- source_labels: ["__address__"]
target_label: "__param_target"
regex: '(.*)'
replacement: "$1"
- source_labels: ["__param_target"]
target_label: "instance"
- target_label: "__address__"
replacement: "127.0.0.1:9115"
- source_labels: ["__address__"]
regex: "127\\.0\\.0\\.1:9115"
target_label: "__scheme__"
replacement: "http"
''
];
};
}

View File

@@ -0,0 +1,51 @@
{ config, lib, pkgs, ... }:
# Daily scheduled Laravel artisan jobs
# Runs artisan finish:reports at 01:00 for production and staging APIs
let
php = pkgs.php82;
sites = [
{
domain = "api.ebs.amz.at";
user = "api_ebs_amz_at";
}
{
domain = "api.stage.ebs.amz.at";
user = "api_stage_ebs_amz_at";
}
];
mkArtisanService = site: {
name = "artisan-finish-reports-${site.domain}";
value = {
description = "Laravel artisan finish:reports for ${site.domain}";
after = [ "network.target" "mysql.service" "phpfpm-${site.domain}.service" ];
serviceConfig = {
Type = "oneshot";
User = site.user;
Group = "nginx";
WorkingDirectory = "/var/www/${site.domain}";
ExecStart = "${php}/bin/php artisan finish:reports";
};
};
};
mkArtisanTimer = site: {
name = "artisan-finish-reports-${site.domain}";
value = {
description = "Daily timer for artisan finish:reports on ${site.domain}";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "*-*-* 01:00:00";
Persistent = true;
};
};
};
in
{
systemd.services = builtins.listToAttrs (map mkArtisanService sites);
systemd.timers = builtins.listToAttrs (map mkArtisanTimer sites);
}

View File

@@ -0,0 +1,30 @@
{ ... }:
{
# Create Laravel storage directories for all API instances
# These directories are required for Laravel to function properly
systemd.tmpfiles.rules = [
# api.ebs.cloonar.dev
"d /var/www/api.ebs.cloonar.dev/storage/framework/cache 0775 api_ebs_cloonar_dev nginx -"
"d /var/www/api.ebs.cloonar.dev/storage/framework/testing 0775 api_ebs_cloonar_dev nginx -"
"d /var/www/api.ebs.cloonar.dev/storage/framework/sessions 0775 api_ebs_cloonar_dev nginx -"
"d /var/www/api.ebs.cloonar.dev/storage/framework/views 0775 api_ebs_cloonar_dev nginx -"
"d /var/www/api.ebs.cloonar.dev/storage/logs 0775 api_ebs_cloonar_dev nginx -"
"d /var/www/api.ebs.cloonar.dev/bootstrap/cache 0775 api_ebs_cloonar_dev nginx -"
# api.ebs.amz.at
"d /var/www/api.ebs.amz.at/storage/framework/cache 0775 api_ebs_amz_at nginx -"
"d /var/www/api.ebs.amz.at/storage/framework/testing 0775 api_ebs_amz_at nginx -"
"d /var/www/api.ebs.amz.at/storage/framework/sessions 0775 api_ebs_amz_at nginx -"
"d /var/www/api.ebs.amz.at/storage/framework/views 0775 api_ebs_amz_at nginx -"
"d /var/www/api.ebs.amz.at/storage/logs 0775 api_ebs_amz_at nginx -"
"d /var/www/api.ebs.amz.at/bootstrap/cache 0775 api_ebs_amz_at nginx -"
# api.stage.ebs.amz.at
"d /var/www/api.stage.ebs.amz.at/storage/framework/cache 0775 api_stage_ebs_amz_at nginx -"
"d /var/www/api.stage.ebs.amz.at/storage/framework/testing 0775 api_stage_ebs_amz_at nginx -"
"d /var/www/api.stage.ebs.amz.at/storage/framework/sessions 0775 api_stage_ebs_amz_at nginx -"
"d /var/www/api.stage.ebs.amz.at/storage/framework/views 0775 api_stage_ebs_amz_at nginx -"
"d /var/www/api.stage.ebs.amz.at/storage/logs 0775 api_stage_ebs_amz_at nginx -"
"d /var/www/api.stage.ebs.amz.at/bootstrap/cache 0775 api_stage_ebs_amz_at nginx -"
];
}

View File

@@ -0,0 +1,43 @@
{ pkgs, config, ... }:
{
services.mysql = {
enable = true;
package = pkgs.mariadb;
settings = {
mysqld = {
max_allowed_packet = "64M";
transaction_isolation = "READ-COMMITTED";
binlog_format = "ROW";
# Allow remote connections
bind-address = "0.0.0.0";
};
};
};
# Create read-only user for remote access after MySQL starts
systemd.services.mysql-setup-readonly-user = {
description = "Setup MySQL read-only user";
after = [ "mysql.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
User = "root";
};
script = ''
PASSWORD=$(cat ${config.sops.secrets.mysql-readonly-password.path})
${pkgs.mariadb}/bin/mysql -u root <<EOF
CREATE USER IF NOT EXISTS 'api_ebs_amz_at_ro'@'%' IDENTIFIED BY '$PASSWORD';
GRANT SELECT ON api_ebs_amz_at.* TO 'api_ebs_amz_at_ro'@'%';
FLUSH PRIVILEGES;
EOF
'';
};
services.mysqlBackup.enable = true;
sops.secrets.mysql-readonly-password = {
owner = "mysql";
};
}

View File

@@ -0,0 +1,56 @@
{ pkgs
, lib
, config
, ...
}:
let
headerChecksFile = pkgs.writeText "header_checks" ''
# Warn about missing critical headers (but don't reject from localhost)
# These help identify misconfigured applications
/^$/ WARN Missing headers detected
'';
in
{
services.postfix = {
mapFiles."header_checks" = headerChecksFile;
enable = true;
hostname = "amzebs-01.amz.at";
domain = "amz.at";
config = {
# Explicitly set hostname to prevent "localhost" HELO issues
myhostname = "amzebs-01.amz.at";
# Set proper HELO name for outgoing SMTP connections
smtp_helo_name = "amzebs-01.amz.at";
# Professional SMTP banner (prevents appearing as default/misconfigured)
smtpd_banner = "$myhostname ESMTP";
# Listen only on localhost for security
# Laravel will send via localhost, no external access needed
inet_interfaces = "loopback-only";
# Compatibility
compatibility_level = "2";
# Only accept mail from localhost
mynetworks = [ "127.0.0.0/8" "[::1]/128" ];
# Larger message size limits for attachments
mailbox_size_limit = 202400000; # ~200MB
message_size_limit = 51200000; # ~50MB
# Ensure proper header handling
# Reject mail that's missing critical headers
header_checks = "regexp:/var/lib/postfix/conf/header_checks";
# Rate limiting to prevent spam-like behavior
# Allow reasonable sending rates for applications
smtpd_client_message_rate_limit = 100;
smtpd_client_recipient_rate_limit = 200;
# Milter configuration is handled automatically by rspamd.postfix.enable
};
};
}

View File

@@ -0,0 +1,84 @@
{ pkgs
, config
, ...
}:
let
domain = "amz.at";
selector = "amzebs-01";
localConfig = pkgs.writeText "local.conf" ''
logging {
level = "notice";
}
# DKIM signing configuration with host-specific selector
dkim_signing {
path = "/var/lib/rspamd/dkim/${domain}.${selector}.key";
selector = "${selector}";
allow_username_mismatch = true;
}
# ARC signing (Authenticated Received Chain)
arc {
path = "/var/lib/rspamd/dkim/${domain}.${selector}.key";
selector = "${selector}";
allow_username_mismatch = true;
}
# Add authentication results to headers
milter_headers {
use = ["authentication-results"];
authenticated_headers = ["authentication-results"];
}
'';
in
{
services.rspamd = {
enable = true;
extraConfig = ''
.include(priority=1,duplicate=merge) "${localConfig}"
'';
# Enable Postfix milter integration
postfix.enable = true;
};
# Copy DKIM key from sops secret to rspamd directory
systemd.services.rspamd-dkim-setup = {
description = "Setup DKIM key from sops secret for ${domain}";
wantedBy = [ "multi-user.target" ];
before = [ "rspamd.service" ];
after = [ "sops-nix.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
DKIM_DIR="/var/lib/rspamd/dkim"
DKIM_KEY="$DKIM_DIR/${domain}.${selector}.key"
# Create directory if it doesn't exist
mkdir -p "$DKIM_DIR"
# Copy key from sops secret
if [ -f "${config.sops.secrets.rspamd-dkim-key.path}" ]; then
cp "${config.sops.secrets.rspamd-dkim-key.path}" "$DKIM_KEY"
chown rspamd:rspamd "$DKIM_KEY"
chmod 600 "$DKIM_KEY"
echo "DKIM key deployed successfully from sops secret"
else
echo "ERROR: DKIM key not found in sops secrets!"
echo "Please ensure rspamd-dkim-key is defined in secrets.yaml"
exit 1
fi
'';
};
sops.secrets.rspamd-dkim-key = {
owner = "rspamd";
group = "rspamd";
mode = "0400";
};
}

View File

@@ -43,8 +43,17 @@ let
'';
};
phpOptions = mkOption {
type = types.lines;
default = "";
description = ''
"Options appended to the PHP configuration file {file}`php.ini` used for this PHP-FPM pool."
'';
};
enableMysql = mkEnableOption (lib.mdDoc "MySQL Database");
enableDefaultLocations = mkEnableOption (lib.mdDoc "Create default nginx location directives") // { default = true; };
enablePhp = mkEnableOption (lib.mdDoc "PHP-FPM support") // { default = true; };
authorizedKeys = mkOption {
type = types.listOf types.str;
@@ -130,12 +139,12 @@ in
BindPaths = "BindPaths=/var/www/${domain}:/var/www/${domain}";
};
}
) cfg.instances;
) (lib.filterAttrs (name: opts: opts.enablePhp) cfg.instances);
services.phpfpm.pools = mapAttrs' (instance: instanceOpts:
let
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
user = if instanceOpts.user != null
user = if instanceOpts.user != null
then instanceOps.user
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
in
@@ -154,10 +163,11 @@ in
"php_admin_value[max_input_vars]" = 1500;
"access.log" = "/var/log/$pool.access.log";
};
phpOptions = instanceOpts.phpOptions;
phpPackage = instanceOpts.phpPackage;
phpEnv."PATH" = pkgs.lib.makeBinPath [ instanceOpts.phpPackage ];
}
) cfg.instances;
) (lib.filterAttrs (name: opts: opts.enablePhp) cfg.instances);
};
@@ -207,7 +217,7 @@ in
'';
# Cache Media: images, icons, video, audio, HTC
"~* \\.(?:jpg|jpeg|gif|png|webp|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff2)$".extraConfig = ''
"~* \\.(?:css|js|jpg|jpeg|gif|png|webp|avif|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff2)$".extraConfig = ''
expires 1y;
access_log off;
add_header Cache-Control "public";
@@ -219,19 +229,12 @@ in
add_header Cache-Control "public";
'';
# Cache CSS, Javascript, Images, Icons, Video, Audio, HTC, Fonts
"~* \\.(?:css|js|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff2)$".extraConfig = ''
expires 1y;
access_log off;
add_header Cache-Control "public";
'';
"/".extraConfig = ''
index index.php index.html;
try_files $uri $uri/ /index.php$is_args$args;
'';
})
{
(mkIf instanceOpts.enablePhp {
"~ [^/]\\.php(/|$)".extraConfig = ''
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
@@ -247,7 +250,7 @@ in
fastcgi_pass unix:${config.services.phpfpm.pools."${domain}".socket};
fastcgi_index index.php;
'';
}
})
];
extraConfig = instanceOpts.extraConfig;
@@ -316,4 +319,3 @@ config.users.groups = mapAttrs' (instance: instanceOpts:
mkIf instanceOpts.enableMysql user
) cfg.instances;
}

View File

@@ -0,0 +1,46 @@
borg-passphrase: ENC[AES256_GCM,data:Q2GvEat5EHmshFiya3yNqFTVS+oJv0al+bYMRwysb0yu7F2gCJd000Y3ibA+tUPSL9iSlMSy0cTkesGVEGBt9w==,iv:/kUJXgibF1cyaCPB55/0nKYq9sSva6psxu2P/l7iRN4=,tag:velr9LTfoj7gEWhUmvPtQg==,type:str]
borg-ssh-key: ENC[AES256_GCM,data:0YEvv7QDmGsur0PFMmz5HqDgDCEk0kRaOu1n7GGWAwmmr0K0bVbpKzHw5wMiMnXEBrvj0izo4P4LYGAlAAYn22Bhgi2eN/vdvSO5V5uDV1ep2dV/TN2m3oYgTIgot47YgwBhcNunIUtEsbZuhAsTGL6LFBPJ3OCLKvhXTNTDaajgH/e4CvyxHHl63MBzr0i1ajigl1IKCk2hhZF4Kd1YGBCVZRoNyyNXywihlcFeskNfldW/sd5Qn2nowVf1MEV9n6Il6Zc1FX69WUVy1k+kOT7HJZGq3uDmgwXQgQhqKm1wh5uOlLkGUX6fz/nz+YFzLFMuUVvs34CzbbEFuWmGU+aNQrfCfI1hqwB5s6wVNdpUmigX9AQMQklu85tHFJg1AaRvhA24Cp/GrptggrTThcjwVFoe9NSQouNYn+ImTvlsE4HuDRRFE6YUounGd2lpRd40LsEjwKiLtwBwqG94u4ZOI91+LG6ZqHftRehE9r/CtedLyqtluNyyQyUNKPraUOm9Rrapewsj0ZCZgGQU,iv:xdRUBQlZlwVIog5KgZRmGNxdmhFE9HgnK3Ahfo+zT9k=,tag:McsJKUEGnKXxiv8Tg5zA4A==,type:str]
mysql-readonly-password: ENC[AES256_GCM,data:k2RplkUZPGZlh29KXXdtwe+MCqKzTI/bLdyuEeicdkbGlBk1SGyLF8vW4t8=,iv:a14IrXYVCDqPKGfJSEPP8g19sPvRTx5NT8IVJJeL48s=,tag:GWgU3oa/+u21/L2y3+vOsw==,type:str]
rspamd-dkim-key: ENC[AES256_GCM,data:maOnsx8AQUIjXqHEzHLxtSvAkr9+YCZid9xWaflkffS0gHd/hoHrozHy+rHSjU7Mz7QHYhjUjFY7Hp7wdKQnHpQLJRV96iNPXTXXYtBr7oDL51cq8ozd094FuMeLNSPitV89OHDcM+9h1F4dsdDWPUiw7eoijQeZ8vx1/VCVAp4FVxTFX3qhoMhXlFabiyM85eKMwJG4BdSwqS624f2Z4tvECRp0pBGtd/3r4/EVRDV1qNsiFvH8mi8eyg9xiWDLDrePq4TuWSu1Xc7z0qpDy0o8iAwGhPu9egIyzHEPk07j9U7PpK56C2UCSY0JBm0hkBGbqLXyRklSMytxoKgw4GJykMwNPNXmA9yuLPanxagJB/z8b7X4HTuYhExzQcC6ke/y8xKcxU4qGt8Ayy5v+QoNpdqXIPsZkIuw9uWm6RIgDt2dCaOdI06lesZKjqU/T6EhDfGoGZX7DwQ7uV9xNDM4NW2jsKpUdFKnzPCCe7/jO/ck4P4i8V+6NWDjj4+/BXDNnKJbMcHIHoSvckCGZiginJsbGvSWd0HfbpR7GQAnL3uKB5/HuFAaUkx+dPHmmP2tOBv6vNt+tq+V9i4kQmwAdl8a9KI456tw9vLwXcBDZOO7n4X5H0jc4afoYCnvLxahvbIXm2QNcBYVKxkqBCvoYEMrBjrnujwbQdEfDKQf3g5p8LQwAfCQ3ng+XH/BDF3qMBdsN1u5Di0FQpCDaGKX8pJ1gg+il76fJgSU8ftoaT32hJnLAjal4cgNIxbta2UYQLixUqaWZ8xqvxrSopkWYrlBBUyQh9jMEoTzpxwCsEPQ72qgVcQfJYlMl4WUBwcasfJnySR+qZ22g3fhStpAQ2HuTGhLjTG1QOewYdwDXDhNmcbqZ478Sp1t7qbBx0R7vWFSyYCMlbmLmvzPm6Z3ET7lkfCrMjMNXaQ8cWSF19QaHAfqRwQooLL93yx7U0KHCilEg4bUjsw8MLQNa4A0ohpq6CG4s5O1+di7W4/h71/moggIebFb2eGLJ8BvbkwiVozXI9L77IGd9RswlEjZed18u7fqetS7dyDthhVG2pvya4zZI/cxIq6oJkNr2RIt3NgYChOh0I/17DuSJJ1jAmPB0Evj8QtCCo49ENnyO5cGWn12DZWybwYkg2jQC4aDFA/u5ajTo3wOKdwHj5hgMz/z05Bn2vAdhCGl6uWWNzcNnDiu3/rjqsjOkfkp0hCP7Q==,iv:FORxJ8htcoLIEJihUN7im3dN4jhnigB70InTohtpWwU=,tag:e2DHBd2dn3piCkEdkbHdoA==,type:str]
sops:
age:
- recipient: age14grjcxaq4h55yfnjxvnqhtswxhj9sfdcvyas4lwvpa8py27pjy2sv3g6v7
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhQUpWNUgxVnhuTXd2TkF0
SVVHemFKRWlYczZ0TnBESVNRczhuRUNnUG1BCmJKQ2JZbHhFcXJidHJzci9OaFBm
ZTd0MGhsaVBic3dMb3psUHRCRnR3ODQKLS0tIERrSG1GVTRHdkJpVWpqdTZ4Yytq
OHhlZjV6MjRVbXFsWjlQSU03ZDNwYm8KAswHRSdV0BW/oJyZx63iZRHsF7SZ6PO+
hajQqmEyfcVfEu39zZzxQ2mtWlOr69I++irOhE3NeiFeJ1yIRQDJEQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1exny8unxynaw03yu8ppahu5z28uermghr8ag34e7kdqnaduq9stsyettzz
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUaUNnY0hpdDAzMTNIUS9D
RmdKbmplUk9DRXlLRXEvSnVjT05sQjcvTnpJCkd6bGRINm5yYUZOUTVzWEdjRmtG
Mmx0ci93N2wvTWV5MzlRVnlYdUxoUWsKLS0tIEVHUlNWYStWTG01RzRrVnNXc3BW
VkRkUXROU3plNmwvTUVhYmhCS2syQkEKKgC0EmUu1u2vZ/SZTnam+h846gZSyY4V
JyMzkws8O5TY9juWdDzXJIU67mIgc4qrWWN3uh8k28JBZGc078b5bg==
-----END AGE ENCRYPTED FILE-----
- recipient: age1v6p8dan2t3w9h94fz4flldl32082j3s9x6zqq7u5j66keth9aphsd6pvch
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoK2JUNVdYTzkvM1BBWXRm
citCNlE4Z1NLdEZ2R0tNZTVSMlFSeGxGOURnClJnYURYa0JZaVprQWdBcmVnOWVj
TGVCK1JWMVlueHJUaTZZYmROM0E5aDAKLS0tIEJxYkdadGtZM250d2d6Ujl2UU9C
YUpkVll2S2RpT0I1UVZiZFRKS1prMEEKp/bGImanJ/58vTQG/gUun/Y2QdmOEi3h
hVS0V2QcfuGgi0/YofLOM3+M6k6ViXw07XfXmR+puvLIHKr2y11x1Q==
-----END AGE ENCRYPTED FILE-----
- recipient: age1xcgc6u7fmc2trgxtdtf5nhrd7axzweuxlg0ya9jre3sdrg6c6easecue9w
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDSGdEZnZEaDRpWUJVcnds
VGFSQklvczBZdEdEbXhodW8vME9wMUpVRENjClFZcnVqYkJxdlBiZFhma0tmZjgz
YXlIdlRDTDU4MHg1dzhGVDRJb2FGYVUKLS0tIDBXSWZ2NkxzdEk0ZlFRM00ybFNy
M0doaWl5R2cwU2RxQm5DbWxXeTZ5S2MKwrB3SysmgzCThQOhEVx18dxIfko0+oZY
9BSZOoFbfuwiLbtpL4J8bzxDvxn6sXxB8EBJH1hbpID53AquWDsxSw==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-11-19T11:16:25Z"
mac: ENC[AES256_GCM,data:x4yor9G+QirceSYSX1K9GdfyGellT4JCkE09Tl9/mOX8HMOKFAQGknuwwU6SNGg+ciBFk4TdjQnDmVai4T8JQo9W/DLiZ+GKnWO3s+ZLDX30sEF0aMjKa43R5CCPO/Fl2XH96TaPC+8itTJQ6TpBSg51QLPcpqrMljiBNWvEoTU=,iv:Zi9rglAwgsejUmIpLN/1QlL80BSp3HP32k1xkWt2b+o=,tag:2ADk8d2G4OezkQjcV3CZuA==,type:str]
unencrypted_suffix: _unencrypted
version: 3.11.0

View File

@@ -0,0 +1,37 @@
{ pkgs, lib, config, ... }:
{
services.webstack.instances."api.ebs.amz.at" = {
enableDefaultLocations = false;
enableMysql = true;
authorizedKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBTsA1z6/vOshSqmEUGO6vFbAYCrucgNORMKyoQ5/9/l"
];
extraConfig = ''
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
error_page 404 /index.php;
'';
locations."/favicon.ico".extraConfig = ''
log_not_found off;
access_log off;
'';
locations."/robots.txt".extraConfig = ''
access_log off;
log_not_found off;
'';
locations."/".extraConfig = ''
try_files $uri $uri/ /index.php$is_args$args;
'';
phpPackage = pkgs.php82.withExtensions ({ enabled, all }:
enabled ++ [ all.imagick ]);
};
# Use HTTP-01 challenge for Let's Encrypt
services.nginx.virtualHosts."api.ebs.amz.at".acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
}

View File

@@ -0,0 +1,37 @@
{ pkgs, lib, config, ... }:
{
services.webstack.instances."api.ebs.cloonar.dev" = {
enableDefaultLocations = false;
enableMysql = true;
authorizedKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIqpF703JmLTBpBjTSvC0bnYu+lSYdmaGPHxMnHEbMmp"
];
extraConfig = ''
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
error_page 404 /index.php;
'';
locations."/favicon.ico".extraConfig = ''
log_not_found off;
access_log off;
'';
locations."/robots.txt".extraConfig = ''
access_log off;
log_not_found off;
'';
locations."/".extraConfig = ''
try_files $uri $uri/ /index.php$is_args$args;
'';
phpPackage = pkgs.php82.withExtensions ({ enabled, all }:
enabled ++ [ all.imagick ]);
};
# Use HTTP-01 challenge for Let's Encrypt
services.nginx.virtualHosts."api.ebs.cloonar.dev".acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
}

View File

@@ -0,0 +1,37 @@
{ pkgs, lib, config, ... }:
{
services.webstack.instances."api.stage.ebs.amz.at" = {
enableDefaultLocations = false;
enableMysql = true;
authorizedKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIqpF703JmLTBpBjTSvC0bnYu+lSYdmaGPHxMnHEbMmp"
];
extraConfig = ''
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
error_page 404 /index.php;
'';
locations."/favicon.ico".extraConfig = ''
log_not_found off;
access_log off;
'';
locations."/robots.txt".extraConfig = ''
access_log off;
log_not_found off;
'';
locations."/".extraConfig = ''
try_files $uri $uri/ /index.php$is_args$args;
'';
phpPackage = pkgs.php82.withExtensions ({ enabled, all }:
enabled ++ [ all.imagick ]);
};
# Use HTTP-01 challenge for Let's Encrypt
services.nginx.virtualHosts."api.stage.ebs.amz.at".acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
}

View File

@@ -0,0 +1,14 @@
{ ... }: {
imports = [
# Enabled vhosts (cloonar.dev)
./api.ebs.cloonar.dev.nix
./ebs.cloonar.dev.nix
./ebs-mobile.cloonar.dev.nix
# Disabled vhosts (amz.at) - uncomment to enable
./api.ebs.amz.at.nix
./api.stage.ebs.amz.at.nix
./ebs.amz.at.nix
./stage.ebs.amz.at.nix
];
}

View File

@@ -0,0 +1,49 @@
{ pkgs, lib, config, ... }:
let
domain = "ebs-mobile.cloonar.dev";
dataDir = "/var/www/${domain}";
in {
services.nginx.virtualHosts."${domain}" = {
forceSSL = true;
enableACME = true;
# Use HTTP-01 challenge for Let's Encrypt
acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
root = "${dataDir}";
locations."/favicon.ico".extraConfig = ''
log_not_found off;
access_log off;
'';
# React client-side routing support
locations."/".extraConfig = ''
index index.html;
try_files $uri $uri/ /index.html$is_args$args;
'';
# Cache static assets
locations."~* \\.(js|jpg|gif|png|webp|css|woff2|svg|ico)$".extraConfig = ''
expires 365d;
add_header Pragma "public";
add_header Cache-Control "public";
'';
# Deny PHP execution
locations."~ [^/]\\.php(/|$)".extraConfig = ''
deny all;
'';
};
users.users."${domain}" = {
isNormalUser = true;
createHome = true;
home = dataDir;
homeMode = "770";
group = "nginx";
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIErjoADQK5SJ5si/iezzwQn5xH1RkgnTIlbeE4BRU1FN"
];
};
users.groups.${domain} = {};
}

View File

@@ -0,0 +1,49 @@
{ pkgs, lib, config, ... }:
let
domain = "ebs.amz.at";
dataDir = "/var/www/${domain}";
in {
services.nginx.virtualHosts."${domain}" = {
forceSSL = true;
enableACME = true;
# Use HTTP-01 challenge for Let's Encrypt
acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
root = "${dataDir}";
locations."/favicon.ico".extraConfig = ''
log_not_found off;
access_log off;
'';
# React client-side routing support
locations."/".extraConfig = ''
index index.html;
try_files $uri $uri/ /index.html$is_args$args;
'';
# Cache static assets
locations."~* \\.(js|jpg|gif|png|webp|css|woff2|svg|ico)$".extraConfig = ''
expires 365d;
add_header Pragma "public";
add_header Cache-Control "public";
'';
# Deny PHP execution
locations."~ [^/]\\.php(/|$)".extraConfig = ''
deny all;
'';
};
users.users."${domain}" = {
isNormalUser = true;
createHome = true;
home = dataDir;
homeMode = "770";
group = "nginx";
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIInwmhTIPw7NnR3LDn2T5N6by0ZPXdL3r2O/8oRUc/ki"
];
};
users.groups.${domain} = {};
}

View File

@@ -0,0 +1,49 @@
{ pkgs, lib, config, ... }:
let
domain = "ebs.cloonar.dev";
dataDir = "/var/www/${domain}";
in {
services.nginx.virtualHosts."${domain}" = {
forceSSL = true;
enableACME = true;
# Use HTTP-01 challenge for Let's Encrypt
acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
root = "${dataDir}";
locations."/favicon.ico".extraConfig = ''
log_not_found off;
access_log off;
'';
# React client-side routing support
locations."/".extraConfig = ''
index index.html;
try_files $uri $uri/ /index.html$is_args$args;
'';
# Cache static assets
locations."~* \\.(js|jpg|gif|png|webp|css|woff2|svg|ico)$".extraConfig = ''
expires 365d;
add_header Pragma "public";
add_header Cache-Control "public";
'';
# Deny PHP execution
locations."~ [^/]\\.php(/|$)".extraConfig = ''
deny all;
'';
};
users.users."${domain}" = {
isNormalUser = true;
createHome = true;
home = dataDir;
homeMode = "770";
group = "nginx";
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIErjoADQK5SJ5si/iezzwQn5xH1RkgnTIlbeE4BRU1FN"
];
};
users.groups.${domain} = {};
}

View File

@@ -0,0 +1,49 @@
{ pkgs, lib, config, ... }:
let
domain = "stage.ebs.amz.at";
dataDir = "/var/www/${domain}";
in {
services.nginx.virtualHosts."${domain}" = {
forceSSL = true;
enableACME = true;
# Use HTTP-01 challenge for Let's Encrypt
acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
root = "${dataDir}";
locations."/favicon.ico".extraConfig = ''
log_not_found off;
access_log off;
'';
# React client-side routing support
locations."/".extraConfig = ''
index index.html;
try_files $uri $uri/ /index.html$is_args$args;
'';
# Cache static assets
locations."~* \\.(js|jpg|gif|png|webp|css|woff2|svg|ico)$".extraConfig = ''
expires 365d;
add_header Pragma "public";
add_header Cache-Control "public";
'';
# Deny PHP execution
locations."~ [^/]\\.php(/|$)".extraConfig = ''
deny all;
'';
};
users.users."${domain}" = {
isNormalUser = true;
createHome = true;
home = dataDir;
homeMode = "770";
group = "nginx";
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIErjoADQK5SJ5si/iezzwQn5xH1RkgnTIlbeE4BRU1FN"
];
};
users.groups.${domain} = {};
}

1
hosts/amzebs-01/utils Symbolic link
View File

@@ -0,0 +1 @@
../../utils

1
hosts/fw/channel Normal file
View File

@@ -0,0 +1 @@
https://channels.nixos.org/nixos-25.11

192
hosts/fw/configuration.nix Normal file
View File

@@ -0,0 +1,192 @@
{ lib, pkgs, ... }: {
imports = [
./fleet.nix
./utils/bento.nix
./utils/modules/sops.nix
./utils/modules/lego/lego.nix
./utils/modules/nginx.nix
./utils/modules/autoupgrade.nix
./utils/modules/victoriametrics
./utils/modules/promtail
./utils/modules/borgbackup.nix
./utils/modules/set-nix-channel.nix
# fw
./modules/network-prefix.nix
./modules/networking.nix
./modules/setupnetwork.nix
./modules/firewall.nix
# ./modules/dhcp4.nix
# ./modules/unbound.nix
./modules/dnsmasq.nix
./modules/avahi.nix
./modules/openconnect.nix
./modules/wireguard.nix
./modules/podman.nix
./modules/omada.nix
./modules/ddclient.nix
# ./modules/wol.nix
# microvm
./modules/microvm.nix
./modules/gitea-vm.nix
# ./modules/vscode-server.nix # Add VS Code Server microvm
./modules/ai-mailer.nix
# ./modules/wazuh.nix
# web
./modules/web
# git
./modules/gitea.nix
# ./modules/fwmetrics.nix
# ha customers
./modules/ha-customers
./modules/firefox-sync.nix
./modules/fivefilters.nix
# ./modules/pyload
# home assistant
./modules/home-assistant
./modules/deconz.nix
# ./modules/mopidy.nix
# ./modules/mosquitto.nix
# ./modules/snapserver.nix
./modules/lms.nix
# gaming
# ./modules/palworld.nix
# ./modules/ark-survival-evolved.nix
./modules/foundry-vtt.nix
# setup network
./modules/setupnetwork.nix
./modules/set-nix-channel.nix # Automatically manage nix-channel from /var/bento/channel
./modules/grafana-monitor.nix # Grafana online status monitor
./hardware-configuration.nix
];
networkPrefix = "10.42";
nixpkgs.overlays = [
(import ./utils/overlays/packages.nix)
];
nixpkgs.config.permittedInsecurePackages = [
"openssl-1.1.1w"
];
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
"mongodb"
"ai-mailer"
"filebot"
];
# Intel N100 Graphics Support for hardware transcoding
hardware.graphics = {
enable = true;
extraPackages = with pkgs; [
intel-media-driver # VAAPI driver (iHD) for modern Intel GPUs
vpl-gpu-rt # Intel VPL/QSV runtime for Gen 12+ (N100)
intel-compute-runtime # OpenCL support for tone-mapping
];
};
hardware.enableRedistributableFirmware = true;
time.timeZone = "Europe/Vienna";
services.logind.settings.Login.RuntimeDirectorySize = "2G";
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
sops.defaultSopsFile = ./secrets.yaml;
environment.systemPackages = with pkgs; [
bento
conntrack-tools # view network connection states
ethtool # manage NIC settings (offload, NIC feeatures, ...)
git
htop # to see the system load
tcpdump # view network traffic
vim # my preferred editor
wol
inotify-tools
];
nix = {
settings = {
auto-optimise-store = true;
# Build performance optimizations
max-jobs = 4;
cores = 4;
# Enable eval caching for faster rebuilds
eval-cache = true;
# Use binary caches to avoid unnecessary rebuilds
substituters = [
"https://cache.nixos.org"
];
trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
];
};
gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 60d";
};
# Free up to 1GiB whenever there is less than 100MiB left.
extraOptions = ''
min-free = ${toString (100 * 1024 * 1024)}
max-free = ${toString (1024 * 1024 * 1024)}
'';
};
services.tlp = {
enable = true;
settings = {
CPU_SCALING_GOVERNOR_ON_AC = "performance"; # powersave or performance
CPU_ENERGY_PERF_POLICY_ON_AC = "performance"; # power or performance
# CPU_MIN_PERF_ON_AC = 0;
# CPU_MAX_PERF_ON_AC = 100; # max 100
};
};
systemd.services = {
powertop = {
wantedBy = [ "multi-user.target" ];
after = [ "multi-user.target" ];
description = "Powertop tunings";
path = [ pkgs.kmod ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = "yes";
ExecStart = "${pkgs.powertop}/bin/powertop --auto-tune && for dev in /sys/class/net/*; do echo on > \"$dev/device/power/control\"; done'";
};
};
};
boot.tmp.cleanOnBoot = true;
zramSwap.enable = true;
networking.hostName = "fw";
services.openssh.enable = true;
users.users.root.openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRQuPqH5fdX3KEw7DXzWEdO3AlUn1oSmtJtHB71ICoH Generated By Termius"
];
# backups
borgbackup.repo = "u149513-sub2@u149513-sub2.your-backup.de:borg";
services.borgbackup.jobs.default.paths = lib.mkAfter [
"/var/lib/microvms/persist/web-02/var/backup"
];
system.stateVersion = "22.05";
}

1
hosts/fw/fleet.nix Symbolic link
View File

@@ -0,0 +1 @@
../../fleet.nix

View File

@@ -0,0 +1,22 @@
{ lib, config, modulesPath, ... }:
{
boot.loader.systemd-boot = {
enable = true;
configurationLimit = 5;
};
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "vmw_pvscsi" "xen_blkfront" ];
boot.initrd.kernelModules = [ "nvme" "kvm-intel" ];
fileSystems."/boot" = {
device = "/dev/disk/by-label/boot";
fsType = "vfat";
};
fileSystems."/" = {
device = "/dev/disk/by-partlabel/NIXOS";
fsType = "ext4";
};
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View File

@@ -0,0 +1,111 @@
{ config, pkgs, ... }:
{
users.users.ai-mailer = {
isSystemUser = true;
group = "ai-mailer";
home = "/var/lib/ai-mailer";
createHome = true;
description = "AI Mailer service user";
};
users.groups.ai-mailer = { };
environment.etc."ai-mailer/config.yaml" = {
mode = "0400";
user = "ai-mailer";
group = "ai-mailer";
text = ''
imap:
server: "imap.gmail.com"
port: 993
username: "it@paraclub.at"
password: "file://${config.sops.secrets.ai-mailer-imap-password.path}"
mailbox_in: "INBOX"
draft_box: "[Gmail]/Entwürfe"
processed_box: "INBOX/Done"
use_tls: true
ai:
openrouter_api_key: "file://${config.sops.secrets.ai-mailer-openrouter-key.path}"
model: "openai/gpt-5-mini"
temperature: 0.3
max_tokens: 200000
context:
urls:
- "https://paraclub.cloonar.dev/de/tandemfallschirmspringen/faq/"
- "https://paraclub.at/de/"
- "https://paraclub.at/de/tandemfallschirmspringen/alle-infos/"
- "https://paraclub.at/de/tandemfallschirmspringen/kosten-tandemsprung/"
- "https://paraclub.at/de/ueber-uns/anfahrt/"
- "https://paraclub.at/de/tandemfallschirmspringen/faq/"
- "https://paraclub.at/de/ausbildung/uebersicht/"
- "https://paraclub.at/de/ausbildung/aff-ablauf/"
- "https://paraclub.at/de/ausbildung/kurstermine/"
- "https://paraclub.at/de/ausbildung/anmeldung/"
- "https://paraclub.at/de/ausbildung/kosten/"
polling:
interval: "300s"
processing:
max_tokens: 30000
skip_junk_emails: false
logging:
level: "info"
file_path: "/var/log/ai-mailer/ai-mailer.log"
'';
};
sops.secrets.ai-mailer-imap-password = {
owner = "ai-mailer";
};
sops.secrets.ai-mailer-openrouter-key = {
owner = "ai-mailer";
};
systemd.services.ai-mailer = {
description = "AI Mail Assistant Service";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
User = "ai-mailer";
Group = "ai-mailer";
WorkingDirectory = "/var/lib/ai-mailer";
ExecStart = "${pkgs.ai-mailer}/bin/ai-mailer -config /etc/ai-mailer/config.yaml";
Restart = "always";
RestartSec = "10s";
StateDirectory = "ai-mailer";
LogsDirectory = "ai-mailer";
RuntimeDirectory = "ai-mailer";
# Security settings
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
CapabilityBoundingSet = "";
};
restartTriggers = [
"/etc/ai-mailer/config.yaml"
config.sops.secrets.ai-mailer-imap-password.path
config.sops.secrets.ai-mailer-openrouter-key.path
];
};
}

View File

@@ -0,0 +1,94 @@
{ config, pkgs, lib, ... }:
let
domain = "a11ywatch.cloonar.com";
confDir = "/var/lib/a11ywatch";
json = pkgs.formats.json { };
in {
# 1) Enable Podman (daemonless, drop-in for docker)
virtualisation.podman.enable = true; # :contentReference[oaicite:0]{index=0}
virtualisation.podman.dockerCompat = true; # :contentReference[oaicite:1]{index=1}
virtualisation.podman.defaultNetwork.settings.dns_enabled = true;# :contentReference[oaicite:2]{index=2}
services.nginx.virtualHosts."${domain}" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://localhost:3000/";
};
};
environment.etc."containers/networks/a11ywatch-net.json" = {
source = json.generate "a11ywatch-net.json" ({
name = "a11ywatch-net";
id = "ccb4b7fb90d2df26db27ef0995765b04f52d318db752c9474b470c5ef4d7978d";
driver = "bridge";
network_interface = "podman1";
subnets = [
{
subnet = "10.89.0.0/24";
gateway = "10.89.0.1";
}
];
ipv6_enabled = false;
internal = false;
dns_enabled = true;
ipam_options = {
driver = "host-local";
};
});
};
users.users.a11ywatch = {
isSystemUser = true;
group = "a11ywatch";
home = "/var/lib/a11ywatch";
createHome = true;
};
users.groups.a11ywatch = { };
users.groups.docker.members = [ "a11ywatch" ];
# 2) Create the bridge network on boot via a oneshot systemd service
systemd.services.a11ywatch-net = {
description = "Ensure a11ywatch-net Podman network exists";
wants = [ "podman.service" ];
after = [ "podman.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = ''
${pkgs.podman}/bin/podman network inspect a11ywatch-net >/dev/null 2>&1 \
|| ${pkgs.podman}/bin/podman network create a11ywatch-net
'';
RemainAfterExit = true;
};
wantedBy = [
"multi-user.target"
];
};
# 3) Declare your two containers using the podman backend
virtualisation.oci-containers = {
backend = "podman"; # :contentReference[oaicite:3]{index=3}
containers = {
a11ywatch-backend = {
image = "docker.io/a11ywatch/a11ywatch:latest";
autoStart = true;
ports = [ "3280:3280" ];
volumes = [ "${confDir}:/a11ywatch/conf" ];
environment = { SUPER_MODE = "true"; };
extraOptions = [ "--network=a11ywatch-net" ];
};
a11ywatch-frontend = {
image = "docker.io/a11ywatch/web:latest";
autoStart = true;
ports = [ "3000:3000" ];
volumes = [ "${confDir}:/a11ywatch/conf" ];
environment = { SUPER_MODE = "true"; };
extraOptions = [
"--network=a11ywatch-net"
];
};
};
};
}

View File

@@ -0,0 +1,24 @@
{ config, pkgs, ... }:
{
virtualisation.oci-containers.backend = "podman";
virtualisation.oci-containers.containers = {
ark = {
image = "hermsi/ark-server:latest";
autoStart = true;
environmentFiles = [
config.sops.secrets.ark.path
];
volumes = [
"/var/lib/ark/app:/app/"
"/var/lib/ark/backup:/home/steam/ARK-Backups"
];
extraOptions = [
"--network=server"
"--ip=${config.networkPrefix}.97.201"
];
};
};
sops.secrets.ark = {};
}

View File

@@ -0,0 +1,16 @@
{ pkgs, ... }: {
services.avahi = {
enable = true;
reflector = true;
allowInterfaces = [
"multimedia"
"server"
"lan"
"smart"
];
};
environment.systemPackages = with pkgs; [
nssmdns
];
}

View File

@@ -0,0 +1,54 @@
{
lib,
pkgs,
...
}: let
users = [
{
username = "ca-test";
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDglSLU9AUtbU0fCN0eByi/EHyo1QiPPLiscN5RAR+wq";
}
];
userList = lib.concatStringsSep "," (map (u: u.username) users);
in {
environment.etc = {
# our single user+key file
"cloonar_assistant_ssh/sftp_users_keys" = {
text = lib.concatStringsSep "\n"
(map (u: "${u.username} ${u.key}") users);
mode = "0600";
user = "root";
group = "root";
};
# the little awk script to extract the key for $1
"cloonar_assistant_ssh/sftp-fetch-key.sh" = {
text = ''
#!/usr/bin/env bash
awk -v u="$1" '$1==u { $1=""; sub(/^ +/, ""); print }' /etc/cloonar_assistant_ssh/sftp_users_keys
'';
mode = "0700";
user = "root";
group = "root";
};
};
systemd.tmpfiles.rules = map (u:
# Type 'd' = create directory if missing
# Mode 0755, owner root:root
"d /home/cloonar-assistant-configs/${u.username} 0755 root root -"
) users;
services.openssh.extraConfig = ''
Match User ${userList}
X11Forwarding no
AllowTcpForwarding no
ChrootDirectory /home/cloonar-assistant-configs/%u
ForceCommand internal-sftp
# only for those matched users:
AuthorizedKeysCommand /etc/cloonar_assistant_ssh/sftp-fetch-key.sh %u
AuthorizedKeysCommandUser root
'';
}

View File

@@ -0,0 +1,25 @@
{ config, ... }:
{
services.ddclient = {
enable = true;
usev4 = "if, if=wan";
protocol = "hetzner";
# server = "https://dns.hetzner.com/api/v1/";
username = "dominik.polakovics@cloonar.com";
passwordFile = config.sops.secrets.ddclient.path;
zone = "cloonar.com";
domains = [
"fw.cloonar.com"
"vpn.cloonar.com"
"git.cloonar.com"
"palworld.cloonar.com"
"matrix.cloonar.com"
"element.cloonar.com"
"tinder.cloonar.com"
];
};
sops.secrets.ddclient = {
# owner = config.systemd.services.ddclient.serviceConfig.User;
};
}

View File

@@ -0,0 +1,36 @@
{ config, pkgs, ... }: {
virtualisation = {
oci-containers.containers = {
deconz = {
autoStart = true;
image = "marthoc/deconz";
volumes = [
"/etc/localtime:/etc/localtime:ro"
"/var/lib/deconz:/root/.local/share/dresden-elektronik/deCONZ"
"/dev/bus/usb:/dev/bus/usb:ro"
"/run/udev:/run/udev:ro"
];
environment = {
DECONZ_DEVICE = "/dev/ttyACM0";
TZ = "Europe/Vienna";
DECONZ_UID = "0";
DECONZ_GID = "0";
DECONZ_START_VERBOSE = "1";
};
extraOptions = [
"--network=server"
"--ip=${config.networkPrefix}.97.22"
"--device=/dev/ttyACM0"
"--hostname=deconz"
"--mac-address=1a:c4:04:6e:29:bd"
"--cap-add=CAP_MKNOD"
"--cap-add=CAP_NET_RAW"
"--cap-add=CAP_NET_ADMIN"
"--device-cgroup-rule=c 166:* rmw"
"--device-cgroup-rule=c 188:* rmw"
"--security-opt=label=disable"
];
};
};
};
}

289
hosts/fw/modules/dhcp4.nix Normal file
View File

@@ -0,0 +1,289 @@
{ config, ... }:
{
services.kea.dhcp4 = {
enable = true;
settings = {
interfaces-config = {
interfaces = [
"lan"
"server"
"infrastructure"
"multimedia"
"smart"
"guest"
];
};
lease-database = {
name = "/var/lib/kea/dhcp4.leases";
persist = true;
type = "memfile";
};
rebind-timer = 2000;
renew-timer = 1000;
subnet4 = [
{
id = 96;
pools = [
{
pool = "${config.networkPrefix}.96.100 - ${config.networkPrefix}.96.240";
}
];
subnet = "${config.networkPrefix}.96.0/24";
interface = "lan";
option-data = [
{
name = "routers";
data = "${config.networkPrefix}.96.1";
}
{
name = "domain-name";
data = "cloonar.com";
}
{
name = "domain-search";
data = "cloonar.com";
}
{
name = "domain-name-servers";
data = "${config.networkPrefix}.96.1";
}
];
reservations = [
{
hw-address = "04:7c:16:d5:63:5e";
ip-address = "${config.networkPrefix}.96.5";
server-hostname = "omada.cloonar.com";
}
{
hw-address = "30:05:5c:56:62:37";
ip-address = "${config.networkPrefix}.96.100";
server-hostname = "brn30055c566237.cloonar.com";
}
{
hw-address = "24:df:a7:b1:1b:74";
ip-address = "${config.networkPrefix}.96.101";
server-hostname = "rmproplus-b1-1b-74.cloonar.com";
}
];
}
{
id = 97;
pools = [
{
pool = "${config.networkPrefix}.97.100 - ${config.networkPrefix}.97.240";
}
];
subnet = "${config.networkPrefix}.97.0/24";
interface = "server";
option-data = [
{
name = "routers";
data = "${config.networkPrefix}.97.1";
}
{
name = "domain-name";
data = "cloonar.com";
}
{
name = "domain-name-servers";
data = "${config.networkPrefix}.97.1";
}
];
reservations = [
{
hw-address = "1a:c4:04:6e:29:bd";
ip-address = "${config.networkPrefix}.97.2";
server-hostname = "omada.cloonar.com";
}
{
hw-address = "02:00:00:00:00:03";
ip-address = "${config.networkPrefix}.97.5";
server-hostname = "web-02.cloonar.com";
}
{
hw-address = "02:00:00:00:00:04";
ip-address = "${config.networkPrefix}.97.6";
server-hostname = "matrix.cloonar.com";
}
{
hw-address = "ea:db:d4:c1:18:ba";
ip-address = "${config.networkPrefix}.97.50";
server-hostname = "git.cloonar.com";
}
{
hw-address = "c2:4f:64:dd:13:0c";
ip-address = "${config.networkPrefix}.97.20";
server-hostname = "home-assistant.cloonar.com";
}
{
hw-address = "1a:c4:04:6e:29:02";
ip-address = "${config.networkPrefix}.97.25";
server-hostname = "deconz.cloonar.com";
}
];
}
{
id = 101;
pools = [
{
pool = "${config.networkPrefix}.101.100 - ${config.networkPrefix}.101.240";
}
];
subnet = "${config.networkPrefix}.101.0/24";
interface = "infrastructure";
option-data = [
{
name = "routers";
data = "${config.networkPrefix}.101.1";
}
{
name = "domain-name";
data = "cloonar.com";
}
{
name = "domain-name-servers";
data = "${config.networkPrefix}.101.1";
}
{
name = "capwap-ac-v4";
code = 138;
data = "${config.networkPrefix}.97.2";
}
];
reservations = [
];
}
{
id = 99;
pools = [
{
pool = "${config.networkPrefix}.99.100 - ${config.networkPrefix}.99.240";
}
];
subnet = "${config.networkPrefix}.99.0/24";
interface = "multimedia";
option-data = [
{
name = "routers";
data = "${config.networkPrefix}.99.1";
}
{
name = "domain-name";
data = "cloonar.multimedia";
}
{
name = "domain-name-servers";
data = "${config.networkPrefix}.99.1";
}
];
reservations = [
{
hw-address = "c4:a7:2b:c7:ea:30";
ip-address = "${config.networkPrefix}.99.10";
hostname = "metz.cloonar.multimedia";
}
{
hw-address = "f0:2f:9e:d4:3b:21";
ip-address = "${config.networkPrefix}.99.11";
hostname = "firetv-living";
}
{
hw-address = "bc:33:29:ed:24:f0";
ip-address = "${config.networkPrefix}.99.12";
hostname = "ps5";
}
{
hw-address = "e4:2a:ac:32:3f:79";
ip-address = "${config.networkPrefix}.99.13";
hostname = "xbox";
}
{
hw-address = "98:b6:e9:b6:ef:f4";
ip-address = "${config.networkPrefix}.99.14";
hostname = "switch";
}
{
hw-address = "f0:2f:9e:c1:74:72";
ip-address = "${config.networkPrefix}.99.21";
hostname = "firetv-bedroom";
}
{
hw-address = "30:05:5c:56:62:37";
ip-address = "${config.networkPrefix}.99.100";
server-hostname = "brn30055c566237";
}
];
}
{
id = 254;
pools = [
{
pool = "${config.networkPrefix}.254.10 - ${config.networkPrefix}.254.254";
}
];
subnet = "${config.networkPrefix}.254.0/24";
interface = "guest";
option-data = [
{
name = "routers";
data = "${config.networkPrefix}.254.1";
}
{
name = "domain-name-servers";
data = "9.9.9.9";
}
];
}
{
id = 100;
pools = [
{
pool = "${config.networkPrefix}.100.100 - ${config.networkPrefix}.100.240";
}
];
subnet = "${config.networkPrefix}.100.0/24";
interface = "smart";
option-data = [
{
name = "routers";
data = "${config.networkPrefix}.100.1";
}
{
name = "domain-name";
data = "cloonar.smart";
}
{
name = "domain-name-servers";
data = "${config.networkPrefix}.100.1";
}
];
reservations = [
{
hw-address = "fc:ee:28:03:63:e9";
ip-address = "${config.networkPrefix}.100.148";
server-hostname = "k1c";
}
{
hw-address = "cc:50:e3:bc:27:64";
ip-address = "${config.networkPrefix}.100.112";
server-hostname = "Nuki_Bridge_1A753F72";
}
{
hw-address = "34:6f:24:f3:af:ad";
ip-address = "${config.networkPrefix}.100.137";
server-hostname = "daikin86604";
}
{
hw-address = "34:6f:24:c1:f8:54";
ip-address = "${config.networkPrefix}.100.139";
server-hostname = "daikin53800";
}
];
}
];
valid-lifetime = 4000;
};
};
}

View File

@@ -0,0 +1,176 @@
{ config, ... }: {
services.resolved.enable = false;
services.dnsmasq = {
enable = true;
settings = {
port = "53";
bind-interfaces = true; # force dnsmasq to bind immediately
expand-hosts = true;
log-dhcp = true;
server = [
"/epicenter.works/10.50.60.1"
"/akvorrat.at/10.50.60.1"
"9.9.9.9"
"149.112.112.11"
];
interface = [
"lan"
"server"
"infrastructure"
"multimedia"
"guest"
"smart"
];
domain = [
"cloonar.com,lan"
"cloonar.com,server"
"cloonar.com,infrastructure"
"cloonar.multimedia,multimedia"
"cloonar.smart,smart"
"cloonar.guest,guest"
];
dhcp-option = [
"lan,15,cloonar.com" # domain name
"lan,3,${config.networkPrefix}.96.1" # Gateway
"lan,6,${config.networkPrefix}.96.1" # DNS
"server,15,cloonar.com"
"server,3,${config.networkPrefix}.97.1"
"server,6,${config.networkPrefix}.97.1"
"infrastructure,15,cloonar.com"
"infrastructure,3,${config.networkPrefix}.101.1"
"infrastructure,6,${config.networkPrefix}.101.1"
"multimedia,15,cloonar.multimedia"
"multimedia,3,${config.networkPrefix}.99.1"
"multimedia,6,${config.networkPrefix}.99.1"
"smart,15,cloonar.smart"
"smart,3,${config.networkPrefix}.100.1"
"smart,6,${config.networkPrefix}.100.1"
"guest,15,cloonar.guest"
"guest,3,${config.networkPrefix}.254.1"
"guest,6,9.9.9.9"
];
dhcp-range = [
"lan,${config.networkPrefix}.96.100,${config.networkPrefix}.96.200,24h"
"server,${config.networkPrefix}.97.100,${config.networkPrefix}.97.200,24h"
"infrastructure,${config.networkPrefix}.101.100,${config.networkPrefix}.101.200,24h"
"multimedia,${config.networkPrefix}.99.100,${config.networkPrefix}.99.200,24h"
"smart,${config.networkPrefix}.100.100,${config.networkPrefix}.100.200,24h"
"guest,${config.networkPrefix}.254.100,${config.networkPrefix}.254.200,24h"
];
dhcp-host = [
"24:df:a7:b1:1b:74,${config.networkPrefix}.96.101,rmproplus-b1-1b-74"
"30:05:5c:56:62:37,${config.networkPrefix}.99.100,brn30055c566237"
"1a:c4:04:6e:29:bd,${config.networkPrefix}.97.2,omada"
"02:00:00:00:00:04,${config.networkPrefix}.97.6,matrix"
"ea:db:d4:c1:18:ba,${config.networkPrefix}.97.50,git"
"c2:4f:64:dd:13:0c,${config.networkPrefix}.97.20,home-assistant"
"6c:1f:f7:8e:a9:86,${config.networkPrefix}.97.11,nas"
"1a:c4:04:6e:29:02,${config.networkPrefix}.101.25,deconz"
"c4:a7:2b:c7:ea:30,${config.networkPrefix}.99.10,metz"
"f0:2f:9e:d4:3b:21,${config.networkPrefix}.99.11,firetv-living"
"e4:2a:ac:32:3f:79,${config.networkPrefix}.99.13,xbox"
"f0:2f:9e:c1:74:72,${config.networkPrefix}.99.21,firetv-bedroom"
"fc:ee:28:03:63:e9,${config.networkPrefix}.100.148,k1c"
"cc:50:e3:bc:27:64,${config.networkPrefix}.100.112,Nuki_Bridge_1A753F72"
"34:6f:24:f3:af:ad,${config.networkPrefix}.100.137,daikin86604"
"34:6f:24:c1:f8:54,${config.networkPrefix}.100.139,daikin53800"
];
address = [
"/fw.cloonar.com/${config.networkPrefix}.97.1"
"/omada.cloonar.com/${config.networkPrefix}.97.2"
"/web-02.cloonar.com/${config.networkPrefix}.97.5"
"/pla.cloonar.com/${config.networkPrefix}.97.5"
"/piped.cloonar.com/${config.networkPrefix}.97.5" # Replaced by Invidious
"/pipedapi.cloonar.com/${config.networkPrefix}.97.5" # Replaced by Invidious
"/invidious.cloonar.com/${config.networkPrefix}.97.5"
"/fivefilters.cloonar.com/${config.networkPrefix}.97.5"
"/n8n.cloonar.com/${config.networkPrefix}.97.5"
"/home-assistant.cloonar.com/${config.networkPrefix}.97.20"
"/mopidy.cloonar.com/${config.networkPrefix}.97.21"
"/snapcast.cloonar.com/${config.networkPrefix}.97.21"
"/lms.cloonar.com/${config.networkPrefix}.97.21"
"/git.cloonar.com/${config.networkPrefix}.97.50"
"/feeds.cloonar.com/188.34.191.144"
"/nukibridge1a753f72.cloonar.smart/${config.networkPrefix}.100.112"
"/allywatch.cloonar.com/${config.networkPrefix}.97.5"
"/brn30055c566237.cloonar.multimedia/${config.networkPrefix}.99.100"
"/stage.wsw.at/10.254.235.22"
"/prod.wsw.at/10.254.217.23"
"/piwik.wohnservice-wien.at/10.254.240.109"
"/wohnberatung-wien.at/10.254.240.109"
"/wohnpartner-wien.at/10.254.240.109"
"/wohnservice-wien.at/10.254.240.109"
"/mieterhilfe.at/10.254.240.109"
"/wienbautvor.at/10.254.240.109"
"/wienwohntbesser.at/10.254.240.109"
"/a.stage.wohnberatung-wien.at/10.254.240.110"
"/a.stage.wohnpartner-wien.at/10.254.240.110"
"/a.stage.wohnservice-wien.at/10.254.240.110"
"/a.stage.mieterhilfe.at/10.254.240.110"
"/a.stage.wienbautvor.at/10.254.240.110"
"/a.stage.wienwohntbesser.at/10.254.240.110"
"/b.stage.wohnberatung-wien.at/10.254.240.110"
"/b.stage.wohnpartner-wien.at/10.254.240.110"
"/b.stage.wohnservice-wien.at/10.254.240.110"
"/b.stage.mieterhilfe.at/10.254.240.110"
"/b.stage.wienbautvor.at/10.254.240.110"
"/b.stage.wienwohntbesser.at/10.254.240.110"
"/web.hilgenberg-gmbh.de/91.107.197.169"
# gaming
"/foundry-vtt.cloonar.com/${config.networkPrefix}.97.5"
"/sync.cloonar.com/${config.networkPrefix}.97.5"
# multimedia
"/dl.cloonar.com/${config.networkPrefix}.97.5"
"/jellyfin.cloonar.com/${config.networkPrefix}.97.5"
"/deconz.cloonar.multimedia/${config.networkPrefix}.97.22"
"/ddl-warez.to/172.67.184.30"
"/cdnjs.cloudflare.com/104.17.24.14"
# esphome devices
"/livingroom-bulb-1.cloonar.smart/${config.networkPrefix}.100.11"
"/livingroom-bulb-2.cloonar.smart/${config.networkPrefix}.100.12"
"/livingroom-bulb-3.cloonar.smart/${config.networkPrefix}.100.13"
"/livingroom-bulb-4.cloonar.smart/${config.networkPrefix}.100.14"
"/livingroom-bulb-5.cloonar.smart/${config.networkPrefix}.100.15"
"/livingroom-bulb-6.cloonar.smart/${config.networkPrefix}.100.16"
"/bedroom-bulb-0.cloonar.smart/${config.networkPrefix}.100.21"
"/bedroom-bulb-0.cloonar.smart/${config.networkPrefix}.100.22"
"/bedroom-bulb-0.cloonar.smart/${config.networkPrefix}.100.23"
"/bedroom-bulb-0.cloonar.smart/${config.networkPrefix}.100.24"
"/hallway-bulb-0.cloonar.smart/${config.networkPrefix}.100.31"
"/hallway-bulb-0.cloonar.smart/${config.networkPrefix}.100.32"
"/bath-bulb-0.cloonar.smart/${config.networkPrefix}.100.41"
"/bath-bulb-0.cloonar.smart/${config.networkPrefix}.100.42"
"/paraclub.at/188.34.191.144"
];
};
};
systemd.services.dnsmasq = {
requires = [ "network-online.target" ];
after = [ "network-online.target" ];
};
networking.firewall.allowedUDPPorts = [ 53 67 ];
}

View File

@@ -0,0 +1,59 @@
{ config, pkgs, ... }:
let
domain = "sync.cloonar.com";
networkPrefix = config.networkPrefix;
in {
sops.secrets.firefox-sync = {
mode = "0777";
};
security.acme.certs."${domain}" = {
group = "nginx";
};
containers."firefox-sync" = {
autoStart = true;
ephemeral = false; # because of ssh key
privateNetwork = true;
hostBridge = "server";
hostAddress = "${config.networkPrefix}.97.1";
localAddress = "${config.networkPrefix}.97.6/24";
bindMounts = {
"/run/secrets/firefox-sync" = {
hostPath = "/run/secrets/firefox-sync";
isReadOnly = true;
};
};
config = { lib, config, pkgs, ... }: {
networking = {
hostName = "firefox-sync";
useHostResolvConf = false;
defaultGateway = {
address = "${networkPrefix}.97.1";
interface = "eth0";
};
nameservers = [ "${networkPrefix}.97.1" ];
};
services.mysql.package = pkgs.mariadb;
services.firefox-syncserver = {
enable = true;
settings.host = "0.0.0.0";
singleNode = {
enable = true;
hostname = "0.0.0.0";
url = "https://${domain}";
};
secrets = "/run/secrets/firefox-sync";
logLevel = "debug";
};
networking.firewall = {
enable = true;
allowedTCPPorts = [ 5000 ];
};
system.stateVersion = "23.05";
};
};
}

View File

@@ -0,0 +1,191 @@
{ config, pkgs, ... }: {
networking = {
firewall.checkReversePath = false;
nat.enable = false;
nftables = {
enable = true;
tables = {
"cloonar-fw" = {
family = "inet";
content = ''
chain snap-qos-raw {
type filter hook prerouting priority raw; policy accept;
tcp dport 1704 counter mark set 10 comment "Mark Snapcast traffic"
tcp dport 3483 counter mark set 10 comment "Mark Squezelite traffic"
udp dport 3483 counter mark set 10 comment "Mark Squezelite traffic"
}
chain snap-qos-mangle {
type filter hook postrouting priority mangle + 10; policy accept;
mark 10 counter ip dscp set cs3 comment "Tag Snapcast with CS3"
}
chain output {
type filter hook output priority 100; policy accept;
}
chain rpfilter {
type filter hook prerouting priority mangle + 10; policy drop;
meta nfproto ipv4 udp sport . udp dport { 68 . 67, 67 . 68 } accept comment "DHCPv4 client/server"
fib saddr . mark . iif oif exists accept
}
chain input {
type filter hook input priority filter; policy drop;
iifname "lo" accept comment "trusted interfaces"
iifname "lan" counter accept comment "Spice"
iifname { "server", "vserver", "vm-*", "lan", "wg_cloonar" } counter accept comment "allow trusted to router"
ct state vmap { invalid : drop, established : accept, related : accept, new : jump input-allow, untracked : jump input-allow }
tcp flags syn / fin,syn,rst,ack log prefix "refused connection: " level info
}
chain input-allow {
udp dport != { 53, 5353 } ct state new limit rate over 1/second burst 10 packets drop comment "rate limit for new connections"
iifname lo accept
iifname "wan" udp dport 51820 counter accept comment "Wireguard traffic"
iifname "wan" tcp dport 9273 counter accept comment "Prometheus traffic"
iifname "lan" tcp dport 5931 counter accept comment "Spice"
iifname { "server", "vserver", "vm-*", "lan", "wg_cloonar" } counter accept comment "allow trusted to router"
iifname { "multimedia", "smart", "infrastructure", "podman0", "setup" } udp dport { 53, 5353 } counter accept comment "DNS"
iifname { "multimedia", "smart", "infrastructure", "server", "lan", "guest" } udp dport { 67 } counter accept comment "DHCP"
iifname { "wan", "multimedia" } icmp type { echo-request, destination-unreachable, time-exceeded } counter accept comment "Allow select ICMP"
# Accept mDNS for avahi reflection
iifname "server" ip saddr ${config.networkPrefix}.97.20/32 tcp dport { llmnr } counter accept
iifname "server" ip saddr ${config.networkPrefix}.97.20/32 udp dport { mdns, llmnr } counter accept
iifname "server" udp dport 5353 ip daddr 224.0.0.251 counter accept comment "Avahi mDNS"
iifname "lan" udp dport 5353 ip daddr 224.0.0.251 counter accept comment "Avahi mDNS"
# Allow all returning traffic
ct state { established, related } counter accept
# Allow returning traffic from wrwks and drop everthing else
iifname "wrwks" ct state { established, related } counter accept
iifname "wrwks" drop
# Allow returning traffic from wg_epicenter and drop everthing else
iifname "wg_epicenter" ct state { established, related } counter accept
iifname "wg_epicenter" drop
# Allow returning traffic from wg_ghetto_at and drop everthing else
iifname "wg_ghetto_at" ct state { established, related } counter accept
iifname "wg_ghetto_at" drop
# Allow returning traffic from wan and drop everthing else
iifname "wan" ct state { established, related } accept comment "Allow established traffic"
iifname "wan" icmp type { echo-request, destination-unreachable, time-exceeded } counter accept comment "Allow select ICMP"
iifname "wan" counter drop comment "Drop all other unsolicited traffic from wan"
limit rate 60/minute burst 100 packets log prefix "Input - Drop: " comment "Log any unmatched traffic"
}
chain forward {
type filter hook forward priority filter; policy drop;
iifname "wg_cloonar" counter accept comment "test wireguard"
iifname "wg_cloonar" oifname lo counter accept comment "wireguard to server"
# enable flow offloading for better throughput
# ip protocol { tcp, udp } flow offload @f
# broadcast
iifname "server" oifname { "lan", "multimedia" } udp dport { 9 } counter accept comment "wakeonlan"
# multimedia airplay
iifname "multimedia" oifname { "lan" } counter accept
iifname "multimedia" oifname "server" tcp dport { 1704, 1705 } counter accept
iifname "multimedia" oifname "server" tcp dport { 3483, 9000 } counter accept
iifname "multimedia" oifname "server" udp dport { 3483 } counter accept
iifname "multimedia" oifname "server" icmp type { echo-request, destination-unreachable, time-exceeded } counter accept comment "Allow select ICMP"
iifname "lan" oifname "server" udp dport { 5000, 5353, 6001 - 6011 } counter accept
# avahi
iifname "server" ip saddr ${config.networkPrefix}.97.20/32 oifname { "lan" } counter accept
# Allow Chromecast
iifname "lan" oifname "server" udp dport 5353 ip daddr 224.0.0.251 counter accept comment "mDNS query LANServer"
iifname "server" oifname "lan" udp sport 5353 ip saddr 224.0.0.251 counter accept comment "mDNS response ServerLAN"
iifname "lan" oifname "server" tcp dport 9881 counter accept comment "chromecast"
# SSDP / UPnP discovery if needed
iifname { "lan", "server" } oifname { "server", "lan" } \
udp dport 1900 ip daddr 239.255.255.250 counter accept comment "SSDP query"
iifname { "lan", "server" } oifname { "server", "lan" } \
udp sport 1900 ip saddr 239.255.255.250 counter accept comment "SSDP response"
# smart home coap
iifname "smart" oifname "server" ip daddr ${config.networkPrefix}.97.20/32 udp dport { 5683 } counter accept
iifname "smart" oifname "server" ip daddr ${config.networkPrefix}.97.20/32 tcp dport { 1883 } counter accept
# Forward to git server
oifname "server" ip daddr ${config.networkPrefix}.97.50 tcp dport { 22 } counter accept
oifname "server" ip daddr ${config.networkPrefix}.97.5 tcp dport { 80, 443 } counter accept
# lan and vpn to any
iifname { "lan", "server", "vserver", "wg_cloonar" } oifname { "lan", "vb-*", "vm-*", "server", "vserver", "infrastructure", "multimedia", "smart", "wg_cloonar", "guest", "setup" } counter accept
iifname { "lan", "server", "wg_cloonar" } oifname { "wrwks", "wg_epicenter", "wg_ghetto_at" } counter accept
iifname { "infrastructure", "setup" } oifname { "server", "vserver" } counter accept
iifname { "lan", "wan" } udp dport { 8211, 27015 } counter accept comment "palworld"
# accept palword server
iifname { "wan", "lan" } oifname "podman0" udp dport { 8211, 27015 } counter accept comment "palworld"
# forward to ark server
oifname "server" ip daddr ${config.networkPrefix}.97.201 tcp dport { 27020 } counter accept comment "ark survival evolved"
oifname "server" ip daddr ${config.networkPrefix}.97.201 udp dport { 7777, 7778, 27015 } counter accept comment "ark survival evolved"
# firefox-sync
oifname "server" ip daddr ${config.networkPrefix}.97.51 tcp dport { 5000 } counter accept comment "firefox-sync"
# allow all established, related
ct state { established, related } accept comment "Allow established traffic"
# Allow trusted network WAN access
iifname {
"lan",
"infrastructure",
"server",
"vserver",
"multimedia",
"smart",
"wg_cloonar",
"podman*",
"guest",
"setup",
"vb-*",
"vm-*",
} oifname {
"wan",
} counter accept comment "Allow trusted LAN to WAN"
limit rate 60/minute burst 100 packets log prefix "Forward - Drop: " comment "Log any unmatched traffic"
}
'';
};
"cloonar-nat" = {
family = "ip";
content = ''
chain prerouting {
type nat hook prerouting priority filter; policy accept;
iifname "server" ip daddr ${config.networkPrefix}.96.255 udp dport { 9 } dnat to ${config.networkPrefix}.96.255
iifname "wan" tcp dport { 22 } dnat to ${config.networkPrefix}.97.50
iifname "wan" tcp dport { 80, 443 } dnat to ${config.networkPrefix}.97.5
iifname "wan" tcp dport { 5000 } dnat to ${config.networkPrefix}.97.51
iifname { "wan", "lan" } udp dport { 7777, 7778, 27015 } dnat to ${config.networkPrefix}.97.201
iifname { "wan", "lan" } tcp dport { 27020 } dnat to ${config.networkPrefix}.97.201
}
# Setup NAT masquerading on external interfaces
chain postrouting {
type nat hook postrouting priority filter; policy accept;
oifname { "wan", "wg_cloonar", "wrwks", "wg_epicenter", "wg_ghetto_at" } masquerade
iifname { "lan", "wg_cloonar" } ip daddr ${config.networkPrefix}.110.101 masquerade
iifname { "wan", "wg_cloonar" } ip daddr ${config.networkPrefix}.97.50 masquerade
iifname { "wan", "wg_cloonar" } ip daddr ${config.networkPrefix}.97.51 masquerade
iifname { "wan", "wg_cloonar" } ip daddr ${config.networkPrefix}.97.201 masquerade
}
'';
};
};
};
};
}

View File

@@ -0,0 +1,32 @@
{ config, pkgs, ... }: {
users.users.fivefilters = {
isSystemUser = true;
group = "omada";
home = "/var/lib/fivefilters";
createHome = true;
};
users.groups.fivefilters = { };
systemd.tmpfiles.rules = [
# parent is created by createHome already, but harmless to repeat
"d /var/lib/fivefilters 0755 fivefilters fivefilters - -"
"d /var/lib/fivefilters/cache 0755 fivefilters fivefilters - -"
];
# TODO: check if we can run docker service as other user than root
virtualisation = {
oci-containers.containers = {
fivefilters = {
autoStart = true;
image = "heussd/fivefilters-full-text-rss:3.8.1";
volumes = [
"/var/lib/fivefilters/cache:/var/www/html/cache"
];
extraOptions = [
"--network=server"
"--ip=${config.networkPrefix}.97.10"
];
};
};
};
}

View File

@@ -0,0 +1,162 @@
{ config, pkgs, ... }:
let
foundry-vtt = pkgs.callPackage ../pkgs/foundry-vtt {};
cids = import ../modules/staticids.nix;
hostConfig = config;
url = "https://foundry-vtt.cloonar.com"; # URL to check
targetService = "container@foundry-vtt.service"; # systemd unit to restart (e.g. "docker-container@myapp.service")
threshold = 3; # consecutive failures before restart
interval = "1min"; # how often to run
timeoutSeconds = 10; # curl timeout
checkUrlScript = pkgs.writeShellScript "check-foundry-up" ''
#!/usr/bin/env bash
set -euo pipefail
URL="$1"
TARGET="$2"
THRESHOLD="$3"
TIMEOUT="$4"
STATE_DIR="/run/url-watchdog"
mkdir -p "$STATE_DIR"
SAFE_TARGET="$(systemd-escape --path "$TARGET")"
STATE_FILE="$STATE_DIR/$SAFE_TARGET.count"
TMP="$(mktemp)"
# Get HTTP status; "000" if curl fails.
status="$(curl -sS -m "$TIMEOUT" -o "$TMP" -w "%{http_code}" "$URL" || echo "000")"
fail=0
if [[ "$status" == "502" || "$status" == "504" || "$status" == "000" ]]; then
fail=1
fi
count=0
if [[ -f "$STATE_FILE" ]]; then
count="$(cat "$STATE_FILE" 2>/dev/null || echo 0)"
fi
if [[ "$fail" -eq 1 ]]; then
count=$((count+1))
else
count=0
fi
if [[ "$count" -ge "$THRESHOLD" ]]; then
printf '[%s] %s failing (%s) %sx -> restarting %s\n' "$(date -Is)" "$URL" "$status" "$count" "$TARGET"
systemctl restart "$TARGET"
count=0
fi
echo "$count" > "$STATE_FILE"
rm -f "$TMP"
'';
in {
users.users.foundry-vtt = {
isSystemUser = true;
uid = cids.uids.foundry-vtt;
home = "/var/lib/foundry-vtt";
group = "foundry-vtt";
createHome = true;
};
users.groups.foundry-vtt = {
gid = cids.gids.foundry-vtt;
};
containers.foundry-vtt = {
autoStart = true;
ephemeral = true;
privateNetwork = true;
hostBridge = "server";
hostAddress = "${hostConfig.networkPrefix}.97.1";
localAddress = "${hostConfig.networkPrefix}.97.21/24";
bindMounts = {
"/var/lib/foundry-vtt" = {
hostPath = "/var/lib/foundry-vtt";
isReadOnly = false;
};
};
config = { lib, config, pkgs, ... }: {
networking = {
hostName = "foundry-vtt";
useHostResolvConf = false;
defaultGateway = {
address = "${hostConfig.networkPrefix}.96.1";
interface = "eth0";
};
firewall.enable = false;
nameservers = [ "${hostConfig.networkPrefix}.97.1" ];
};
systemd.services.foundry-vtt = {
description = "Foundry VTT Server";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
environment = {
NODE_ENV = "production";
};
serviceConfig = {
ExecStart = "${pkgs.nodejs}/bin/node ${foundry-vtt}/share/foundry-vtt/main.js --dataPath=${config.users.users.foundry-vtt.home}";
Restart = "always";
User = "foundry-vtt";
WorkingDirectory = "${config.users.users.foundry-vtt.home}";
};
};
users.users.foundry-vtt = {
isSystemUser = true;
uid = cids.uids.foundry-vtt;
home = "/var/lib/foundry-vtt";
group = "foundry-vtt";
};
users.groups.foundry-vtt = {
gid = cids.gids.foundry-vtt;
};
system.stateVersion = "24.05";
};
};
systemd.services."restart-foundry-vtt" = {
description = "Restart foundry-vtt container";
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.systemd}/bin/systemctl restart container@foundry-vtt.service";
};
};
systemd.timers."restart-foundry-vtt" = {
wantedBy = [ "timers.target" ];
timerConfig = {
# 03:00 local time (Europe/Vienna for you)
OnCalendar = "03:00";
# If the machine was off at 03:00, run once at next boot
Persistent = true;
Unit = "restart-foundry-vtt.service";
};
};
systemd.services.foundry-vtt-watchdog = {
description = "Foundry VTT watchdog: restart ${targetService} on Nginx gateway errors";
serviceConfig = {
Type = "oneshot";
ExecStart = "${checkUrlScript} ${url} ${targetService} ${toString threshold} ${toString timeoutSeconds}";
};
# Ensure needed tools are on PATH inside the unit
path = [ pkgs.curl pkgs.coreutils pkgs.systemd ];
# Wait until networking is really up
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
};
systemd.timers.foundry-vtt-watchdog = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = interval;
OnUnitActiveSec = interval;
AccuracySec = "10s";
};
};
}

View File

@@ -0,0 +1,30 @@
{ config, pkgs, ... }:
let
configure_prom = builtins.toFile "prometheus.yml" ''
scrape_configs:
- job_name: 'server'
stream_parse: true
static_configs:
- targets:
- ${config.networking.hostName}:9100
'';
in {
sops.secrets.victoria-agent-env = {
sopsFile = ../utils/modules/victoriametrics/secrets.yaml;
};
services.prometheus.exporters.node.enable = true;
systemd.services.export-fw-to-prometheus = {
path = with pkgs; [victoriametrics];
enable = true;
after = ["network-online.target"];
wants = ["network-online.target"];
wantedBy = ["multi-user.target"];
script = "vmagent -promscrape.config=${configure_prom} -envflag.enable -remoteWrite.url=https://victoria-server.cloonar.com/api/v1/write";
serviceConfig = {
EnvironmentFile=config.sops.secrets.victoria-agent-env.path;
};
};
}

View File

@@ -0,0 +1,44 @@
# Gitea Runner Docker Image
This directory contains the Dockerfile for the custom Gitea Actions runner image that includes additional dependencies needed for CI workflows.
## Included Tools
- **Base**: `shivammathur/node:latest` (includes Node.js and common development tools)
- **Chrome dependencies**: Full Puppeteer/Chromium dependencies for headless browser testing
- **webp**: WebP image format tools (`cwebp`, `dwebp`)
- **libavif-bin**: AVIF image format tools (`avifenc`, `avifdec`)
## Building the Image
```bash
cd hosts/fw/modules
docker build -f gitea-runner.Dockerfile -t git.cloonar.com/infrastructure/gitea-runner:latest .
```
## Pushing to Registry
First, authenticate with your Gitea container registry:
```bash
docker login git.cloonar.com
```
Then push the image:
```bash
docker push git.cloonar.com/infrastructure/gitea-runner:latest
```
## Using the Image
The image is already configured in `gitea-vm.nix` and will be used automatically by the Gitea Actions runners for jobs labeled with `ubuntu-latest`.
## Updating the Image
When you need to add new dependencies:
1. Edit `gitea-runner.Dockerfile`
2. Rebuild the image with the commands above
3. Push to the registry
4. Restart the runner VMs: `systemctl restart microvm@git-runner-1.service microvm@git-runner-2.service`

View File

@@ -0,0 +1,54 @@
FROM shivammathur/node:latest
# Install Chrome dependencies for Puppeteer
RUN apt-get update && apt-get install -y \
ca-certificates \
fonts-liberation \
libappindicator3-1 \
libasound2t64 \
libatk-bridge2.0-0 \
libatk1.0-0 \
libc6 \
libcairo2 \
libcups2 \
libdbus-1-3 \
libexpat1 \
libfontconfig1 \
libgbm1 \
libgcc-s1 \
libglib2.0-0 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libstdc++6 \
libx11-6 \
libx11-xcb1 \
libxcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxext6 \
libxfixes3 \
libxi6 \
libxrandr2 \
libxrender1 \
libxss1 \
libxtst6 \
lsb-release \
wget \
xdg-utils \
webp \
libavif-bin \
chromium \
&& rm -rf /var/lib/apt/lists/*
RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - && \
echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list && \
apt-get update && \
apt-get install -y google-chrome-stable && \
rm -rf /var/lib/apt/lists/*
# Verify installations
RUN cwebp -version && avifenc --version

View File

@@ -0,0 +1,251 @@
{ config, lib, nixpkgs, pkgs, ... }: let
# hostname = "git-02";
# json = pkgs.formats.json { };
runners = ["git-runner-1" "git-runner-2"];
indexedRunners = lib.lists.imap1 (i: v: { name=v; value=i; }) runners;
in {
microvm.vms = lib.mapAttrs (runner: idx: {
config = {
microvm = {
mem = 4048;
shares = [
{
source = "/nix/store";
mountPoint = "/nix/.ro-store";
tag = "ro-store";
proto = "virtiofs";
}
{
source = "/run/secrets";
mountPoint = "/run/secrets";
tag = "ro-token";
proto = "virtiofs";
}
];
volumes = [
{
image = "rootfs.img";
mountPoint = "/";
size = 51200;
}
];
interfaces = [
{
type = "tap";
id = "vm-${runner}";
mac = "02:00:00:00:00:0${toString idx}";
}
];
};
systemd.network.networks."10-lan" = {
matchConfig.PermanentMACAddress = "02:00:00:00:00:0${toString idx}";
address = [ "${config.networkPrefix}.97.5${toString idx}/24" ];
gateway = [ "${config.networkPrefix}.97.1" ];
dns = [ "${config.networkPrefix}.97.1" ];
};
networking.hostName = runner;
virtualisation.podman.enable = true;
services.gitea-actions-runner.instances.${runner} = {
enable = true;
url = "https://git.cloonar.com";
name = runner;
tokenFile = "/run/secrets/gitea-runner-token";
labels = [
# "ubuntu-latest:docker://shivammathur/node:latest"
"ubuntu-latest:docker://git.cloonar.com/infrastructure/gitea-runner:1.0.0"
];
settings = {
container = {
network = "podman";
};
cache = {
enabled = true;
host = "${config.networkPrefix}.97.5${toString idx}"; # LAN IP of the machine running act_runner
port = 8088; # any free TCP port
};
};
};
services.openssh.enable = true;
users.users.root.openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7"
];
networking.firewall = {
enable = true; # default, but being explicit is fine
allowedTCPPorts = [ 8088 ];
};
system.stateVersion = "22.05";
};
}) (lib.listToAttrs (lib.lists.imap1 (i: v: { name=v; value=i; }) runners));
# microvm.vms = {
# gitea = {
# config = {
# microvm = {
# hypervisor = "cloud-hypervisor";
# shares = [
# {
# source = "/nix/store";
# mountPoint = "/nix/.ro-store";
# tag = "ro-store";
# proto = "virtiofs";
# }
# {
# source = "/var/lib/acme/git.cloonar.com";
# mountPoint = "/var/lib/acme/${hostname}.cloonar.com";
# tag = "ro-cert";
# proto = "virtiofs";
# }
# ];
# interfaces = [
# {
# type = "tap";
# id = "vm-${hostname}";
# mac = "02:00:00:00:00:01";
# }
# ];
# };
#
# imports = [
# ../fleet.nix
# ];
#
# environment.systemPackages = with pkgs; [
# vim # my preferred editor
# ];
#
# networking = {
# hostName = hostname;
# firewall = {
# enable = true;
# allowedTCPPorts = [ 22 80 443 ];
# };
# };
#
# services.nginx.enable = true;
# services.nginx.virtualHosts."${hostname}.cloonar.com" = {
# sslCertificate = "/var/lib/acme/${hostname}.cloonar.com/fullchain.pem";
# sslCertificateKey = "/var/lib/acme/${hostname}.cloonar.com/key.pem";
# sslTrustedCertificate = "/var/lib/acme/${hostname}.cloonar.com/chain.pem";
# forceSSL = true;
# locations."/" = {
# proxyPass = "http://localhost:3001/";
# };
# };
#
# services.gitea = {
# enable = true;
# appName = "Cloonar Gitea server"; # Give the site a name
# settings = {
# server = {
# ROOT_URL = "https://${hostname}.cloonar.com/";
# HTTP_PORT = 3001;
# DOMAIN = "${hostname}.cloonar.com";
# };
# openid = {
# ENABLE_OPENID_SIGNIN = true;
# ENABLE_OPENID_SIGNUP = true;
# WHITELISTED_URIS = "auth.cloonar.com";
# };
# service = {
# DISABLE_REGISTRATION = true;
# ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
# SHOW_REGISTRATION_BUTTON = false;
# };
# actions.ENABLED=true;
# };
# };
#
# services.openssh.enable = true;
# users.users.root.openssh.authorizedKeys.keys = [
# "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7"
# "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRQuPqH5fdX3KEw7DXzWEdO3AlUn1oSmtJtHB71ICoH Generated By Termius"
# ];
#
# system.stateVersion = "22.05";
# };
# };
#
# gitea-runner-1 = {
# config = {
# microvm = {
# mem = 4048;
# shares = [
# {
# source = "/nix/store";
# mountPoint = "/nix/.ro-store";
# tag = "ro-store";
# proto = "virtiofs";
# }
# {
# source = "/run/secrets";
# mountPoint = "/run/secrets";
# tag = "ro-token";
# proto = "virtiofs";
# }
# ];
# volumes = [
# {
# image = "rootfs.img";
# mountPoint = "/";
# size = 102400;
# }
# ];
# interfaces = [
# {
# type = "tap";
# id = "vm-gitea-runner-1";
# mac = "02:00:00:00:00:02";
# }
# ];
# };
#
# environment.systemPackages = with pkgs; [
# vim # my preferred editor
# ];
#
# networking.hostName = "gitea-runner";
#
# virtualisation.podman.enable = true;
#
# services.gitea-actions-runner.instances.vm = {
# enable = true;
# url = "https://git.cloonar.com";
# name = "vm";
# tokenFile = "/run/secrets/gitea-runner-token";
# labels = [
# "ubuntu-latest:docker://shivammathur/node:latest"
# ];
# settings = {
# container = {
# network = "podman";
# };
# };
# };
#
# services.openssh.enable = true;
# users.users.root.openssh.authorizedKeys.keys = [
# "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7"
# "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRQuPqH5fdX3KEw7DXzWEdO3AlUn1oSmtJtHB71ICoH Generated By Termius"
# ];
#
# system.stateVersion = "22.05";
# };
# };
# };
sops.secrets.gitea-runner-token = {};
environment = {
systemPackages = [
pkgs.qemu
pkgs.quickemu
];
};
}

142
hosts/fw/modules/gitea.nix Normal file
View File

@@ -0,0 +1,142 @@
{ config, pkgs, ... }:
let
cids = import ../modules/staticids.nix;
domain = "git.cloonar.com";
networkPrefix = config.networkPrefix;
user = {
isSystemUser = true;
uid = cids.uids.gitea;
group = "gitea";
home = "/var/lib/gitea";
createHome = true;
};
group = {
gid = cids.gids.gitea;
};
in
{
users.users.gitea = user;
users.groups.gitea = group;
security.acme.certs."${domain}" = {
group = "nginx";
};
containers.git = {
autoStart = true;
ephemeral = false; # because of ssh key
privateNetwork = true;
hostBridge = "server";
hostAddress = "${networkPrefix}.97.1";
localAddress = "${networkPrefix}.97.50/24";
bindMounts = {
"/var/lib/gitea" = {
hostPath = "/var/lib/gitea/";
isReadOnly = false;
};
"/var/lib/acme/gitea/" = {
hostPath = config.security.acme.certs.${domain}.directory;
isReadOnly = true;
};
"/run/secrets/gitea-mailer-password" = {
hostPath = config.sops.secrets.gitea-mailer-password.path;
};
};
config = { lib, config, pkgs, ... }: {
imports = [
../fleet.nix
../modules/cloonar-assistant-config-server.nix
];
environment.systemPackages = with pkgs; [
vim # my preferred editor
];
networking = {
hostName = "git";
useHostResolvConf = false;
defaultGateway = {
address = "${networkPrefix}.96.1";
interface = "eth0";
};
firewall.enable = false;
nameservers = [ "${networkPrefix}.97.1" ];
};
services.nginx.enable = true;
services.nginx.virtualHosts."${domain}" = {
sslCertificate = "/var/lib/acme/gitea/fullchain.pem";
sslCertificateKey = "/var/lib/acme/gitea/key.pem";
sslTrustedCertificate = "/var/lib/acme/gitea/chain.pem";
forceSSL = true;
extraConfig = ''
client_max_body_size 2048M;
'';
locations."/" = {
proxyPass = "http://localhost:3001/";
};
};
services.gitea = {
enable = true;
appName = "Cloonar Gitea server"; # Give the site a name
mailerPasswordFile = "/run/secrets/gitea-mailer-password";
settings = {
server = {
ROOT_URL = "https://${domain}/";
HTTP_PORT = 3001;
DOMAIN = domain;
};
repository = {
DEFAULT_BRANCH = "main";
};
openid = {
ENABLE_OPENID_SIGNIN = false;
ENABLE_OPENID_SIGNUP = true;
WHITELISTED_URIS = "auth.cloonar.com";
};
service = {
DISABLE_REGISTRATION = false;
ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
SHOW_REGISTRATION_BUTTON = false;
ENABLE_NOTIFY_MAIL = true;
REQUIRE_SIGNIN_VIEW = false;
};
mailer = {
ENABLED = true;
FROM = "Gitea Cloonar <gitea@cloonar.com>";
PROTOCOL = "smtp+starttls";
SMTP_ADDR = "mail.cloonar.com";
SMTP_PORT = 587;
USER = "gitea@cloonar.com";
};
actions.ENABLED=true;
attachment = {
MAX_SIZE = 2048; # 2GB in MB for general attachments
};
packages = {
ENABLED = true;
};
};
};
services.openssh.enable = true;
users.users.root.openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRQuPqH5fdX3KEw7DXzWEdO3AlUn1oSmtJtHB71ICoH Generated By Termius"
];
users.users.gitea = user;
users.groups.gitea = group;
system.stateVersion = "23.05";
};
};
sops.secrets.gitea-runner = {};
sops.secrets.gitea-mailer-password = {
owner = "gitea";
restartUnits = [ "container@git.service" ];
};
}

View File

@@ -0,0 +1,193 @@
{ config, pkgs, lib, ... }:
let
grafanaMonitorUser = "grafana-monitor";
grafanaMonitorGroup = "grafana-monitor";
stateDir = "/var/lib/${grafanaMonitorUser}";
# Monitoring script will be defined here later
monitorScript = pkgs.writeShellScriptBin "grafana-online-check" ''
#!${pkgs.bash}/bin/bash
set -euo pipefail
GRAFANA_URL="https://grafana.cloonar.com/api/health"
STATE_FILE="${stateDir}/status.env"
PUSHOVER_API_TOKEN_FILE="/run/secrets/pushover-api-token"
PUSHOVER_USER_KEY_FILE="/run/secrets/pushover-user-key"
MAX_FAILURES=5
# Ensure state directory exists (NixOS creates $HOME for the user, which is stateDir)
# The script runs as grafanaMonitorUser, so $HOME will be /var/lib/grafana-monitor
mkdir -p "''${HOME}"
# Load current state or initialize
CONSECUTIVE_FAILURES=0
ALERT_SENT="false"
LAST_KNOWN_STATUS="UP" # Assume UP initially if no state file
# Note: STATE_FILE uses $stateDir which is /var/lib/grafana-monitor.
# The script will run with HOME=/var/lib/grafana-monitor.
# So, using ''${HOME}/status.env or ''${STATE_FILE} should resolve to the same path.
# Let's stick to ''${STATE_FILE} for consistency with its definition.
if [[ -f "''${STATE_FILE}" ]]; then
source "''${STATE_FILE}"
fi
# Check secrets
if [[ ! -f "''${PUSHOVER_API_TOKEN_FILE}" ]] || [[ ! -r "''${PUSHOVER_API_TOKEN_FILE}" ]]; then
echo "Error: Pushover API token file (''${PUSHOVER_API_TOKEN_FILE}) not found or not readable." >&2
exit 1
fi
PUSHOVER_API_TOKEN=$(cat "''${PUSHOVER_API_TOKEN_FILE}")
if [[ ! -f "''${PUSHOVER_USER_KEY_FILE}" ]] || [[ ! -r "''${PUSHOVER_USER_KEY_FILE}" ]]; then
echo "Error: Pushover user key file (''${PUSHOVER_USER_KEY_FILE}) not found or not readable." >&2
exit 1
fi
PUSHOVER_USER_KEY=$(cat "''${PUSHOVER_USER_KEY_FILE}")
# Internet connectivity check
INTERNET_CHECK_URL="https://1.1.1.1" # Using a reliable IP to bypass potential DNS issues for the check itself
echo "Performing internet connectivity check to ''${INTERNET_CHECK_URL}..."
if ! ${pkgs.curl}/bin/curl --head --silent --fail --connect-timeout 3 --max-time 5 "''${INTERNET_CHECK_URL}" > /dev/null 2>&1; then
echo "Internet connectivity check failed. Cannot reach ''${INTERNET_CHECK_URL}. Skipping Grafana check and exiting successfully."
exit 0
else
echo "Internet connectivity check successful. Proceeding with Grafana check."
fi
echo "" # Add a blank line for readability before Grafana check logs
echo "Checking Grafana at ''${GRAFANA_URL}..."
ACTUAL_HTTP_CODE="000" # Default if curl doesn't provide one
CURL_ERROR_MESSAGE=""
CURL_STDERR_OUTPUT=$(mktemp)
# Ensure temp file is cleaned up on exit, error, or interrupt
trap 'rm -f "''${CURL_STDERR_OUTPUT}"' EXIT TERM INT HUP
# -L: follow redirects
# -sS: silent mode, but show errors
# --fail: curl exits with 22 on server errors (4xx, 5xx)
# --connect-timeout 5: max time to connect
# --max-time 10: max total time for operation
# --stderr: redirect stderr to a file to capture detailed errors
# -o /dev/null: discard response body
# --write-out "%{http_code}": output the HTTP status code
if ACTUAL_HTTP_CODE=$(${pkgs.curl}/bin/curl -L -sS --fail --connect-timeout 5 --max-time 10 \
--stderr "''${CURL_STDERR_OUTPUT}" \
-o /dev/null --write-out "%{http_code}" "''${GRAFANA_URL}"); then
# Curl exited with 0. With --fail, this means HTTP status was 2xx.
echo "Grafana is UP (HTTP ''${ACTUAL_HTTP_CODE})."
CURRENT_STATUS="UP"
if [[ "''${LAST_KNOWN_STATUS}" == "DOWN" && "''${ALERT_SENT}" == "true" ]]; then
echo "Grafana recovered. Sending recovery notification."
${pkgs.curl}/bin/curl -sS -X POST \
-F "token=''${PUSHOVER_API_TOKEN}" \
-F "user=''${PUSHOVER_USER_KEY}" \
-F "message=Grafana at ''${GRAFANA_URL} is back online (HTTP ''${ACTUAL_HTTP_CODE})." \
-F "title=Grafana Recovered (fw)" \
-F "priority=0" \
https://api.pushover.net/1/messages.json
ALERT_SENT="false"
fi
CONSECUTIVE_FAILURES=0
else
# Curl exited with a non-zero status.
CURL_EXIT_CODE=$?
CURL_ERROR_MESSAGE=$(cat "''${CURL_STDERR_OUTPUT}" | tr -d '\n' | sed 's/"/\\"/g') # Read, remove newlines, escape quotes for JSON
echo "Grafana check failed. Curl Exit Code: ''${CURL_EXIT_CODE}. HTTP Code reported: ''${ACTUAL_HTTP_CODE}."
echo "Curl Stderr: ''${CURL_ERROR_MESSAGE}"
CURRENT_STATUS="DOWN"
CONSECUTIVE_FAILURES=$(( ''${CONSECUTIVE_FAILURES} + 1 ))
echo "Consecutive failures: ''${CONSECUTIVE_FAILURES}"
if [[ ''${CONSECUTIVE_FAILURES} -ge ''${MAX_FAILURES} && "''${ALERT_SENT}" == "false" ]]; then
echo "Grafana has been offline for ''${CONSECUTIVE_FAILURES} checks (>= ''${MAX_FAILURES}). Sending alert."
PUSHOVER_TITLE="Grafana OFFLINE (fw)"
PUSHOVER_MSG="Grafana ''${GRAFANA_URL} offline for ''${MAX_FAILURES}+ min. HTTP:''${ACTUAL_HTTP_CODE}, CurlExit:''${CURL_EXIT_CODE}."
if [[ -n "''${CURL_ERROR_MESSAGE}" ]]; then
PUSHOVER_MSG+=" Err: ''${CURL_ERROR_MESSAGE}"
fi
# Truncate message if too long for Pushover (1024 chars)
PUSHOVER_MSG=$(echo "''${PUSHOVER_MSG}" | cut -c 1-1024)
${pkgs.curl}/bin/curl -sS -X POST \
-F "token=''${PUSHOVER_API_TOKEN}" \
-F "user=''${PUSHOVER_USER_KEY}" \
-F "message=''${PUSHOVER_MSG}" \
-F "title=''${PUSHOVER_TITLE}" \
-F "priority=1" \
https://api.pushover.net/1/messages.json
ALERT_SENT="true"
fi
fi
# Temp file is removed by trap
# Save current state
echo "Saving state: CONSECUTIVE_FAILURES=''${CONSECUTIVE_FAILURES}, ALERT_SENT=''${ALERT_SENT}, LAST_KNOWN_STATUS=''${CURRENT_STATUS}"
(
echo "CONSECUTIVE_FAILURES=''${CONSECUTIVE_FAILURES}"
echo "ALERT_SENT=''${ALERT_SENT}"
echo "LAST_KNOWN_STATUS=''${CURRENT_STATUS}"
) > "''${STATE_FILE}" # Using STATE_FILE which is ${stateDir}/status.env
chmod 600 "''${STATE_FILE}"
echo "Grafana check finished."
'';
in
{
# Module is now implicitly enabled when imported
config = {
users.users.${grafanaMonitorUser} = {
isSystemUser = true;
group = grafanaMonitorGroup;
home = stateDir; # Home directory for state
createHome = true; # NixOS will create this directory
description = "User for Grafana online monitoring service";
};
users.groups.${grafanaMonitorGroup} = {};
# Sops secrets for Pushover
sops.secrets."pushover-api-token" = {
owner = grafanaMonitorUser;
group = grafanaMonitorGroup;
mode = "0400"; # Read-only for the user
};
sops.secrets."pushover-user-key" = {
owner = grafanaMonitorUser;
group = grafanaMonitorGroup;
mode = "0400"; # Read-only for the user
};
environment.systemPackages = [
pkgs.curl
pkgs.coreutils # for mkdir, cat, echo, rm used in script (though bash builtins are often used)
];
systemd.services.grafana-online-check = {
description = "Grafana Online Check Service";
wantedBy = [ "multi-user.target" ]; # Or timers.target if only started by timer
after = [ "network-online.target" ]; # Ensure network is up and secrets are available
requires = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
User = grafanaMonitorUser;
Group = grafanaMonitorGroup;
ExecStart = "${monitorScript}/bin/grafana-online-check";
# Permissions to write to its own home directory (stateDir) are implicit
# If using StateDirectory= in systemd, it would be different.
# For home directory usage, ensure the user has rights. `createHome = true` helps.
};
};
systemd.timers.grafana-online-check = {
description = "Timer to periodically check Grafana's online status";
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "2min"; # Wait a bit after boot
OnUnitActiveSec = "1min"; # Run every 1 minute after the last run
Unit = "grafana-online-check.service";
};
};
};
}

View File

@@ -0,0 +1,6 @@
{ config, pkgs, ... }:
{
imports = [
./ghetto.nix
];
}

View File

@@ -0,0 +1,29 @@
{
lib,
pkgs,
...
}: let
create_users = host: {
users.users."${host.username}.ghetto.at" = {
createHome = true;
home = "/home/customers/ghetto/" + host.username;
isNormalUser = false;
isSystemUser = true;
group = "sftp_users";
openssh.authorizedKeys.keys = [
host.key
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7"
];
shell = null;
};
};
users = [
{
username = "fw";
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGzJRWe8hsqAVnGSjPrcheloteWMzORoQ5Gj4IfhCROF";
}
];
in {
imports = builtins.map create_users users;
}

View File

@@ -0,0 +1,60 @@
{ config, ... }: {
services.home-assistant.config = {
sensor = [
{
platform = "rest";
name = "creality extruder";
resource = "http://k1c-63e9.cloonar.smart:7125/printer/objects/query?extruder";
value_template = "OK";
json_attributes_path = "$.result.status.extruder";
json_attributes = [
"pressure_advance"
"power"
"target"
"temperature"
];
}
{
platform = "rest";
name = "creality print stats";
resource = "http://k1c-63e9.cloonar.smart:7125/printer/objects/query?print_stats";
value_template = "OK";
json_attributes_path = "$.result.status.print_stats";
json_attributes = [
"filename"
"total_duration"
"print_duration"
"filament_used"
"state"
"message"
];
}
{
platform = "template";
sensors = {
crality_hotend_actual = {
friendly_name = "Hot End Actual";
value_template = "{{ state_attr('sensor.creality_extruder', 'temperature') | float | round(1) }}";
device_class = "temperature";
unit_of_measurement = "°C";
};
};
}
];
"automation 3d printer state" = {
alias = "3d printer state change";
trigger = [
{
platform = "template";
value_template = "{{ state_attr('sensor.creality_print_stats','state') == 'standby' }}";
}
];
action = {
service = "notify.mobile_app_dominiks_iphone";
data = {
message = "Printer status changed to {{ state_attr('sensor.creality_print_stats','state') }}";
};
};
};
};
}

View File

@@ -1,29 +1,49 @@
{ pkgs, ... }:
{
services.home-assistant.extraComponents = [
"daikin"
"enocean"
];
# services.home-assistant.customComponents = [
# (pkgs.callPackage ./custom-components/scheduler.nix { })
# ];
services.home-assistant.customLovelaceModules = [
(pkgs.callPackage ./custom-components/lovelace-scheduler.nix { })
];
services.home-assistant.config = {
sensor = [
{
name = "Living Room Window Handle";
name = "Living Room Window Handle 2";
platform = "enocean";
id = [ 129 0 227 53 ];
device_class = "windowhandle";
}
{
name = "Living Room Window Handle 1";
platform = "enocean";
id = [ 129 0 229 8 ];
device_class = "windowhandle";
}
];
"automation ac_livingroom" = {
alias = "ac_livingroom";
hide_entity = true;
trigger = {
platform = "state";
entity_id = "sensor.windowhandle_living_room_window_handle";
to = [ "open" "tilt" ];
};
trigger = [
{
platform = "state";
entity_id = "sensor.windowhandle_living_room_window_handle_1";
to = [ "open" "tilt" ];
}
{
platform = "state";
entity_id = "sensor.windowhandle_living_room_window_handle_2";
to = [ "open" "tilt" ];
}
];
action = {
service = "climate.set_hvac_mode";
target = {
entity_id = "climate.livingroom_ac";
entity_id = "climate.living_room";
};
data = {
hvac_mode = "off";
@@ -32,12 +52,11 @@
};
"automation ac_eco" = {
alias = "ac_eco";
hide_entity = true;
trigger = {
platform = "state";
entity_id = [
"climate.livingroom_ac"
"climate.bedroom_ac"
"climate.living_room"
"climate.bedroom"
];
to = [
"heat"
@@ -56,7 +75,6 @@
};
"automation bedroom_ac_on" = {
alias = "bedroom ac on";
hide_entity = true;
trigger = {
platform = "time";
at = "00:30:00";
@@ -69,7 +87,7 @@
{
service = "climate.set_hvac_mode";
target = {
entity_id = "climate.bedroom_ac";
entity_id = "climate.bedroom";
};
data = {
hvac_mode = "cold";
@@ -82,7 +100,6 @@
};
"automation bedroom_ac_off" = {
alias = "bedroom ac on";
hide_entity = true;
trigger = {
platform = "template";
value_template = ''
@@ -92,7 +109,7 @@
action = {
service = "climate.set_hvac_mode";
target = {
entity_id = "climate.bedroom_ac";
entity_id = "climate.bedroom";
};
data = {
hvac_mode = "off";

View File

@@ -50,28 +50,28 @@
sensor_low_battery = {
name = "Sensor has low battery!";
message = ''
{%- set domains = ['sensor', 'battery'] -%}
{%- set threshold = 30 -%}
{%- set exclude_entities = ['sensor.sensors_lowest_battery_level','sensor.dominiks_iphone_battery_level'] -%}
{% set domains = ['sensor', 'battery'] %}
{% set threshold = 30 %}
{%- set exclude_entities = ['sensor.sensors_lowest_battery_level','sensor.dominiks_iphone_battery_level','sensor.roborock_s8_pro_ultra_battery'] -%}
Sensors are below 50% battery:
{%- for domain in domains -%}
{%- for item in states[domain] -%}
{%- if item.entity_id not in exclude_entities -%}
{%- if item.attributes.battery_level is defined -%}
{%- set level = item.attributes.battery_level|int -%}
{% for domain in domains %}
{% for item in states[domain] %}
{% if item.entity_id not in exclude_entities %}
{% if item.attributes.battery_level is defined %}
{% set level = item.attributes.battery_level|int %}
{% if level > 0 and level < threshold %}
- {{ item.attributes.friendly_name }} ({{ item.attributes['battery_level']|int}}%)
{%- endif -%}
{%- endif -%}
{%- if item.attributes.device_class is defined and item.attributes.device_class == 'battery' -%}
{%- set level = item.state|int -%}
{% endif %}
{% if item.attributes.device_class is defined and item.attributes.device_class == 'battery' %}
{% set level = item.state|int %}
{% if level > 0 and level <= threshold %}
- {{ item.attributes.friendly_name }} ({{ item.state|int }}%)
{%- endif -%}
{%- endif %}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
'';
entity_id = "binary_sensor.sensor_low_battery";
state = "on";

View File

@@ -0,0 +1,18 @@
{ stdenv, fetchFromGitHub }:
stdenv.mkDerivation rec {
pname = "ha-bermuda";
version = "0.7.2"; # Replace with the latest version
src = fetchFromGitHub {
owner = "agittins";
repo = "bermuda";
rev = "v${version}";
sha256 = "sha256-FBmZc2I9JoLAQ55yasa0i+SM0dMg2IbR3AaKgEybRu8="; # Replace with the correct SHA256 hash
};
installPhase = ''
mkdir -p $out
cp -r custom_components/bermuda $out/
'';
}

View File

@@ -0,0 +1,27 @@
{ lib
, buildHomeAssistantComponent
, fetchFromGitHub
}:
buildHomeAssistantComponent rec {
owner = "hacs";
domain = "hacs";
version = "2.0.1"; # Replace with the latest version
src = fetchFromGitHub {
owner = "hacs";
repo = "integration";
rev = version;
sha256 = ""; # You'll need to fill this in
};
propagatedBuildInputs = [
# Add any required dependencies here
];
meta = with lib; {
homepage = "https://github.com/hacs/integration";
license = licenses.mit;
description = "HACS (Home Assistant Community Store)";
};
}

View File

@@ -0,0 +1,36 @@
{ lib
, buildNpmPackage
, fetchFromGitHub
}:
buildNpmPackage rec {
pname = "lovelace-scheduler";
version = "3.2.13";
src = fetchFromGitHub {
owner = "nielsfaber";
repo = "scheduler-card";
rev = "v${version}";
hash = "sha256-LFKOTu0SBeHpf8Hjvsgc/xOUux9d4lBCshdD9u7eO5o=";
};
npmDepsHash = "sha256-JJexFmVbDHi2JCiCpcDupzVf0xfwy+vqWILq/dLVcBo=";
installPhase = ''
runHook preInstall
mkdir $out
cp card-mod.js $out
runHook postInstall
'';
passthru.entrypoint = "card-mod.js";
meta = with lib; {
description = "This is a Lovelace card for Home Assistant that can be used to create a time schedule for your smart devices. You can create new rules, modify existing rules and temporarily disable rules.";
homepage = "https://github.com/nielsfaber/scheduler-card";
license = licenses.mit;
platforms = platforms.all;
};
}

View File

@@ -0,0 +1,30 @@
{
buildHomeAssistantComponent,
fetchFromGitHub,
lib,
gitUpdater,
}:
buildHomeAssistantComponent rec {
owner = "nielsfaber";
domain = "scheduler";
version = "3.3.7";
src = fetchFromGitHub {
owner = "nielsfaber";
repo = "scheduler-component";
rev = "refs/tags/${version}";
hash = "sha256-zXO2UDLhSTOemzsO9G5ZUzr50Zg8kDW/aObn6Y3j70k=";
};
passthru.updateScript = gitUpdater {
ignoredVersions = "(Alpha|Beta|alpha|beta).*";
};
meta = {
changelog = "https://github.com/nielsfaber/scheduler-component/releases/tag/${version}";
description = "This is a custom component for Home Assistant, that is used for controlling your existing devices based on time. It works nicely together with the Lovelace scheduler card.";
homepage = "https://github.com/nielsfaber/scheduler-component";
license = lib.licenses.agpl3Only;
};
}

View File

@@ -0,0 +1,292 @@
{ config, pkgs, ... }:
let
domain = "home-assistant.cloonar.com";
pkgs-with-home-assistant = import (builtins.fetchGit {
name = "new-home-assistant";
url = "https://github.com/nixos/nixpkgs/";
rev = "18dd725c29603f582cf1900e0d25f9f1063dbf11";
}) {};
networkPrefix = config.networkPrefix;
in
{
users.users.hass = {
home = "/var/lib/hass";
createHome = true;
group = "hass";
uid = config.ids.uids.hass;
extraGroups = [ "dialout" ];
};
users.groups.hass.gid = config.ids.gids.hass;
security.acme.certs."${domain}" = {
group = "nginx";
};
sops.secrets."home-assistant-secrets.yaml" = {
owner = "hass";
restartUnits = [ "container@hass.service" ];
};
sops.secrets."home-assistant-ldap" = {
owner = "hass";
};
containers.hass = {
autoStart = true;
ephemeral = false;
privateNetwork = true;
hostBridge = "server";
hostAddress = "${networkPrefix}.97.1";
localAddress = "${networkPrefix}.97.20/24";
extraFlags = [
"--capability=CAP_NET_ADMIN"
"--capability=CAP_MKNOD"
];
allowedDevices = [
{
modifier = "rwm";
node = "char-usb_device";
}
{
modifier = "rwm";
node = "char-ttyUSB";
}
];
bindMounts = {
"/dev/ttyUSB0" = {
hostPath = "/dev/ttyUSB0";
isReadOnly = false;
};
"/etc/localtime" = {
hostPath = "/etc/localtime";
};
"/var/lib/hass" = {
hostPath = "/var/lib/hass/";
isReadOnly = false;
};
"/var/lib/acme/hass/" = {
hostPath = "${config.security.acme.certs.${domain}.directory}";
};
"/run/secrets/home-assistant-ldap" = {
hostPath = config.sops.secrets."home-assistant-ldap".path;
};
"/var/lib/hass/secrets.yaml" = {
hostPath = config.sops.secrets."home-assistant-secrets.yaml".path;
};
};
config = { lib, config, pkgs, ... }: {
networkPrefix = networkPrefix;
imports = [
../network-prefix.nix
./3dprinter.nix
./ac.nix
# ./aeg.nix
./battery.nix
./electricity.nix
./enocean.nix
./ldap.nix
./light.nix
./locks.nix
./multimedia.nix
./music.nix
./notify.nix
./pc.nix
./power-saving.nix
./pushover.nix
./presense.nix
./remote.nix
./roborock.nix
./scenes
./scene-switch.nix
./shelly.nix
./sleep.nix
./snapcast.nix
];
networking = {
hostName = "home-assistant";
useHostResolvConf = false;
defaultGateway = {
address = "${networkPrefix}.96.1";
interface = "eth0";
};
firewall.enable = false;
nameservers = [ "${networkPrefix}.97.1" ];
};
environment.systemPackages = [
pkgs.wol
pkgs.mariadb
];
services.nginx.enable = true;
services.nginx.virtualHosts."${domain}" = {
sslCertificate = "/var/lib/acme/hass/fullchain.pem";
sslCertificateKey = "/var/lib/acme/hass/key.pem";
sslTrustedCertificate = "/var/lib/acme/hass/chain.pem";
forceSSL = true;
extraConfig = ''
proxy_buffering off;
'';
locations."/".extraConfig = ''
proxy_pass http://127.0.0.1:8123;
proxy_set_header Host $host;
proxy_redirect http:// https://;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
'';
};
services.home-assistant = {
package = pkgs-with-home-assistant.home-assistant;
enable = true;
};
services.home-assistant.extraComponents = [
"mobile_app"
"backup"
"denonavr"
"androidtv"
"rainbird"
"zha"
"tplink_omada"
];
systemd.services.install-hacs = {
description = "Install HACS";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
};
script = ''
set -e
HACS_VERSION="2.0.5" # Replace with the latest version
HACS_DIR="/var/lib/hass/custom_components/hacs"
mkdir -p "$HACS_DIR"
${pkgs.curl}/bin/curl -L "https://github.com/hacs/integration/releases/download/$HACS_VERSION/hacs.zip" -o /tmp/hacs.zip
${pkgs.unzip}/bin/unzip -o /tmp/hacs.zip -d "$HACS_DIR"
rm /tmp/hacs.zip
chown -R hass:hass "$HACS_DIR"
'';
};
services.home-assistant.extraPackages = ps: with ps; [
mysqlclient
];
services.mysql = {
enable = true;
package = pkgs.mariadb;
ensureDatabases = [ "hass" ];
ensureUsers = [
{
name = "hass";
ensurePermissions = {
"hass.*" = "ALL PRIVILEGES";
};
}
];
};
services.mysqlBackup = {
enable = true;
databases = [ "hass" ];
};
services.home-assistant.config =
let
hiddenEntities = [
"sensor.last_boot"
"sensor.date"
];
in
{
recorder = {
db_url = "mysql://hass@localhost/hass?unix_socket=/var/run/mysqld/mysqld.sock";
};
homeassistant = {
name = "Home";
latitude = "!secret home_latitude";
longitude = "!secret home_longitude";
elevation = "!secret home_elevation";
unit_system = "metric";
currency = "EUR";
country = "AT";
time_zone = "Europe/Vienna";
external_url = "https://${domain}";
};
zone = {
name = "Home";
latitude = "!secret home_latitude";
longitude = "!secret home_longitude";
radius = 35;
icon = "mdi:account-multiple";
};
automation = "!include automations.yaml";
frontend = { };
http = {
use_x_forwarded_for = true;
trusted_proxies = [
"127.0.0.1"
"::1"
];
};
api = { };
history.exclude = {
entities = hiddenEntities;
domains = [
"automation"
"updater"
];
};
"map" = { };
enocean = {
device = "/dev/ttyUSB0";
};
# logbook.exclude.entities = "hiddenEntities";
logger = {
default = "info";
};
#icloud = {
# username = "!secret icloud_email";
# password = "!secret icloud_password";
# with_family = true;
#};
network = { };
zeroconf = { };
system_health = { };
default_config = { };
system_log = { };
sensor = [
{
platform = "template";
sensors.bedtime_alarm = {
friendly_name = "Bedtime Alarm";
value_template = "09:00";
};
}
];
};
services.mosquitto = {
enable = true;
listeners = [
{
acl = [ "pattern readwrite #" ];
omitPasswordAuth = true;
settings.allow_anonymous = true;
}
];
};
users.users.hass.extraGroups = [ "dialout" ];
system.stateVersion = "23.05";
};
};
}

View File

@@ -0,0 +1,28 @@
{ config, pkgs, ... }:
let
in {
services.home-assistant.customComponents = with pkgs.home-assistant-custom-components; [
epex_spot
];
services.home-assistant.config = {
sensor = [
{
platform = "template";
sensors = {
electricity_price = {
friendly_name = "Current Price of electricity";
unit_of_measurement = "EUR/kWh";
value_template = ''
{{ ((states('sensor.epex_spot_data_price') | float ) + (0.0149 + 0.074 + 0.007 + 0.0074 + 0.0006)) | float }}
'';
entity_id = [
"sensor.epex_spot_data_price"
"sensor.time"
];
};
};
}
];
};
}

View File

@@ -0,0 +1,26 @@
{
services.home-assistant.config = {
"binary_sensor pc_0" = [
{
platform = "enocean";
id = [ 254 235 105 198 ];
name = "enocean_switch_pc";
}
];
"binary_sensor bed_1" = [
{
platform = "enocean";
id = [ 254 207 162 105 ];
name = "enocean_switch_bed_1";
}
];
sensor = [
{
name = "Bathroom HT";
platform = "enocean";
id = [ 5 41 146 251 ];
device_class = "temperature";
}
];
};
}

View File

@@ -20,7 +20,7 @@ let
CLIENT="ldapsearch"
SERVER="ldaps://ldap.cloonar.com:636"
USERDN="cn=home-assistant,ou=system,ou=users,dc=cloonar,dc=com"
PW="$(<${config.sops.secrets.home-assistant-ldap.path})"
PW="$(</run/secrets/home-assistant-ldap)"
BASEDN="ou=users,dc=cloonar,dc=com"
SCOPE="one"
FILTER="(&(objectClass=cloonarUser)(memberOf=cn=HomeAssistant,ou=groups,dc=cloonar,dc=com)(mail=$(ldap_dn_escape "$username")))"
@@ -52,11 +52,5 @@ in
meta = true;
}
];
sops.secrets.home-assistant-ldap = {
sopsFile = ./secrets.yaml;
owner = "hass";
};
}

View File

@@ -0,0 +1,522 @@
{
services.home-assistant.extraComponents = [
"deconz"
"shelly"
"sun"
"nanoleaf"
];
services.home-assistant.config = {
homeassistant = {
customize_domain = {
light = {
assumed_state = false;
};
};
};
customize_domain = {
light = {
assumed_state = false;
};
};
"automation light_sunrise" = {
alias = "light_sunrise";
trigger = {
platform = "sun";
event = "sunrise";
};
action = {
service = "light.turn_on";
target = {
entity_id = "{{ states.light | selectattr(\"state\",\"eq\",\"on\") | map(attribute=\"entity_id\") | list }}";
};
data = {
brightness_pct = 254;
color_temp = 250;
};
};
};
"automation light_sunset" = {
alias = "light_sunset";
trigger = {
platform = "sun";
event = "sunset";
};
action = {
service = "light.turn_on";
target = {
entity_id = "{{ states.light | selectattr(\"state\",\"eq\",\"on\") | map(attribute=\"entity_id\") | list }}";
};
data = {
brightness_pct = 30;
color_temp = 450;
};
};
};
"automation light_on" = {
alias = "light_on";
trigger = {
platform = "state";
entity_id = [
"light.bedroom_lights"
"light.kitchen_lights"
"light.livingroom_lights"
"light.hallway_lights"
"light.bathroom_lights"
"light.toilet_lights"
"light.storage_lights"
];
to = "on";
};
action = [
{
choose = [
{
conditions = [ "{{ is_state('automation.light_sunset', 'off') }}" ];
sequence = [
{
service = "light.turn_on";
target = {
entity_id = "{{ trigger.entity_id }}";
};
data = {
brightness_pct = 100;
color_temp = 250;
};
}
];
}
{
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and trigger.entity_id == 'light.toilet_lights' }}" ];
sequence = [
{
service = "light.turn_on";
target = {
entity_id = "{{ trigger.entity_id }}";
};
data = {
brightness_pct = 20;
color_temp = 450;
};
}
];
}
{
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and trigger.entity_id == 'light.hallway_lights' }}" ];
sequence = [
{
service = "light.turn_on";
target = {
entity_id = "{{ trigger.entity_id }}";
};
data = {
brightness_pct = 30;
rgbw_color = [ 255 126 0 255 ];
};
}
];
}
{
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and trigger.entity_id == 'light.bathroom_lights' }}" ];
sequence = [
{
service = "light.turn_on";
target = {
entity_id = "{{ trigger.entity_id }}";
};
data = {
brightness_pct = 30;
rgbw_color = [ 255 126 0 255 ];
};
}
];
}
{
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and trigger.entity_id == 'light.livingroom_lights' }}" ];
sequence = [
{
service = "light.turn_on";
target = {
entity_id = "{{ trigger.entity_id }}";
};
data = {
brightness_pct = 30;
color_temp = 450;
};
}
];
}
{
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and trigger.entity_id == 'light.bedroom_lights' }}" ];
sequence = [
{
service = "light.turn_on";
target = {
entity_id = "light.bedroom_lights";
};
data = {
brightness_pct = 20;
rgbw_color = [ 255 126 0 255 ];
};
}
];
}
{
conditions = [ "{{ state_attr('sun.sun', 'elevation') < 5 and trigger.entity_id == 'light.kitchen_lights' }}" ];
sequence = [
{
service = "light.turn_on";
target = {
entity_id = "light.kitchen_lights";
};
data = {
brightness_pct = 30;
color_temp = 450;
};
}
];
}
{
conditions = [ "{{ state_attr('sun.sun', 'elevation') > 4 }}" ];
sequence = [
{
service = "light.turn_on";
target = {
entity_id = "{{ trigger.entity_id }}";
};
data = {
brightness_pct = 100;
color_temp = 250;
};
}
];
}
];
}
];
};
"automation bathroom light small" = {
alias = "bathroom light small";
mode = "restart";
trigger = {
platform = "state";
entity_id = [
"light.bathroom_switch_channel_1"
];
from = "on";
to = "off";
};
action = [
{
service = "switch.turn_off";
target = {
entity_id = "switch.bathroom_small";
};
}
];
};
"automation bathroom light" = {
alias = "bathroom light";
mode = "restart";
trigger = {
platform = "state";
entity_id = [
"light.bathroom_switch_channel_1"
];
from = "off";
to = "on";
};
action = [
{
delay = 3600;
}
{
service = "light.turn_off";
target = {
entity_id = "light.bathroom_switch_channel_1";
};
}
];
};
"automation bed_led" = {
alias = "bed_led";
mode = "restart";
trigger = {
platform = "state";
entity_id = [
"light.bedroom_led"
];
from = "off";
to = "on";
};
action = [
{
delay = 10800;
}
{
service = "light.turn_off";
target = {
entity_id = "{{ trigger.entity_id }}";
};
}
];
};
"automation hallway_motion" = {
alias = "Hallway Motion";
trigger = {
platform = "state";
entity_id = "binary_sensor.hallway_motion_motion";
};
action = {
service_template = "light.turn_{{ trigger.to_state.state }}";
target = {
entity_id = "light.hallway_lights";
};
};
};
"automation bedroom light" = {
alias = "bedroom light";
trigger = [
{
platform = "event";
event_type = "button_pressed";
event_data = {
id = [ 254 207 162 105 ];
which = 1;
onoff = 1;
pushed = 1;
};
}
{
platform = "event";
event_type = "shelly.click";
event_data = {
device = "shellybutton1-E8DB84AA136D";
click_type = "double";
};
}
];
action = [
{
service = "light.toggle";
target = {
entity_id = "light.bedroom_lights";
};
}
];
};
"automation bed light" = {
alias = "bed light";
trigger = [
{
platform = "event";
event_type = "button_pressed";
event_data = {
id = [ 254 207 162 105 ];
which = 0;
onoff = 1;
pushed = 1;
};
}
{
platform = "event";
event_type = "shelly.click";
event_data = {
device = "shellybutton1-E8DB84AA136D";
click_type = "triple";
};
}
];
action = [
{
service = "light.toggle";
target = {
entity_id = "light.bedroom_bed";
};
}
];
};
"automation reading 1 light" = {
alias = "reading 1 light";
trigger = [
{
platform = "event";
event_type = "button_pressed";
event_data = {
id = [ 254 207 162 105 ];
which = 0;
onoff = 0;
pushed = 1;
};
}
];
action = [
{
service = "light.toggle";
target = {
entity_id = "light.bed_reading_1";
};
}
];
};
"automation bed_button_2" = {
alias = "bed_button_2";
trigger = {
platform = "event";
event_type = "shelly.click";
event_data = {
device = "shellybutton1-E8DB84AA136D";
};
};
action = [
{
choose = [
{
conditions = [ "{{ trigger.event.data.click_type == \"single\" }}" ];
sequence = [
{
service = "light.toggle";
entity_id = "light.bed_reading_2";
}
];
}
];
}
];
};
light = [
{
platform = "switch";
name = "Livingroom Switch";
entity_id = "switch.livingroom_switch";
}
{
platform = "group";
name = "Livingroom Lights";
all = true;
entities = [
"light.livingroom_switch"
"light.living_bulb_1"
"light.living_bulb_2"
"light.living_bulb_3"
"light.living_bulb_4"
"light.living_bulb_5"
"light.living_bulb_6"
# "light.living_room"
];
}
{
platform = "switch";
name = "Kitchen Switch";
entity_id = "switch.kitchen_switch";
}
{
platform = "group";
name = "Kitchen Lights";
all = true;
entities = [
"light.kitchen_switch"
"light.kitchen_bulb_1"
"light.kitchen"
];
}
{
platform = "switch";
name = "Bedroom Switch";
entity_id = "switch.bedroom_switch";
}
{
platform = "group";
name = "Bedroom Lights";
all = true;
entities = [
"light.bedroom_switch"
"light.bedroom_bulb_1"
"light.bedroom_bulb_2"
"light.bedroom_bulb_3"
"light.bedroom_bulb_4"
];
}
{
platform = "group";
name = "Bathroom Lights";
all = true;
entities = [
"light.bathroom_switch"
"light.bathroom_bulb_1"
"light.bathroom_bulb_2"
];
}
{
platform = "group";
name = "Hallway Lights";
all = true;
entities = [
"light.hallway_light_switch_mini_switch"
"light.hallway_bulb_1"
"light.hallway_bulb_2"
];
}
{
platform = "template";
lights = {
hallway_group_proxy = {
friendly_name = "Hallway Lights (Proxy)";
# follow the real groups on/off state
value_template = "{{ is_state('light.hallway_lights','on') }}";
turn_on = {
service = "light.turn_on";
data = { entity_id = "light.hallway_lights"; };
};
turn_off = {
service = "light.turn_off";
data = { entity_id = "light.hallway_lights"; };
};
# brightness support
set_level = {
service = "light.turn_on";
data_template = {
entity_id = "light.hallway_lights";
brightness = "{{ brightness }}";
};
};
# color temperature support (if you have CT-capable bulbs)
set_temperature = {
service = "light.turn_on";
data_template = {
entity_id = "light.hallway_lights";
color_temp = "{{ color_temp }}";
};
};
# RGB color support
set_color = {
service = "light.turn_on";
data_template = {
entity_id = "light.hallway_lights";
rgb_color = [ "{{ red }}" "{{ green }}" "{{ blue }}" ];
};
};
# always report as “available”
availability_template = "true";
# declare which color modes you need
supported_color_modes = [ "brightness" "color_temp" "rgb" ];
};
};
}
{
platform = "switch";
name = "Toilet Switch";
entity_id = "switch.toilet";
}
{
platform = "group";
name = "Toilet Lights";
all = true;
entities = [
"light.toilet_switch"
"light.toilet_bulb"
];
}
];
};
}

View File

@@ -1,4 +1,9 @@
{
let
devices = [
"device_tracker.dominiks_iphone"
"device_tracker.dominiks_mp01"
];
in {
services.home-assistant.extraComponents = [
"nuki"
];
@@ -7,16 +12,19 @@
"automation house_door" = {
alias = "house_door";
mode = "restart";
hide_entity = true;
trigger = {
platform = "state";
entity_id = [
"person.dominik"
];
entity_id = devices;
from = "not_home";
to = "home";
};
action = [
{
service = "script.turn_on";
target = {
entity_id = "script.turn_on_circuits";
};
}
{
service = "lock.unlock";
target = {
@@ -57,6 +65,60 @@
}
];
}
{
conditions = [ "{{ state.house_door != \"unlocked\" }}" ];
sequence = [
{
service = "notify.mobile_app_dominiks_iphone";
data = {
message = "Someone is at the door!";
actions = [
{
action = "action_open";
title = "Open house door";
}
{
action = "action_ignore";
title = "Ignore";
}
];
};
}
{
wait_for_trigger = [
{
platform = "event";
event_type = "mobile_app_notification_action";
event_data = {
action = "{{ action_open }}";
};
}
{
platform = "event";
event_type = "mobile_app_notification_action";
event_data = {
action = "{{ action_ignore }}";
};
}
];
}
{
choose = [
{
conditions = "{{ wait.trigger.event.data.action == action_open }}";
sequence = [{
service = "lock.open";
target = {
entity_id = "lock.house_door";
};
}];
}
];
}
];
}
];
}
];

View File

@@ -0,0 +1,512 @@
{
services.home-assistant.extraComponents = [
"ping"
"broadlink"
"androidtv"
"samsungtv"
"apple_tv"
];
services.home-assistant.config = {
ios = {
actions = [
{
name = "Home Cinema";
label.text = "Home Cinema";
icon = {
icon = "theater";
color = "#ffffff";
};
show_in_watch = true;
}
];
};
binary_sensor = [
{
name = "xbox";
platform = "ping";
host = "xbox.cloonar.multimedia";
count = 2;
scan_interval = 5;
}
{
name = "ps5";
platform = "ping";
host = "ps5.cloonar.multimedia";
count = 2;
scan_interval = 5;
}
{
name = "steamdeck";
platform = "ping";
host = "steamdeck.cloonar.com";
count = 2;
scan_interval = 5;
}
{
platform = "template";
sensors = {
multimedia_device_on = {
friendly_name = "Any multimedia device on";
device_class = "connectivity";
value_template = ''
{% if ((states('media_player.living_room') != 'off') and (states('media_player.living_room') != 'standby')) or is_state('binary_sensor.ps5', 'on') or is_state('binary_sensor.xbox', 'on') or (is_state('binary_sensor.steamdeck', 'on') and (states('sensor.steamdeck_power') | float(default=0) > 5)) %}
on
{% else %}
off
{% endif %}
'';
};
};
}
];
script = {
turn_on_tv = {
sequence = [
{
choose = [
{
conditions = [
{
condition = "state";
entity_id = "switch.tv_switch";
state = "off";
}
];
sequence = [
{
service = "automation.turn_off";
target = {
entity_id = "automation.all_multimedia_off";
};
}
{
service = "switch.turn_on";
target = {
entity_id = "switch.tv_switch";
};
}
{
delay = 10;
}
{
service = "remote.send_command";
target = {
entity_id = "remote.rmproplus";
};
data = {
num_repeats = 1;
delay_secs = 0.4;
hold_secs = 0;
command = "b64:JgBOAJaSFREVNRU2FTUVERURFRAVERURFTUVNhU1FREVERUQFREVERUQFTYVNRURFREVEBURFTYVNRURFRAVNhU1FTYVNRUABfmWkhURFQANBQAAAAAAAAAAAAA=";
};
}
{
delay = 10;
}
{
service = "remote.turn_on";
target = {
entity_id = "remote.living_room";
};
}
{
delay = 120;
}
{
service = "automation.turn_on";
target = {
entity_id = "automation.all_multimedia_off";
};
}
];
}
{
conditions = [
{
condition = "state";
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
state = "unavailable";
}
];
sequence = [
{
service = "remote.send_command";
target = {
entity_id = "remote.rmproplus";
};
data = {
num_repeats = 1;
delay_secs = 0.4;
hold_secs = 0;
command = "b64:JgBOAJaSFREVNRU2FTUVERURFRAVERURFTUVNhU1FREVERUQFREVERUQFTYVNRURFREVEBURFTYVNRURFRAVNhU1FTYVNRUABfmWkhURFQANBQAAAAAAAAAAAAA=";
};
}
];
}
{
conditions = [
{
condition = "state";
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
state = "off";
}
];
sequence = [
{
service = "media_player.turn_on";
target = {
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
};
}
];
}
];
}
];
};
};
"automation steamdeck on" = {
alias = "steamdeck on";
trigger = {
platform = "template";
value_template = "{% if is_state('binary_sensor.steamdeck', 'on') and (states('sensor.steamdeck_power') | float > 5) %}true{% endif %}";
};
action = [
{
service = "denonavr.get_command";
target = {
entity_id = "media_player.marantz_sr6015";
};
data = {
command = "/goform/formiPhoneAppDirect.xml?SIDVD";
};
}
];
};
"automation xbox on" = {
alias = "xbox on";
trigger = {
platform = "state";
entity_id = "binary_sensor.xbox";
to = "on";
};
action = [
{
service = "denonavr.get_command";
target = {
entity_id = "media_player.marantz_sr6015";
};
data = {
command = "/goform/formiPhoneAppDirect.xml?SIGAME";
};
}
];
};
"automation firetv on" = {
alias = "firetv on";
trigger = {
platform = "state";
entity_id = "media_player.fire_tv_firetv_living_cloonar_multimedia";
from = "off";
};
action = [
{
service = "denonavr.get_command";
target = {
entity_id = "media_player.marantz_sr6015";
};
data = {
command = "/goform/formiPhoneAppDirect.xml?SIMPLAY";
};
}
];
};
"automation ps5 on" = {
alias = "ps5 on";
trigger = {
platform = "state";
entity_id = "binary_sensor.ps5";
to = "on";
};
action = [
{
service = "denonavr.get_command";
target = {
entity_id = "media_player.marantz_sr6015";
};
data = {
command = "/goform/formiPhoneAppDirect.xml?SIBD";
};
}
];
};
"automation all multimedia off" = {
alias = "all multimedia off";
trigger = {
platform = "state";
entity_id = "binary_sensor.multimedia_device_on";
to = "off";
for = "00:00:30";
};
action = [
{
service = "media_player.turn_off";
target = {
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
};
}
{
service = "denonavr.get_command";
target = {
entity_id = "media_player.marantz_sr6015";
};
data = {
command = "/goform/formiPhoneAppDirect.xml?PWSTANDBY";
};
}
# silverscreen up
{
service = "remote.send_command";
target = {
entity_id = "remote.rmproplus";
};
data = {
num_repeats = 2;
delay_secs = 1;
hold_secs = 0;
command = "b64:sgBqAgkaBBoJCRsJHBoKGgoJGgQaCQkaBAgbGwoIHAgcGwkJGwgAARkbCRsJGwkJGgQaCgkaBAgbCRsbCQkbGwkJGgQIGxwJGwkJGxsJCRwIHBoKCBsECBsbCAQIGwkAARgbChoKGgoJGxsJCRoECBsJHBsJCRoEGgkJGwkcGgobCQkbGwkJGwkbGwoIHAkbGwkJGwkAARgbCRsJGwoIGxwJCRsJGwkbGwoIGxwIChoKGhwJGwkJHBsJCRsJGxsJCRsJHBsJCRsJAAEYGwkbCRsKCBscCQkbCRsJGxsJCRwbCQkbCRsbCRsJCRscCQgcCRocCQkbCRsbCQobCQABGBsJGwkbCQkbHAkJGwkbCRsbCQkbGwoJGwkbGwkbCQkbGwoIHAkbGwkJGgobGwkKGwkAARccCRsJGwkJHBsJCRsJGwkbGwkJGxsKCRsIHBsJGwkJGxsKCRoJGxwJCRsJGxsJChsIAAEZGwgcCRsJCRscCQkbCRsJGhwJCRscCQkaChsbCRsJCRscCQgcCRocCQkbCRsbCggcCQABGBsJGwkbCggcGwkJGwkbCRsbCggcGgoJGwkbGwkbCggcGwkJGwkbGwkJHAgcGwkJGwkAARgbChoKGgoJGhwJCRsJGwkcGgoJGxsJCRsJGxsJHAkJGxsJCRsJGhwJCRwJGhwJCRsJAAEYGwoaChsJCRsbCQkaChsJGxwJCRsbCQkbCRsbChsJCRsbCQkbCRsbCgkbCRsbCQkcCAABFwQaChsJGwkJGxsKCBwIHAgcGwkJGxsKCBwIGwQaCRsJCRwaCggcCBwbCQkbCRwaCggcCAAF3AAAAAAAAAAAAAAAAAAA";
};
}
# turn off beamer
{
service = "remote.send_command";
target = {
entity_id = "remote.rmproplus";
};
data = {
num_repeats = 2;
delay_secs = 1;
hold_secs = 0;
command = "b64:JgDaAAABKZMUERMSExITEhMSExETEhMSExITEhMSExETNxQ2ExITEhMSEzcTNxM3ExITEhM3ExITNxMSEhITEhM3EzcTEhM3EwAFyAABKJQUERMSEhITEhMSExITEhMSEhITEhMSExITNxM3ExITEhMREzcTNxQ3EhITEhM3ExITNxMSExITEhM3EzcTEhM3EwAFyAABKJQUERMSExETEhMSExITEhMSExETEhMSExITNxM3ExITEhMREzcTOBI4ExETEhM3ExITNxMSExITEhM3EzcTEhM3E5IGAA0FAAAAAAAAAAAAAAAAAAA=";
};
}
];
};
"automation all_multimedia_on" = {
alias = "all multimedia on";
trigger = {
platform = "state";
entity_id = "binary_sensor.multimedia_device_on";
to = "on";
};
action = [
{
service = "script.turn_on";
target = {
entity_id = "script.turn_on_tv";
};
}
{
delay = 5;
}
{
service = "androidtv.adb_command";
target = {
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
};
data = {
command = "adb shell am start -a android.intent.action.VIEW -d content://android.media.tv/passthrough/com.mediatek.tvinput%2F.hdmi.HDMIInputService%2FHDMI100004";
};
}
];
};
"automation bedroom tv off" = {
alias = "bedroom tv off";
trigger = {
platform = "state";
entity_id = "media_player.fire_tv_firetv_bedroom_cloonar_multimedia";
to = "off";
};
action = [
{
service = "media_player.turn_off";
target = {
entity_id = "media_player.samsung_7_series_55";
};
}
];
};
"automation multimedia scene switch" = {
alias = "multimedia scene switch";
trigger = [
{
platform = "event";
event_type = "button_pressed";
event_data = {
id = [ 254 235 105 198 ];
onoff = 1;
};
}
{
platform = "event";
event_type = "ios.action_fired";
event_data = {
actionID = "Home Cinema";
};
}
];
action = [
{
choose = [
{
conditions = [
{
condition = "state";
entity_id = "switch.tv_switch";
state = "off";
}
];
sequence = [
{
service = "script.turn_on";
target = {
entity_id = "script.turn_on_tv";
};
}
];
}
{
conditions = [
{
condition = "or";
conditions = [
{
condition = "state";
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
state = "on";
}
{
condition = "state";
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
state = "idle";
}
];
}
];
sequence = [
# silver screen down
{
service = "remote.send_command";
target = {
entity_id = "remote.rmproplus";
};
data = {
num_repeats = 2;
delay_secs = 1;
hold_secs = 0;
command = "b64:sQs0AB0JCxsLGx0IHQgLGh0ICxoLGx0JCxodCQobCxoLAAEXHQgdCR0JCxodCQsbCxsLGx0JCxoAAAAA";
};
}
# turn on beamer
{
service = "remote.send_command";
target = {
entity_id = "remote.rmproplus";
};
data = {
num_repeats = 1;
delay_secs = 0.4;
hold_secs = 0;
command = "b64:JgAgAQABKZMUERMSExETEhMSExITEhMSExETEhMSExITNxM3ExITERM3EzgSOBM3ExETEhM3ExITEhMSExITERM3EzcTEhM3EwAFyAABKZMTEhMRExITEhMSExITEhMRExITEhMSExITNxM3ExITERM3EzcTNxM3ExITEhM3ExITEhMSExETEhM3EzcTEhM3EwAFyAABKZMUERMRExITEhMSExITERMSExITEhMSExITNxM3ExISEhM3EzcTNxM3ExITEhM3ExITEhMSExETEhM3EzcTEhM3EwAFxwABKZQUERMRFBETEhMSExITEhISExITEhMSExITNxM3ExITERM3EzcTNxM3FBETEhM3ExITEhMSExITERM3EzcTEhM3EwANBQAAAAAAAAAA";
};
}
{
service = "media_player.turn_off";
target = {
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
};
}
{
service = "media_player.turn_on";
target = {
entity_id = "media_player.marantz_sr6015";
};
}
];
}
{
conditions = [
{
condition = "or";
conditions = [
{
condition = "state";
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
state = "off";
}
{
condition = "state";
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
state = "unavailable";
}
];
}
];
sequence = [
{
service = "remote.send_command";
target = {
entity_id = "remote.rmproplus";
};
data = {
num_repeats = 2;
delay_secs = 1;
hold_secs = 0;
command = "b64:sgBqAgkaBBoJCRsJHBoKGgoJGgQaCQkaBAgbGwoIHAgcGwkJGwgAARkbCRsJGwkJGgQaCgkaBAgbCRsbCQkbGwkJGgQIGxwJGwkJGxsJCRwIHBoKCBsECBsbCAQIGwkAARgbChoKGgoJGxsJCRoECBsJHBsJCRoEGgkJGwkcGgobCQkbGwkJGwkbGwoIHAkbGwkJGwkAARgbCRsJGwoIGxwJCRsJGwkbGwoIGxwIChoKGhwJGwkJHBsJCRsJGxsJCRsJHBsJCRsJAAEYGwkbCRsKCBscCQkbCRsJGxsJCRwbCQkbCRsbCRsJCRscCQgcCRocCQkbCRsbCQobCQABGBsJGwkbCQkbHAkJGwkbCRsbCQkbGwoJGwkbGwkbCQkbGwoIHAkbGwkJGgobGwkKGwkAARccCRsJGwkJHBsJCRsJGwkbGwkJGxsKCRsIHBsJGwkJGxsKCRoJGxwJCRsJGxsJChsIAAEZGwgcCRsJCRscCQkbCRsJGhwJCRscCQkaChsbCRsJCRscCQgcCRocCQkbCRsbCggcCQABGBsJGwkbCggcGwkJGwkbCRsbCggcGgoJGwkbGwkbCggcGwkJGwkbGwkJHAgcGwkJGwkAARgbChoKGgoJGhwJCRsJGwkcGgoJGxsJCRsJGxsJHAkJGxsJCRsJGhwJCRwJGhwJCRsJAAEYGwoaChsJCRsbCQkaChsJGxwJCRsbCQkbCRsbChsJCRsbCQkbCRsbCgkbCRsbCQkcCAABFwQaChsJGwkJGxsKCBwIHAgcGwkJGxsKCBwIGwQaCRsJCRwaCggcCBwbCQkbCRwaCggcCAAF3AAAAAAAAAAAAAAAAAAA";
};
}
# turn off beamer
{
service = "remote.send_command";
target = {
entity_id = "remote.rmproplus";
};
data = {
num_repeats = 2;
delay_secs = 1;
hold_secs = 0;
command = "b64:JgDaAAABKZMUERMSExITEhMSExETEhMSExITEhMSExETNxQ2ExITEhMSEzcTNxM3ExITEhM3ExITNxMSEhITEhM3EzcTEhM3EwAFyAABKJQUERMSEhITEhMSExITEhMSEhITEhMSExITNxM3ExITEhMREzcTNxQ3EhITEhM3ExITNxMSExITEhM3EzcTEhM3EwAFyAABKJQUERMSExETEhMSExITEhMSExETEhMSExITNxM3ExITEhMREzcTOBI4ExETEhM3ExITNxMSExITEhM3EzcTEhM3E5IGAA0FAAAAAAAAAAAAAAAAAAA=";
};
}
{
service = "script.turn_on";
target = {
entity_id = "script.turn_on_tv";
};
}
{
service = "media_player.turn_off";
target = {
entity_id = "media_player.marantz_sr6015";
};
}
];
}
];
}
{
delay = 5;
}
{
service = "androidtv.adb_command";
target = {
entity_id = "media_player.android_tv_metz_cloonar_multimedia";
};
data = {
command = "adb shell am start -a android.intent.action.VIEW -d content://android.media.tv/passthrough/com.mediatek.tvinput%2F.hdmi.HDMIInputService%2FHDMI100004";
};
}
];
};
};
}

View File

@@ -0,0 +1,68 @@
{
services.home-assistant.extraComponents = [
"squeezebox"
"slimproto"
];
services.home-assistant.config = {
"automation toilet music" = {
alias = "toilet music";
trigger = {
platform = "state";
entity_id = "light.toilet_switch";
};
action = [
{
service = "media_player.volume_mute";
target = {
entity_id = "media_player.music_toilet";
};
data = {
is_volume_muted = "{{ trigger.to_state.state != 'on' }}";
};
}
];
};
"automation bathroom music" = {
alias = "bathroom music";
trigger = {
platform = "state";
entity_id = "light.bathroom_switch";
};
action = [
{
service = "media_player.volume_mute";
target = {
entity_id = "media_player.music_bathroom";
};
data = {
is_volume_muted = "{{ trigger.to_state.state != 'on' }}";
};
}
];
};
"automation piano" = {
alias = "piano";
trigger = {
platform = "state";
entity_id = "media_player.music_piano";
attribute = "is_volume_muted";
};
condition = [
{
condition = "template";
value_template = "{{ trigger.from_state.state != 'unavailable' }}";
}
{
condition = "template";
value_template = "{{ state_attr('media_player.music_piano_snapcast_client', 'is_volume_muted') == true or state_attr('media_player.music_piano_snapcast_client', 'is_volume_muted') == false }}";
}
];
action = {
service = "switch.turn_on";
target = {
entity_id = "switch.piano_switch_power";
};
};
};
};
}

Some files were not shown because too many files have changed in this diff Show More