No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-09 16:35:43 -04:00
.opencode/skills Improvements to the update and skills 2026-09-26 23:18:13 -04:00
asleeponthejob.info Weekly maintenance updating versions 2026-10-09 16:35:43 -04:00
emocows.com Weekly maintenance updating versions 2026-10-09 16:35:43 -04:00
scripts Changes to the traefik backup 2026-09-19 18:51:44 -04:00
system/docker Livia server configuration for Docker services 2026-08-30 14:36:16 -04:00
.gitignore Livia server configuration for Docker services 2026-08-30 14:36:16 -04:00
AGENTS.md Livia server configuration for Docker services 2026-08-30 14:36:16 -04:00
opencode.json.example Livia server configuration for Docker services 2026-08-30 14:36:16 -04:00
README.md Updated update skill and change back up strategy 2026-08-30 23:17:12 -04:00

Livia Server Configuration

Created: 2026-07-06 Updated: 2026-08-30 Server: livia (192.168.50.4) OS: Ubuntu 24.04.4 LTS

Directory Layout

livia/
├── asleeponthejob.info/
│   ├── forgejo/                    # Forgejo git server
│   │   ├── compose.yml
│   │   ├── backup.sh
│   │   └── README.md
│   ├── portainer/                  # Portainer Docker management
│   │   └── compose.yml
│   ├── traefik/                    # Traefik reverse proxy
│   │   ├── compose.yml
│   │   ├── traefik.env.example
│   │   ├── traefik.yml
│   │   ├── dynamic.yml
│   │   ├── backup.sh
│   │   └── README.md
│   └── wud/                        # WUD (What's Up Docker?)
│       ├── compose.yml
│       ├── wud.env.example
│       ├── backup.sh
│       └── README.md
├── emocows.com/
│   ├── audiobookshelf/             # Audiobookshelf audiobook server
│   │   └── compose.yml
│   ├── authentik/                  # Authentik OIDC provider
│   │   ├── docker-compose.yml
│   │   ├── .env.example
│   │   └── README.md
│   ├── immich/                     # Immich photo management
│   │   ├── docker-compose.yml
│   │   ├── .env.example
│   │   └── README.md
│   ├── jellyfin/                   # Jellyfin media server
│   │   ├── compose.yml
│   │   ├── encoding.xml
│   │   ├── system.xml
│   │   ├── backup.sh
│   │   └── README.md
│   ├── mealie/                     # Mealie recipe manager
│   │   ├── compose.yml
│   │   ├── mealie.env.example
│   │   ├── backup.sh
│   │   └── README.md
│   ├── media-stack/                # Media management stack
│   │   ├── docker-compose.yml
│   │   └── README.md
│   └── navidrome/                  # Navidrome music server
│       └── compose.yml
├── scripts/                        # Maintenance and deployment scripts
│   ├── enable-maintenance
│   ├── disable-maintenance
│   ├── deploy-updates.sh
│   ├── livia-update.sh
│   └── backup-databases.sh
├── ssh/                            # SSH configuration
│   ├── config
│   └── livia.pub
├── system/                         # System configuration
│   ├── docker/daemon.json
│   ├── journald.conf
│   ├── fstab
│   └── swappiness.conf
├── .gitignore
├── AGENTS.md
├── README.md
└── opencode.json.example

Services Overview

Public Services (Let's Encrypt TLS)

Service Domain Internal Port
Traefik traefik.asleeponthejob.info 443
Authentik auth.emocows.com 9000
Forgejo git.asleeponthejob.info 3000
Immich pics.emocows.com 2283
Jellyfin media.emocows.com 8096
Mealie meals.emocows.com 9925
Navidrome music.emocows.com 4533
Portainer portainer.asleeponthejob.info 9443
WUD wud.asleeponthejob.info 3000
Audiobookshelf books.emocows.com 80

Internal Services (Self-Signed CA TLS)

Service Domain Internal Port
Prowlarr prowlarr.emocows.com 9696
Sonarr sonarr.emocows.com 8989
Radarr radarr.emocows.com 7878
Lidarr lidarr.emocows.com 8686
qBittorrent qbittorrent.emocows.com 1330

Internal-Only Services

Service Purpose Internal Port
Forgejo Postgres Forgejo database 5432
Mealie Postgres Mealie database 5432
Authentik Postgres Authentik database 5432
Immich Postgres Immich database 5432

Hardware

  • ASUS desktop, NVIDIA GeForce GTX 1080
  • 31 GiB RAM, 238.5G NVMe (root) + 894.3G SATA (/home)
  • Media: /mnt/Entertainment/{Movies,Music,TvSeries,Audiobooks,Podcasts}
  • Downloads: /mnt/Downloads
  • Photos: /mnt/Pics

Secrets Management

All secrets are stored in 1Password "Home Lab" vault. No secrets are committed to this repository.

1Password Items

1Password Item Type Purpose
Traefik (Dashboard) Login Dashboard password (hash in traefik.env)
Arista (Authentik) Login Web UI login (akadmin)
Jellyfin (Livia) Login Web UI login
Mealie (Homelab) Login Web UI login
Mealie Env Document .env file with DB + OIDC secrets
Livia (Portainer) Login Web UI login
Arista (Immich) Login Web UI login
WUD Login OIDC + SMTP secrets (custom fields)
Livia Backup Document Backup archive

On-Server Environment Files

File 1Password Source Purpose
/srv/traefik/traefik.env Traefik (Dashboard) Dashboard basic auth hash
/srv/authentik/.env Manual creation DB password, secret key
/srv/mealie/mealie.env Mealie Env (document) DB passwords, OIDC credentials
/srv/immich/.env Manual creation DB password
/srv/wud/wud.env WUD (custom fields) OIDC client ID + secret, SMTP password
/srv/forgejo/forgejo.env Manual creation DB password, Forgejo config

Environment File Templates

Template files (.env.example) are provided in each service directory. To create an environment file:

# Example for Traefik (generate hash from password)
op item get "Traefik (Dashboard)" --vault "Home Lab" --fields password --reveal | \
  jq -r '.password' | openssl passwd -apr1 -stdin
# Create traefik.env with: TRAEFIK_DASHBOARD_USERS=admin:<hash>

# Example for Mealie (download document)
op document get "Mealie Env" --vault "Home Lab" > /srv/mealie/mealie.env
chmod 600 /srv/mealie/mealie.env

Backup Scripts

Per-Service Backups

Each service has a backup.sh script in its directory:

# Jellyfin
cd emocows.com/jellyfin && ./backup.sh --local

# Mealie
cd emocows.com/mealie && ./backup.sh --local

# Traefik
cd asleeponthejob.info/traefik && ./backup.sh --local

# WUD
cd asleeponthejob.info/wud && ./backup.sh --local

# Forgejo
cd asleeponthejob.info/forgejo && ./backup.sh --local

# Restore (Jellyfin and Mealie only)
cd emocows.com/jellyfin && ./backup.sh --restore
cd emocows.com/mealie && ./backup.sh --restore

Database Backups (scripts/backup-databases.sh)

Runs on livia (not via SSH from client). Backs up all PostgreSQL databases:

Container Database User
mealie-postgres mealie mealie
immich_postgres immich postgres
authentik_postgres authentik authentik
forgejo-postgres forgejo forgejo

Always run a database backup before destructive actions (container upgrades, compose changes, migrations):

# Backup all databases (runs on livia)
cat scripts/backup-databases.sh | ssh livia "sudo bash -s"

# Backup a single database directly (e.g., Mealie)
ssh livia "sudo docker exec mealie-postgres pg_dump -U mealie -d mealie --no-owner --no-acl | gzip" > mealie-backup.sql.gz

# Restore from latest backups
cat scripts/backup-databases.sh | ssh livia "sudo bash -s -- --restore"
  • Backups are stored at /opt/backups/{database}/ on livia
  • Retention: 7 days (older backups are auto-rotated)
  • Format: .sql.gz (compressed PostgreSQL dump, restorable with zcat ... | psql)
  • Local backup copies saved to this machine when using > redirection

Quick Restore

# 1. Fresh Ubuntu 24.04 install
# 2. Install Docker + nvidia-container-toolkit
# 3. Install cron: sudo apt install cron
# 4. Grab "Livia Backup" document from 1Password and extract
# 5. Clone this repository
# 6. Create environment files from 1Password:
#    - /srv/mealie/mealie.env (from "Mealie Env" document)
#    - /srv/traefik/traefik.env (generate hash from "Traefik (Dashboard)")
#    - /srv/wud/wud.env (from "WUD" custom fields)
#    - /srv/authentik/.env (manual creation)
#    - /srv/immich/.env (manual creation)
#    - /srv/forgejo/forgejo.env (manual creation)
# 7. Create required directories:
#    sudo mkdir -p /srv/{traefik,mealie,authentik,immich,wud,forgejo,navidrome,audiobookshelf}
# 8. Deploy services (in order):
#    cd asleeponthejob.info/traefik && sudo docker compose up -d
#    cd ../portainer && sudo docker compose up -d
#    cd ../../emocows.com/authentik && sudo docker compose up -d
#    cd ../mealie && sudo docker compose up -d
#    cd ../immich && sudo docker compose up -d
#    cd ../jellyfin && sudo docker compose up -d
#    cd ../media-stack && sudo docker compose up -d
#    cd ../navidrome && sudo docker compose up -d
#    cd ../audiobookshelf && sudo docker compose up -d
#    cd ../../asleeponthejob.info/wud && sudo docker compose up -d
#    cd ../forgejo && sudo docker compose up -d
# 9. Verify: sudo docker ps

Network Architecture

Internet → Router (port 80/443) → Synology NAS (192.168.50.2) → Livia (192.168.50.4)
  • Synology forwards ports 80/443 to livia
  • Traefik handles HTTP-01 challenge on port 80
  • Let's Encrypt issues certificates for public domains
  • HTTP→HTTPS redirect via Traefik middleware

Certificate Architecture

Traefik uses a hybrid TLS approach: Let's Encrypt for public sites and self-signed CA-signed certs for internal sites.

How It Works

  1. Public sites (have DNS A records) → Let's Encrypt via HTTP-01 challenge
  2. Internal sites (LAN only) → Individual per-service certs signed by Livia Home Lab CA, each with a SAN (Subject Alternative Name)
  3. Why not wildcards? — Wildcard certs (*.emocows.com) block Let's Encrypt ACME challenges; Traefik sees them as "provided" and skips HTTP-01
  4. SAN matching — Each cert has a SAN matching its domain (e.g., DNS:radarr.emocows.com)
  5. Fallback — If no matching cert, Traefik uses the default certificate

Certificate Hierarchy

Livia Home Lab CA (self-signed root, 10-year validity)
├── media.emocows.com
├── prowlarr.emocows.com
├── sonarr.emocows.com
├── radarr.emocows.com
├── lidarr.emocows.com
├── qbittorrent.emocows.com
├── portainer.asleeponthejob.info
├── traefik.asleeponthejob.info
└── wud.asleeponthejob.info

Certificate Files (on-server at /srv/traefik/certs/)

File Purpose
ca.crt / ca.key CA root certificate and private key (install ca.crt on clients)
{service}.crt Leaf certificate for each service
{service}.key Private key for each service
{service}-chain.crt Full chain (leaf + CA) — what Traefik serves
acme.json Let's Encrypt certificates (auto-managed, in /srv/traefik/)

Installation on Client Devices

To avoid browser warnings, install the Livia Home Lab CA certificate in your device's trust store:

macOS:

scp livia:/srv/traefik/certs/ca.crt /tmp/livia-ca.crt
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/livia-ca.crt

Windows:

Chrome, Edge, and other Chromium-based browsers (Vivaldi, Brave) use the Windows certificate store, so a single system-wide install covers them all. Firefox has its own store and needs a separate import.

System-wide install (covers Chrome, Edge, Vivaldi, Brave):

  1. Copy ca.crt from livia to the Windows machine
  2. Double-click ca.crt → Install Certificate
  3. Select Local Machine (requires admin) → Next
  4. Select Place all certificates in the following store → Browse → Trusted Root Certification Authorities → OK → Next → Finish
  5. Accept the security warning → Done

PowerShell (alternative):

# Import to the Local Machine trust store (run as Administrator)
Import-Certificate -FilePath "C:\path\to\ca.crt" -CertStoreLocation Cert:\LocalMachine\Root

Firefox: Firefox uses its own certificate store and does not trust the Windows store by default.

  1. Open Firefox → Settings → Privacy & Security → Certificates → View Certificates
  2. Authorities → Import → select ca.crt
  3. Check Trust this CA to identify websites → OK
  4. Restart Firefox

Note: After installing, restart all browsers for changes to take effect.

Linux (system-wide):

scp livia:/srv/traefik/certs/ca.crt /usr/local/share/ca-certificates/livia-ca.crt
sudo update-ca-certificates

Linux (Chromium/Vivaldi/Chrome/Edge): Chromium-based browsers use their own NSS certificate database, separate from the system trust store.

# Install certutil
sudo apt-get install -y libnss3-tools

# Add the CA to the Chromium NSS trust store
certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "Livia Home Lab CA" -i /path/to/ca.crt

# Restart the browser for changes to take effect

Linux (Firefox):

  1. Settings → Privacy & Security → Certificates → View Certificates
  2. Authorities → Import → select ca.crt
  3. Check "Trust to identify websites"

iOS/Android:

  1. Download ca.crt from https://traefik.asleeponthejob.info (accept warning first)
  2. Install as trusted certificate in device settings

Regenerating Certificates

The server uses individual per-service certificates (not wildcards) because wildcards block Let's Encrypt ACME challenges. Each cert must include a Subject Alternative Name (SAN) — modern browsers ignore the CN field entirely.

Services and their domains:

Service Domain
media media.emocows.com
prowlarr prowlarr.emocows.com
sonarr sonarr.emocows.com
radarr radarr.emocows.com
lidarr lidarr.emocows.com
qbittorrent qbittorrent.emocows.com
traefik-dash traefik.asleeponthejob.info
wud wud.asleeponthejob.info
portainer portainer.asleeponthejob.info

To regenerate a single cert:

ssh livia

# Example: regenerate sonarr cert (repeat for each service)
DOMAIN="sonarr.emocows.com"
NAME="sonarr"
CERT_DIR="/srv/traefik/certs"

# Generate CSR with SAN
sudo openssl req -new -key "$CERT_DIR/$NAME.key" -out "/tmp/$NAME.csr" \
  -subj "/CN=$DOMAIN" -addext "subjectAltName=DNS:$DOMAIN"

# Sign with CA
sudo openssl x509 -req -in "/tmp/$NAME.csr" \
  -CA "$CERT_DIR/ca.crt" -CAkey "$CERT_DIR/ca.key" \
  -CAcreateserial -out "$CERT_DIR/$NAME.crt" -days 3650 \
  -copy_extensions copyall

# Build full chain (leaf + CA)
sudo cat "$CERT_DIR/$NAME.crt" "$CERT_DIR/ca.crt" > "$CERT_DIR/$NAME-chain.crt"

# Verify SANs are present
sudo openssl x509 -in "$CERT_DIR/$NAME.crt" -noout -ext subjectAltName

# Restart Traefik
sudo docker restart traefik

To regenerate the CA (only if compromised or expired):

ssh livia
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout /srv/traefik/certs/ca.key -out /srv/traefik/certs/ca.crt \
  -subj '/CN=Livia Home Lab CA'
# Then regenerate ALL per-service certs (they're signed by the CA)

Configuration Files

File Purpose
traefik/traefik.yml Static config: entrypoints, ACME, file provider
traefik/dynamic.yml Dynamic config: self-signed certs, TLS store
traefik/compose.yml Container labels for routing

WUD (What's Up Docker?)

  • Monitors all containers for updates
  • Notifications: Gmail SMTP, batch mode, Friday mornings
  • OIDC: Authentik at auth.emocows.com
  • CORS: disabled
  • Delete: through UI only