Files
pamietnik/infra/CLAUDE.md
Christoph K. ad65102fdc
All checks were successful
Deploy to NAS / deploy (push) Successful in 44s
Update infra docs with complete working setup
- README.md: rewrite with accurate setup steps including all lessons learned
- CLAUDE.md: update with working CI/CD patterns and known pitfalls
- gitea-actions.md: new file documenting Gitea Actions usage, expressions,
  act_runner config, and troubleshooting for future projects

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 18:46:55 +02:00

3.8 KiB

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 <user> -d <db>

Direkt auf NAS:

sudo docker exec -it shared-postgres-1 psql -U postgres

Wichtig PostgreSQL 15+: Nach GRANT ALL PRIVILEGES ON DATABASE zusätzlich:

GRANT ALL ON SCHEMA public TO <user>;

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

# 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/<projekt>/uploads:/uploads
    restart: unless-stopped
# .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/<org>/<repo>.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