#+title: Homey A home environment for everyone! * NixOS Deployment (active branch: nixos-port) ** Prerequisites Before building, make sure the following are set in the repo: - =hosts/pi-main/default.nix= — SSH public key, static IP, WiFi SSID - =secrets/secrets.yaml= — all secrets populated and sops-encrypted - WiFi password secret formatted as =wifi_psk=YourPassword= (see below) ** Adding / updating secrets #+begin_src bash sops secrets/secrets.yaml #+end_src Opens your editor with the decrypted file. Save and quit to re-encrypt. The WiFi password entry must use the =wifi_psk== prefix so wpa_supplicant can look up the value by name: #+begin_src yaml wifi/psk: "wifi_psk=YourActualWifiPassword" #+end_src ** Phase 1 — Bootstrap image (flash this first) The full =pi-main= config requires sops secrets, which require an age key on the Pi — but the age key doesn't exist until after first boot. To break the chicken-and-egg problem, flash a minimal bootstrap image first. Before building, fill in the WiFi password in =flake.nix= in the =pi-main-bootstrap= config (search for =WIFI_PASSWORD_HERE=): #+begin_src nix networks."Zakobar".psk = "your-actual-wifi-password"; #+end_src Build the bootstrap SD image (requires =aarch64-linux= build capability — either =boot.binfmt.emulatedSystems = ["aarch64-linux"]= on your workstation, or an aarch64 remote builder): #+begin_src bash nix build .#nixosConfigurations.pi-main-bootstrap.config.system.build.sdImage \ --system aarch64-linux #+end_src Find your SD card device, then flash (double-check =/dev/sdX=!): #+begin_src bash lsblk zstdcat result/sd-image/nixos-sd-image-*.img.zst | \ sudo dd of=/dev/sdX bs=4M status=progress conv=fsync #+end_src The Pi will boot at =192.168.1.100=, connect to =Zakobar= WiFi, and accept SSH connections with your key. No services run yet. ** Phase 2 — Generate age key and re-encrypt secrets #+begin_src bash # SSH into the Pi ssh admin@192.168.1.100 # Generate the age key sudo age-keygen -o /var/lib/sops-nix/key.txt # Print the public key — copy it sudo age-keygen -y /var/lib/sops-nix/key.txt #+end_src Back on your workstation, add the public key to =secrets/.sops.yaml= alongside the existing PGP key: #+begin_src yaml keys: - &pi_main age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx creation_rules: - path_regex: secrets/secrets.yaml$ key_groups: - pgp: - 076AA297579A0064 age: - *pi_main #+end_src Then re-encrypt so the Pi can decrypt its own secrets: #+begin_src bash sops updatekeys secrets/secrets.yaml #+end_src ** Phase 3 — Deploy the full config #+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 The Pi builds its own config natively (no cross-compilation). sops-nix will now decrypt all secrets and start all services. ** Caddy plugin hash The first deploy will fail at the Caddy build step because =lib.fakeHash= is a placeholder. Copy the correct hash from the error output and replace it in =modules/caddy.nix=: #+begin_src nix caddyWithCloudflare = pkgs.caddy.withPlugins { plugins = [ "github.com/caddy-dns/cloudflare@..." ]; hash = "sha256-REPLACE_WITH_REAL_HASH="; # ← paste here }; #+end_src Then re-run the deploy command from Phase 3. ** Ongoing deploys from workstation All future config changes follow the same pattern: 1. Edit files on workstation 2. Run: #+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 NixOS activates the new config on the Pi immediately, with an automatic rollback if activation fails. * Installation (legacy Helm) Install using #+begin_src bash helm upgrade --install homey . -n homey #+end_src * Backing up Backups use [[https://restic.net/][restic]] and run automatically via systemd on a daily schedule. ** Strategy — two tiers 1. *Primary (automatic)*: Daily backup to an S3-compatible bucket (Backblaze B2, Wasabi, AWS S3, etc.). Restic deduplicates and encrypts before upload. Retention: 7 daily, 4 weekly, 6 monthly snapshots. 2. *Offload (manual)*: Run =scripts/offload-backup.sh --target /path/to/disk= to clone snapshots from the S3 repo onto a local disk (USB plugged into the Pi, or a disk on your workstation). Uses =restic copy= so deduplication is preserved on the target. ** What is backed up All service data under =/mnt/data/=: - =openldap/= — LDAP database and config - =authelia/= — Authelia config and state - =gitea/= — Gitea repositories and data - =nextcloud/= — Nextcloud files + a =pg_dump= of the database - =jellyfin/= — Jellyfin metadata (media files are excluded — re-downloadable) - =transmission/= — Torrent client config Nextcloud is placed into maintenance mode and postgres is =pg_dump='d before each backup to ensure a consistent snapshot. ** Configuration Repository URL and credentials are set per-host: #+begin_src nix # hosts/pi-main/default.nix homey.backup.repository = "s3:https://s3.us-west-002.backblazeb2.com/your-bucket"; #+end_src S3 credentials live in =secrets/secrets.yaml= as =restic/s3_access_key_id= and =restic/s3_secret_access_key=. ** Restore #+begin_src bash # List snapshots restic -r s3:https://... snapshots # Restore latest snapshot to /mnt/data restic -r s3:https://... restore latest --target /mnt/data # Restore a single service restic -r s3:https://... restore latest --target /mnt/data --include /mnt/data/gitea #+end_src * LDAP Configuration Logins are done to PHPLDAPADMIN DN is like: cn=admin,dc=,dc=io get-secret-val.sh homey openldap-admin password First thing we do is create an organization unit called users To add a new user, we create a child entry to ou=users It has to be of type inetOrgPerson cn = Common Name, sn = Sur Name. Select RDN = User Name (uid) (FROM DROP DOWN MENU) UID = USERNAME, that is what is important. (In PHPLdapAdmin it is under User Name) Now we may continue! * GITEA Site Title: whatever SSH Server Domain: git. SSH Server Port: 2222 Gitea Base URL: http://git. Then add Administrator Account Settings: Administrator Username: gitea-admin Password: from gitea-admin-pass Email address must be populated That will work after a few minutes. Now we go into Authentication Sources Add a new LDAP Authentication source Authentication name: Home LDAP Host: openldap Port: 389 Bind DN = cn=readonly,dc=,dc=io Bind Password: openldap-ro password User Search Base: ou=users,dc=,dc=io user search filter = (uid=%s) Admin filter (title=admin) Username Attribute: uid First Name Attribute: cn Surname Attribute: sn Email Attribute: mail * AUTHELIA https://github.com/authelia/authelia/blob/57d5fbd3f5c82e83296023dc1de6e4f5ff063c00/examples/compose/lite/authelia/configuration.yml This fucking sucks https://gist.github.com/james-d-elliott/5152d27c0781aee856a3383f1284998e * EVERYTHING https://www.talkingquickly.co.uk/gitea-sso-with-keycloak-openldap-openid-connect * DRONE AND GITEA ? https://dev.to/ruanbekker/self-hosted-cicd-with-gitea-and-drone-ci-200l * DAV https://gitlab.com/davical-project/davical/-/blob/master/config/example-config.php Line 800 ish for auth from reverse proxy * NEXTCLOUD I ran THIS command inside su www-data -s /bin/bash -c php occ ldap:promote-group "admins" ** When maintenence mode #+begin_example kubectl exec --tty --stdin -n homey deploy/nextcloud -- su -l www-data -s /bin/bash php /var/www/html/occ maintenance:mode --off #+end_src * I UNDERSTAND I need to backup Chen's stuff And... I need to Jellyfin * PAPERLESS https://github.com/paperless-ngx/paperless-ngx/blob/74c44fe418a91a526b5dab1a91fde4aaebd28bb1/docker/compose/docker-compose.postgres.yml For docker