Files
homey/README.org
T
Aner Zakobar 0b73d493d8 Working NixOS port: all core services operational
- Fix Caddy cfProxy helper for cloudflared http:// vhosts (X-Forwarded-Proto)
- Fix Authelia LDAP bind (readonly user ACL + password sync)
- Add gitea-admin-setup oneshot service to survive rebuilds
- Update Authelia forward_auth with header_up X-Forwarded-Proto https
- Update TODO.org with completed tasks and LDAP config details
- Remove old Helm/k8s artifacts (Chart.yaml, templates/, values/, scripts)
- Add result to .gitignore

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 14:46:21 +03:00

301 lines
7.7 KiB
Org Mode

#+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.<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
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