# CLAUDE.md — NAS Infrastruktur Kontext für Claude Code Sessions zum Thema Deployment und Infrastruktur auf der Synology NAS. --- ## Umgebung - **NAS:** Synology DiskStation, DSM 7.x, IP: `192.168.1.4` - **SSH:** `ssh jacek@192.168.1.4` — Docker-Befehle erfordern `sudo` - **Docker-Datenpfad:** `/volume2/docker/` — alle persistenten Daten hier - **Docker-Binary auf NAS:** `/usr/local/bin/docker` - **Gitea:** `http://192.168.1.4:3000` (Docker-Container auf NAS) --- ## Laufende Dienste | Dienst | Container | Port | Pfad | |--------|-----------|------|------| | PostgreSQL | `shared-postgres-1` | 5433 | `/volume2/docker/shared/` | | act_runner | `gitea-runner` | — | `/volume2/docker/gitea-runner/` | | Pamietnik | `pamietnik-api-1` | 9050 | `/volume2/docker/pamietnik/` | --- ## Datenbankzugriff **Aus Containern:** `host-gateway:5433` (`host-gateway` ist Docker's eingebauter Alias für den Host — in `extra_hosts` und `docker-compose.yml` deklarieren) **Remote (Heimnetz):** `psql -h 192.168.1.4 -p 5433 -U -d ` **Direkt auf NAS:** ```bash sudo docker exec -it shared-postgres-1 psql -U postgres ``` **Wichtig PostgreSQL 15+:** Nach `GRANT ALL PRIVILEGES ON DATABASE` zusätzlich: ```sql GRANT ALL ON SCHEMA public TO ; ``` --- ## CI/CD: Gitea Actions **Workflow-Datei:** `.gitea/workflows/deploy.yml` **Trigger:** Push auf `main` **Runner-Setup:** - Container: `gitea/act_runner:latest` mit `--network host` - `GITEA_INSTANCE_URL` muss NAS-IP sein (`192.168.1.4:3000`), **nicht** `localhost` - `config.yaml` braucht `valid_volumes: [/volume2/docker]` sonst werden Mounts ignoriert **Job-Container:** `docker:latest` mit `-v /volume2/docker:/volume2/docker` - Docker CLI ist im Image enthalten - Socket wird automatisch vom Runner propagiert (nicht nochmal in `options` mounten → Duplicate-Fehler) - `wget` statt `curl` verwenden (`curl` nicht im Image) **Gitea Konfiguration:** - Nicht-sensitive Werte (Pfade, Ports, DB-Namen) → **Variables** (`vars.NAME`) - Passwörter, Tokens → **Secrets** (`secrets.NAME`) - Variables mit Leerzeichen am Ende → Parsing-Fehler in Expressions --- ## Deployment-Muster für neue Projekte ```yaml # docker-compose.yml im Repo services: api: build: . ports: - "${APP_PORT:-8080}:8080" extra_hosts: - "host-gateway:host-gateway" environment: DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@host-gateway:5433/${DB_NAME} volumes: - /volume2/docker//uploads:/uploads restart: unless-stopped ``` ```yaml # .gitea/workflows/deploy.yml jobs: deploy: runs-on: self-hosted container: image: docker:latest options: -v /volume2/docker:/volume2/docker steps: - name: Pull code run: | if [ -d "${{ vars.DEPLOY_DIR }}/.git" ]; then git -C ${{ vars.DEPLOY_DIR }} pull else git clone http://192.168.1.4:3000//.git ${{ vars.DEPLOY_DIR }} fi - name: Write .env run: printf 'DB_PASSWORD=%s\n' '${{ secrets.DB_PASSWORD }}' > ${{ vars.DEPLOY_DIR }}/.env - name: Build & Deploy run: docker compose -f ${{ vars.DEPLOY_DIR }}/docker-compose.yml up --build -d - name: Health check run: sleep 15 && wget -qO- http://192.168.1.4:${{ vars.APP_PORT }}/healthz || exit 1 ``` --- ## Bekannte Fallstricke - **`Secure: true` auf Session-Cookies** schlägt fehl bei HTTP → `Secure: false` setzen - **Ports unter 1024** können Container auf Synology nicht binden → internen Port > 1024 wählen - **`localhost`** im Job-Container zeigt auf den Container selbst, nicht auf die NAS - **Volume-Mounts** in Workflow `container.options` werden doppelt gemountet wenn identisch mit Runner-Mount - **`/volume2/docker`** muss in `valid_volumes` der `config.yaml` stehen sonst wird Mount ignoriert --- ## Vollständige Setup-Anleitung Siehe `infra/README.md`