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>
This commit is contained in:
+300
@@ -0,0 +1,300 @@
|
||||
#+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
|
||||
Reference in New Issue
Block a user