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

125 lines
3.8 KiB
Markdown

# 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:**
```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 <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
```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/<projekt>/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/<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`