SendSecret: Erstimport und Umstellung auf Tag-Deployment
Wrapper-Frontend vor cryptgeon: der Browser verschluesselt lokal, per Mail geht nur der Link raus. Fuer das Deployment nach den Konventionen aus DEPLOY.md hergerichtet: - docker-compose.yml mit festem Projekt- und Container-Namen, kein ports-Mapping, Healthcheck als Deploy-Gate. cryptgeon und redis liegen im internen Netz, nur app haengt im Web-Netz. - cryptgeon von latest auf 2.9.3 gepinnt. Das ist derselbe Stand, den latest bisher geliefert hat; 2.6.2 existiert nicht. - /healthz in server.js, vor dem Catch-all-Proxy registriert. - Dockerfile auf npm ci mit Lockfile und non-root umgestellt. - .gitea/workflows/deploy.yml: Build und Syntaxpruefung vor dem Deploy, .env aus dem Repo-Secret DOTENV. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
70
docker-compose.yml
Normal file
70
docker-compose.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
# Fester Projektname. Ohne das leitet Compose ihn aus dem Verzeichnisnamen
|
||||
# ab - und der ist im CI-Job ein anderer als auf dem Host.
|
||||
name: sendsecret
|
||||
|
||||
services:
|
||||
# Der Wrapper: eigenes Frontend, Mailversand, Proxy auf cryptgeon.
|
||||
# Das ist der einzige Dienst, den der Nginx Proxy Manager sieht.
|
||||
app:
|
||||
# Versionstag ermoeglicht Rollback ohne Rebuild.
|
||||
image: sendsecret:${IMAGE_TAG:-latest}
|
||||
build: ./app
|
||||
# Fester Name: das ist die Adresse, auf die der Proxy zeigt.
|
||||
container_name: sendsecret
|
||||
restart: unless-stopped
|
||||
# Wird im Workflow aus dem Secret DOTENV erzeugt.
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- cryptgeon
|
||||
networks:
|
||||
- nginx-proxy-manager_default
|
||||
- internal
|
||||
# Pflicht: der Deploy-Schritt nutzt --wait und macht das zum Gate.
|
||||
# Abweichung von den 60s der Vorlage: bei --wait-timeout 180 reicht ein
|
||||
# 60s-Intervall nur fuer drei Versuche - der Deploy wuerde beim ersten
|
||||
# Fehlschlag knapp.
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
# Cryptgeon haelt die verschluesselten Notizen. Version gepinnt: die
|
||||
# Frontend-Bundles verschluesseln mit occulto 2.0.6 gegen dieses API-Format.
|
||||
cryptgeon:
|
||||
image: cupcakearmy/cryptgeon:2.9.3
|
||||
container_name: sendsecret-cryptgeon
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
REDIS_URL: redis://redis/
|
||||
ALLOW_ADVANCED: 'false'
|
||||
# Bewusst nicht im Web-Netz: erreichbar nur ueber den Proxy in app.
|
||||
networks:
|
||||
- internal
|
||||
|
||||
# Reiner Zwischenspeicher, ohne Persistenz - Notizen sind einmalig
|
||||
# abrufbar und sollen einen Neustart nicht ueberleben. Deshalb kein Volume.
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
command: redis-server --save "" --appendonly no
|
||||
container_name: sendsecret-redis
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- internal
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
# Kein ports-Mapping: Der Proxy erreicht app ueber das gemeinsame Netz unter
|
||||
# dem Container-Namen. cryptgeon und redis haengen nur im internen Netz.
|
||||
networks:
|
||||
nginx-proxy-manager_default:
|
||||
external: true
|
||||
internal:
|
||||
name: sendsecret-internal
|
||||
Reference in New Issue
Block a user