Homey
- NixOS Deployment (active branch: nixos-port)
- Installation (legacy Helm)
- Backing up
- LDAP Configuration
- GITEA
- AUTHELIA
- EVERYTHING
- DRONE AND GITEA
- DAV
- NEXTCLOUD
- I UNDERSTAND
- PAPERLESS
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 SSIDsecrets/secrets.yaml— all secrets populated and sops-encrypted- WiFi password secret formatted as
wifi_psk=YourPassword(see below)
Adding / updating secrets
sops secrets/secrets.yaml
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:
wifi/psk: "wifi_psk=YourActualWifiPassword"
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):
networks."Zakobar".psk = "your-actual-wifi-password";
Build the bootstrap SD image (requires aarch64-linux build capability —
either boot.binfmt.emulatedSystems = ["aarch64-linux"] on your
workstation, or an aarch64 remote builder):
nix build .#nixosConfigurations.pi-main-bootstrap.config.system.build.sdImage \
--system aarch64-linux
Find your SD card device, then flash (double-check /dev/sdX!):
lsblk
zstdcat result/sd-image/nixos-sd-image-*.img.zst | \
sudo dd of=/dev/sdX bs=4M status=progress conv=fsync
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
# 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
Back on your workstation, add the public key to secrets/.sops.yaml
alongside the existing PGP key:
keys:
- &pi_main age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
creation_rules:
- path_regex: secrets/secrets.yaml$
key_groups:
- pgp:
- 076AA297579A0064
age:
- *pi_main
Then re-encrypt so the Pi can decrypt its own secrets:
sops updatekeys secrets/secrets.yaml
Phase 3 — Deploy the full config
nixos-rebuild switch \
--flake .#pi-main \
--target-host admin@192.168.1.100 \
--build-host admin@192.168.1.100 \
--use-remote-sudo
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:
caddyWithCloudflare = pkgs.caddy.withPlugins {
plugins = [ "github.com/caddy-dns/cloudflare@..." ];
hash = "sha256-REPLACE_WITH_REAL_HASH="; # ← paste here
};
Then re-run the deploy command from Phase 3.
Ongoing deploys from workstation
All future config changes follow the same pattern:
- Edit files on workstation
- Run:
nixos-rebuild switch \
--flake .#pi-main \
--target-host admin@192.168.1.100 \
--build-host admin@192.168.1.100 \
--use-remote-sudo
NixOS activates the new config on the Pi immediately, with an automatic rollback if activation fails.
Installation (legacy Helm)
Install using
helm upgrade --install homey . -n homey
Backing up
Backups use restic and run automatically via systemd on a daily schedule.
Strategy — two tiers
- 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.
- Offload (manual): Run
scripts/offload-backup.sh --target /path/to/diskto clone snapshots from the S3 repo onto a local disk (USB plugged into the Pi, or a disk on your workstation). Usesrestic copyso deduplication is preserved on the target.
What is backed up
All service data under /mnt/data/:
openldap/— LDAP database and configauthelia/— Authelia config and stategitea/— Gitea repositories and datanextcloud/— Nextcloud files + apg_dumpof the databasejellyfin/— 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:
# hosts/pi-main/default.nix
homey.backup.repository = "s3:https://s3.us-west-002.backblazeb2.com/your-bucket";
S3 credentials live in secrets/secrets.yaml as restic/s3_access_key_id and
restic/s3_secret_access_key.
Restore
# 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
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.<YOUR URL> SSH Server Port: 2222 Gitea Base URL: http://git.<YOUR URL>
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
DRONE AND GITEA
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