# Kvitt production stack on the Kvitt Pi (SPEC §10.2). Deployed by install.sh to /opt/kvitt/compose.yaml together # with /opt/kvitt/.env (from .env.example). Run every command from /opt/kvitt. # TLS terminates in Nginx Proxy Manager on the Home Assistant Pi (SPEC §10.5, D-120), which forwards plain HTTP over # the LAN to the server's published port 8080. Only the server publishes a port; backup is reachable only on the # internal network `kvitt` (SPEC §8.9). The router forwards the internet only to NPM, never to this Pi. # Image names: ${KVITT_REGISTRY}/kvitt-, the names the Gitea Actions workflow pushes (D-104). name: kvitt x-logging: &logging driver: json-file options: max-size: "10m" max-file: "3" services: server: image: ${KVITT_REGISTRY:?set KVITT_REGISTRY in .env}/kvitt-server:${KVITT_TAG:?set KVITT_TAG in .env} command: ["serve"] restart: unless-stopped user: "10001:10001" read_only: true cap_drop: [ALL] security_opt: - no-new-privileges:true mem_limit: 160m # On all interfaces of the Pi: NPM on the Home Assistant Pi connects to :8080 over the LAN. ports: - "8080:8080" environment: TZ: Europe/Stockholm KVITT_DATA_DIR: /data KVITT_PUBLIC_URL: https://${KVITT_PUBLIC_HOST:?set KVITT_PUBLIC_HOST in .env}:8443 # NPM's LAN address: only a request whose TCP peer is this address may set X-Forwarded-For, whose last entry # is then the client IP of the rate limits (SPEC §8.5, §8.6, D-120). An IP literal (install.sh checks it). KVITT_TRUSTED_PROXY: ${HA_HOST:?set HA_HOST in .env} # The remaining server settings keep their SPEC §10.4 defaults (KVITT_FCM_PROJECT_ID kvitt-1337, ...). volumes: - data:/data - /opt/kvitt/secrets/fcm-service-account.json:/secrets/fcm-service-account.json:ro # Empty except during the one-off Splitwise import (SPEC §10.8, D-025). - /opt/kvitt/import:/import:ro healthcheck: test: ["CMD", "kvitt-server", "healthcheck"] interval: 30s timeout: 5s retries: 3 start_period: 20s logging: *logging networks: [kvitt] backup: image: ${KVITT_REGISTRY}/kvitt-backup:${KVITT_TAG} restart: unless-stopped # uid 10001 like the server, so it can open the WAL database files the server owns; rclone.conf on the Pi is # therefore owned by 10001 (infra/README.md "Backup uid", D-105). user: "10001:10001" cap_drop: [ALL] security_opt: - no-new-privileges:true mem_limit: 96m environment: TZ: Europe/Stockholm RCLONE_REMOTE: ${RCLONE_REMOTE:-gdrive:} RCLONE_FOLDER_ID: ${RCLONE_FOLDER_ID:?set RCLONE_FOLDER_ID in .env} volumes: - data:/data - backups:/backups - /opt/kvitt/secrets/rclone.conf:/config/rclone/rclone.conf:ro healthcheck: test: ["CMD", "/healthcheck.sh"] interval: 5m timeout: 10s retries: 1 start_period: 30s logging: *logging networks: [kvitt] volumes: data: backups: networks: kvitt: driver: bridge