backup: 2026-07-25 14:39
This commit is contained in:
@@ -25,15 +25,37 @@ Eurovision Vote: Django app sourced from external flake =github:anerisgreat/euro
|
||||
|
||||
Backup: Restic daily at 03:00 to S3 (Backblaze B2, bucket =zakobar-home-backup=). Pre-hook: Nextcloud maintenance mode on + pg_dump. Post-hook: maintenance mode off. Manual offload: =restic copy= to local disk. NAR content and media excluded.
|
||||
|
||||
Reliability hardening in =hosts/pi-main/default.nix=:
|
||||
- Hardware watchdog: =bcm2835_wdt= kernel module, systemd watchdog runtimeTime=300s / rebootTime=360s
|
||||
- WiFi power save disabled: brcmfmac driver drops connections under low traffic; disabled via =iw= on interface up
|
||||
- Network watchdog: timer every 2 min (starts 5 min after boot), pings gateway, restarts wpa_supplicant, reboots if still dead after 30s
|
||||
- zramSwap: zstd, 25% RAM (~2 GB) — breathing room for PHP upload spikes
|
||||
- Nix build-dir: =/mnt/data/nix-build= — avoids small tmpfs filling during large builds
|
||||
Reliability hardening in =hosts/pi-main/default.nix=: hardware watchdog (bcm2835_wdt), WiFi power save disabled, network watchdog timer, zramSwap zstd 25%, Nix build-dir on external HD.
|
||||
|
||||
Bootstrap: =pi-main-bootstrap= config builds an SD image (=sd-image-aarch64.nix=) for first flash.
|
||||
|
||||
** Deployment
|
||||
|
||||
*Always deploy from the dev machine using the dev shell command:*
|
||||
|
||||
#+begin_src bash
|
||||
# Enter the dev shell first:
|
||||
nix develop
|
||||
|
||||
# Then run:
|
||||
homey-deploy-rpi-main
|
||||
#+end_src
|
||||
|
||||
Equivalent command (if not in dev shell):
|
||||
#+begin_src bash
|
||||
nixos-rebuild switch \
|
||||
--flake .#pi-main \
|
||||
--target-host admin@192.168.1.100 \
|
||||
--build-host admin@192.168.1.100 \
|
||||
--use-remote-sudo
|
||||
#+end_src
|
||||
|
||||
Both =--target-host= and =--build-host= point to the Pi — the build happens ON the Pi (uses Attic cache at =attic.zakobar.com=). The dev machine only supplies the flake source; it does not build locally.
|
||||
|
||||
*NEVER run =nixos-rebuild= directly on the Pi* (=/home/admin/homey/= is a stale mirror, not the authoritative source). The dev machine at =/home/aner/projects/selfhosted/homey/= is the source of truth.
|
||||
|
||||
Nix evaluates git-tracked files from the flake. New/modified files must be at least =git add=-ed (staged) before deploying, or they will be invisible to Nix. Untracked files are silently ignored.
|
||||
|
||||
** Conventions
|
||||
|
||||
=homeyConfig= specialArgs (passed to every module): =domain=, =organization=, =timezone=. Never hardcode domain strings.
|
||||
@@ -52,33 +74,34 @@ DynamicUser services (Eurovision Vote): secrets must be mode =0444= (not =0400=)
|
||||
|
||||
Caddy Cloudflare plugin secrets: uses =LoadCredential= + =ExecStart= override (clears list with empty string first, then sets the real start command) to export =CLOUDFLARE_API_TOKEN= before exec-ing caddy.
|
||||
|
||||
Stirling-PDF login disable: =DOCKER_ENABLE_SECURITY=false= is build-time only. To disable the runtime login page, also set =SECURITY_ENABLELOGIN=false=.
|
||||
|
||||
** Gotchas
|
||||
|
||||
hdparm APM udev rule was removed — USB-SATA bridges often don't support APM commands and hdparm hangs indefinitely, causing boot-time crashes. =hdparm= is still available as a package for manual use.
|
||||
hdparm APM udev rule was removed — USB-SATA bridges often don't support APM commands and hdparm hangs indefinitely, causing boot-time crashes.
|
||||
|
||||
=storage.nix= config is gated on =lib.mkIf (cfg.device != "")= — if =homey.storage.device= is empty string, the mount and all tmpfiles rules are skipped. Useful during initial setup.
|
||||
|
||||
Grafana login form disabled (=disable_login_form = true=) — recovery requires re-enabling it in the Nix config. All proxy-auth users are auto-assigned Admin role (safe because Authelia already restricts to admins group).
|
||||
|
||||
Nextcloud preview generation: a separate =oneshot= service =nextcloud-generate-previews= (declared in =hosts/pi-main/default.nix=) fills missing thumbnails after first start. Must be triggered manually or via timer.
|
||||
|
||||
Authelia config bind-mount gotcha: NixOS resolves the symlink to the nix store path at container start. Without =NIXOS_CONFIG_HASH= env var, a config change would not take effect until manual container restart.
|
||||
|
||||
WiFi network name: =Zakobar=. sops secret key: =wifi/psk=. The secret file must contain exactly one line: =wifi_psk=<password>=. The =ext:wifi_psk= format is wpa_supplicant's literal substitution syntax, not an env var.
|
||||
WiFi network name: =Zakobar=. sops secret key: =wifi/psk=. The secret file must contain exactly one line: =wifi_psk=<password>=.
|
||||
|
||||
Attic: writing ephemeral TOML config (not a real file in the store) via =ExecStartPre= shell script that writes to =/run/attic-config.toml=. JWT secret interpolated into the TOML at runtime.
|
||||
Attic: writing ephemeral TOML config via =ExecStartPre= shell script to =/run/attic-config.toml=. JWT secret interpolated into the TOML at runtime.
|
||||
|
||||
First deployment of a new container pulls the image during =nixos-rebuild switch=, which can block the activation for several minutes (e.g. stirling-pdf ~2 GB image took ~6 min on Pi). This is expected — not a hang.
|
||||
|
||||
** Key Files
|
||||
|
||||
- =flake.nix= — module list, =mkHost= builder, =homeyConfig= specialArgs, =rpi4Headless= hardware snippet
|
||||
- =hosts/pi-main/default.nix= — enabled services, static IP, WiFi, reliability hardening, Attic substituter config
|
||||
- =hosts/pi-main-bootstrap/default.nix= — SD card bootstrap image
|
||||
- =shells/defaultShell.nix= — dev shell with =homey-deploy-rpi-main= and other helper commands
|
||||
- =modules/caddy.nix= — =virtualHosts= option, dual vhost generation, Authelia forward_auth snippet
|
||||
- =modules/services/authelia.nix= — access control rule rendering, =accessControlRules= option (unconditional)
|
||||
- =modules/services/uptime-kuma.nix= — =homey.monitoring.monitors= option (unconditional), sync script
|
||||
- =modules/services/attic.nix= — Nix binary cache, JWT token config, netrc injection for Nix daemon
|
||||
- =modules/services/attic-setup.md= — post-deploy steps, token commands, client config, setup history
|
||||
- =modules/services/eurovote.nix= — DynamicUser wrapper for external flake module
|
||||
- =modules/services/stirling-pdf.nix= — PDF tools (merge/split/OCR/etc), port 8084, auth disabled via =SECURITY_ENABLELOGIN=false=
|
||||
- =modules/monitoring.nix= — Prometheus + Grafana, proxy auth wiring, Node Exporter Full dashboard
|
||||
- =modules/common.nix= — Nix settings, podman network creation, sops global config
|
||||
- =modules/storage.nix= — external HD mount, =extraDirs= option
|
||||
@@ -96,7 +119,7 @@ Should be able to do this
|
||||
[store]
|
||||
# Enable the chunk‑aware upload handler
|
||||
enableChunkedUpload = true
|
||||
# Optional: limit the size of each chunk (default 10 MiB)
|
||||
maxChunkSize = 5_000_000 # 5 MiB per chunk
|
||||
# Optional: limit the size of each chunk (default 10 MiB)
|
||||
maxChunkSize = 5_000_000 # 5 MiB per chunk
|
||||
|
||||
#+end_src
|
||||
|
||||
Reference in New Issue
Block a user