# Synology NAS Deployment Checklist (Detailed) This document captures the exact steps and lessons learned to reliably deploy the Stiftung app on a Synology NAS. ## 1) Prerequisites ✅ - DSM 7.0+ with the Docker package installed (Package Center) - SSH enabled (Control Panel → Terminal & SNMP → Enable SSH) - At least 4GB RAM and 10GB free disk space - NAS local IP (e.g., `192.168.1.50`) and open port 8081 ## 2) Directory Layout on NAS ✅ Create this structure on the NAS (e.g., under `/volume1/docker/stiftung`): ``` /volume1/docker/stiftung ├─ app/ # Django app code (the entire project folder "app") ├─ deploy-synology/ # Deployment files (compose, scripts, env template) └─ data/ # Persistent volumes created by compose ├─ db/ ├─ backups/ ├─ redis/ ├─ uploads/ └─ logs/ ``` Important: - The `deploy-synology/docker-compose.yml` uses `build.context: ../app`. Ensure `app/` sits next to `deploy-synology/` in the same parent directory. - If you used File Station to upload ZIPs, make sure you actually extracted the real `app` contents (not an empty folder). ## 3) Environment Configuration ✅ 1) Go to the deployment folder: ```bash cd /volume1/docker/stiftung/deploy-synology ``` 2) Create `.env` from template and edit values: ```bash cp env.template .env vi .env # or use Text Editor in DSM ``` 3) Required variables (example): ```bash # Core SECRET_KEY=change_me_to_a_long_random_string DEBUG=False ALLOWED_HOSTS=localhost,127.0.0.1,crnas,192.168.1.50 CSRF_TRUSTED_ORIGINS=http://crnas:8081,http://192.168.1.50:8081,http://localhost:8081 # Database DB_PASSWORD=super_secure_db_password # Paperless (optional) PAPERLESS_URL= PAPERLESS_TOKEN= ``` Notes: - The database service uses: `POSTGRES_DB=stiftung`, `POSTGRES_USER=stiftung_user`, `POSTGRES_PASSWORD=${DB_PASSWORD}`. - The app services also receive `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`. This alignment prevents auth failures. ## 4) First Deployment ✅ 1) Make scripts executable (first time only): ```bash cd /volume1/docker/stiftung/deploy-synology chmod +x *.sh ``` 2) Start services: ```bash ./deploy.sh ``` 3) Create a Django superuser: ```bash sudo docker-compose exec web python manage.py createsuperuser ``` 4) Access the app: ``` http://:8081 ``` 5) Health endpoint (for quick checks): ``` http://:8081/health/ ``` ## 5) Clean Reset / Redeploy ✅ Use when you change envs, or need a clean DB: ```bash cd /volume1/docker/stiftung/deploy-synology sudo docker-compose down -v rm -rf ./data/db mkdir -p ./data/db POSTGRES_UID=$(sudo docker run --rm postgres:15-alpine id -u postgres) POSTGRES_GID=$(sudo docker run --rm postgres:15-alpine id -g postgres) sudo chown -R $POSTGRES_UID:$POSTGRES_GID ./data/db sudo chmod 700 ./data/db sudo docker-compose up -d --build sudo docker-compose exec web python manage.py migrate ``` ## 6) Backup & Restore (via UI) ✅ - Backups are written to `./data/backups` (mounted as `/app/backups` inside containers). - Backup creation and restore are available in the app under Administration → Backup & Restore. - Restore requires uploading a backup created by this app (`.tar.gz`). The process runs in background; check the job status in the UI. Recommended restore flow on NAS: ```bash cd /volume1/docker/stiftung/deploy-synology sudo docker-compose stop worker beat # avoid writers during restore # Start restore via UI → upload .tar.gz → Start sudo docker-compose logs -f web | cat # watch progress # After completion: sudo docker-compose exec web python manage.py migrate sudo docker-compose restart web sudo docker-compose start worker beat ``` ## 7) Logs & Monitoring ✅ ```bash cd /volume1/docker/stiftung/deploy-synology sudo docker-compose ps sudo docker-compose logs --tail=150 web | cat sudo docker-compose logs -f web | cat ``` ## 8) Known Pitfalls & Fixes ✅ - Build path error: `ERROR: build path .../app does not exist` - Ensure directory layout matches section 2 (compose uses `../app`). - Image pull denied for `gramps/gramps-web` - GrampsWeb was removed from compose; use the provided compose without that service. - DB port already in use - The DB service exposes no host port. Access it internally via service name `db`. - Bind mount path does not exist (e.g., `./data/backups`) - Ensure `../data/backups` exists (compose will also create it). Use the provided layout. - `FATAL: password authentication failed for user "stiftung_user"` - The DB volume may have been initialized with an old password. Align credentials: - Quick fix (change DB user to match .env): ```bash sudo docker-compose exec db psql -U postgres -d postgres -c "ALTER USER stiftung_user WITH PASSWORD '...from .env DB_PASSWORD...'"; sudo docker-compose restart web worker beat ``` - Clean reinit (wipes data): use the Clean Reset steps above. Note path is `./data/db` relative to compose. - SECRET_KEY empty → 500 ImproperlyConfigured - Ensure `.env` has a non-empty `SECRET_KEY` (and it propagates into the web container): ```bash sudo docker-compose exec web env | grep -E "DJANGO_SECRET_KEY|SECRET_KEY" ``` - DisallowedHost for `crnas` - Add NAS hostname/IP to `.env`: ``` ALLOWED_HOSTS=192.168.x.x,crnas,localhost,127.0.0.1 CSRF_TRUSTED_ORIGINS=http://crnas:8081,http://192.168.x.x:8081,http://localhost:8081 ``` - Celery error: `Unable to load celery application. Module 'core' has no attribute 'celery'` - Fixed by adding `core/celery.py` and `from .celery import app as celery_app` in `core/__init__.py` (already included in the app). - Backup error: `pg_dump` not found - The app image installs `postgresql-client` (already included). Rebuild if you changed Dockerfile. - Restore 500 on upload - Fixed by ensuring the restore view imports `BackupJob` and uses the correct form field `backup_file`. ## 9) Updating the App ✅ ```bash cd /volume1/docker/stiftung/deploy-synology sudo docker-compose pull # if using remote images sudo docker-compose up -d --build web worker beat ``` If you changed environment values in `.env`, restart: ```bash sudo docker-compose up -d --build ``` --- Deployment Date: `________________` Deployed By: `________________` Notes: `________________`