fix(deploy): .env.docker resilient — no rm -f, sanity-check vars critiques

- Supprime rm -f (causait la perte de ~23 vars a chaque deploy)
- upsert ecrit KEY=value sans quotes (compatible Docker Compose v2)
- CRLF strip avant ecriture (sed s/\r$//)
- Sanity-check post-upsert: abort si NEXTAUTH_SECRET/AUTH_GOOGLE_ID/etc manquantes
- Header ## AUTO-MANAGED BY CI ## en tete de fichier genere
- deploy-prod.sh: sanity-check pre-deploy (NEXTAUTH_URL/SECRET/GOOGLE_ID/SECRET)
- Ajoute .env.docker.example (reference complete de toutes les vars)
- Ajoute MCP_SERVER_MODE/MCP_SERVER_URL manquantes dans deploy.yaml
This commit is contained in:
Antigravity
2026-06-28 13:15:55 +00:00
parent 19d446f78e
commit b8c85be40f
4 changed files with 102 additions and 110 deletions

View File

@@ -1,121 +1,80 @@
# ============================================================================= ## AUTO-MANAGED BY CI — do not edit manually ##
# Memento - Docker Environment Configuration ## This is a reference template. Real values come from Gitea vars/secrets. ##
# =============================================================================
# Copy this file to .env.docker and update with your values.
# This file is read by docker-compose.yml via env_file directive.
# cp .env.docker.example .env.docker
# ============================================================================= # Core
# APPLICATION URL (REQUIRED) NEXTAUTH_URL=https://memento-note.com
# ============================================================================= NEXTAUTH_SECRET=<secret>
# Change to your server IP or domain ADMIN_EMAIL=admin@example.com
# Examples: ALLOW_REGISTRATION=true
# IP: http://192.168.1.190:3000
# Domain: http://notes.yourdomain.com
# HTTPS: https://notes.yourdomain.com
NEXTAUTH_URL="http://localhost:3000"
# ============================================================================= # PostgreSQL (used by docker-compose to construct DATABASE_URL)
# AUTHENTICATION SECRET (REQUIRED)
# =============================================================================
# Generate with: openssl rand -base64 32
NEXTAUTH_SECRET="changethisinproduction"
# =============================================================================
# REGISTRATION & ADMIN
# =============================================================================
# Set to "false" to disable public registration (default: true)
# ALLOW_REGISTRATION=true
# Admin email - The first user registering with this email gets ADMIN role (REQUIRED)
# ADMIN_EMAIL="admin@yourdomain.com"
# Google OAuth — both required to show "Continue with Google" on /login
# Redirect URI in Google Console: {NEXTAUTH_URL}/api/auth/callback/google
# AUTH_GOOGLE_ID="....apps.googleusercontent.com"
# AUTH_GOOGLE_SECRET="GOCSPX-..."
# =============================================================================
# POSTGRESQL CONFIGURATION
# =============================================================================
POSTGRES_PORT=5432
POSTGRES_DB=memento
POSTGRES_USER=memento POSTGRES_USER=memento
POSTGRES_PASSWORD=memento POSTGRES_PASSWORD=<secret>
POSTGRES_DB=memento
POSTGRES_PORT=5433
# ============================================================================= # AI - Tags
# MCP SERVER CONFIGURATION
# =============================================================================
# Mode: 'stdio' (Claude Desktop, Cline) or 'sse' (N8N, HTTP)
MCP_MODE="stdio"
MCP_PORT="3001"
# Frontend MCP settings (for the MCP settings panel in the web UI)
# MCP_SERVER_MODE="sse"
# MCP_SERVER_URL="http://YOUR_IP:3001"
# =============================================================================
# AI PROVIDER - TAGS GENERATION
# =============================================================================
# Options: ollama, openai, custom
AI_PROVIDER_TAGS=ollama AI_PROVIDER_TAGS=ollama
AI_MODEL_TAGS="granite4:latest" AI_MODEL_TAGS=granite4:latest
# ============================================================================= # AI - Embeddings
# AI PROVIDER - EMBEDDINGS
# =============================================================================
# Options: ollama, openai, custom
AI_PROVIDER_EMBEDDING=ollama AI_PROVIDER_EMBEDDING=ollama
AI_MODEL_EMBEDDING="embeddinggemma:latest" AI_MODEL_EMBEDDING=embeddinggemma:latest
# ============================================================================= # AI - Chat
# AI PROVIDER - CHAT (optional, falls back to AI_PROVIDER_TAGS) AI_PROVIDER_CHAT=ollama
# ============================================================================= AI_MODEL_CHAT=granite4:latest
# AI_PROVIDER_CHAT=ollama
# AI_MODEL_CHAT="granite4:latest"
# ============================================================================= # AI - Custom OpenAI (OpenRouter etc.)
# OLLAMA CONFIGURATION (if provider = ollama) CUSTOM_OPENAI_BASE_URL=https://openrouter.ai/api/v1
# ============================================================================= CUSTOM_OPENAI_API_KEY=<secret>
# Docker service: http://ollama:11434 OPENAI_API_KEY=<secret>
# Host machine: http://host.docker.internal:11434
# Remote server: http://YOUR_SERVER_IP:11434
OLLAMA_BASE_URL="http://ollama:11434"
# ============================================================================= # AI - Ollama
# OPENAI CONFIGURATION (if provider = openai) OLLAMA_BASE_URL=http://ollama:11434
# =============================================================================
# OPENAI_API_KEY="sk-..."
# ============================================================================= # Redis (set by CI, do not override)
# CUSTOM OPENAI-COMPATIBLE PROVIDER (if provider = custom) REDIS_HOST=redis
# =============================================================================
# Compatible with: OpenRouter, Groq, Together AI, Mistral, etc.
# OpenRouter: https://openrouter.ai/api/v1
# Groq: https://api.groq.com/openai/v1
# Together: https://api.together.xyz/v1
# Mistral: https://api.mistral.ai/v1
# CUSTOM_OPENAI_API_KEY="your-api-key"
# CUSTOM_OPENAI_BASE_URL="https://openrouter.ai/api/v1"
# ============================================================================= # Email
# EMAIL / SMTP (optional, required for password reset) EMAIL_PROVIDER=resend
# ============================================================================= SMTP_FROM=noreply@memento-note.com
# SMTP_HOST="smtp.gmail.com" RESEND_API_KEY=<secret>
# SMTP_PORT="587" SMTP_HOST=
# SMTP_USER="your-email@gmail.com" SMTP_PORT=
# SMTP_PASS="your-app-password" SMTP_USER=
# SMTP_FROM="noreply@memento.app" SMTP_PASS=<secret>
SMTP_SECURE=
SMTP_IGNORE_CERT=
# ============================================================================= # Google OAuth
# RESEND EMAIL (alternative to SMTP, optional) AUTH_GOOGLE_ID=<var>
# ============================================================================= AUTH_GOOGLE_SECRET=<secret>
# RESEND_API_KEY="re_..."
# ───────────────────────────────────────────────────────────────────────────── # MCP Server
# Brainstorm / Socket.io MCP_MODE=sse
# ───────────────────────────────────────────────────────────────────────────── MCP_PORT=3001
SOCKET_PORT=3005 MCP_SERVER_MODE=sse
MCP_SERVER_URL=https://memento-note.com/mcp
MCP_API_KEY=<secret>
# Web Search
WEB_SEARCH_PROVIDER=searxng
SEARXNG_URL=http://192.168.1.190:8888
BRAVE_SEARCH_API_KEY=<secret>
JINA_API_KEY=<secret>
# Socket (realtime)
SOCKET_INTERNAL_KEY=<secret>
SOCKET_PORT=3002
SOCKET_HTTP_PORT=3003 SOCKET_HTTP_PORT=3003
SOCKET_INTERNAL_KEY=change-this-to-a-random-secret SOCKET_INTERNAL_URL=http://memento-socket:3002
SOCKET_INTERNAL_URL=http://memento-socket:3003 NEXT_PUBLIC_SOCKET_URL=wss://memento-note.com/ws
NEXT_PUBLIC_SOCKET_URL=https://memento-note.com
# Telegram notifications
TELEGRAM_BOT_TOKEN=<secret>
TELEGRAM_CHAT_ID=<var>
# Monitoring
METRICS_TOKEN=<secret>
GRAFANA_ADMIN_PASSWORD=<secret>

View File

@@ -177,8 +177,9 @@ jobs:
MCP_API_KEY: ${{ secrets.MCP_API_KEY }} MCP_API_KEY: ${{ secrets.MCP_API_KEY }}
run: | run: |
ENV_FILE="/opt/memento/.env.docker" ENV_FILE="/opt/memento/.env.docker"
rm -f "$ENV_FILE"
touch "$ENV_FILE" touch "$ENV_FILE"
sed -i 's/\r$//' "$ENV_FILE"
echo "## AUTO-MANAGED BY CI — do not edit manually ##" > "$ENV_FILE"
upsert() { upsert() {
local key="$1" val="$2" local key="$1" val="$2"
[ -z "$val" ] && return [ -z "$val" ] && return
@@ -215,6 +216,8 @@ jobs:
upsert SMTP_IGNORE_CERT "$SMTP_IGNORE_CERT" upsert SMTP_IGNORE_CERT "$SMTP_IGNORE_CERT"
upsert MCP_MODE "$MCP_MODE" upsert MCP_MODE "$MCP_MODE"
upsert MCP_PORT "$MCP_PORT" upsert MCP_PORT "$MCP_PORT"
upsert MCP_SERVER_MODE "$MCP_MODE"
upsert MCP_SERVER_URL "${APP_URL}/mcp"
upsert WEB_SEARCH_PROVIDER "$WEB_SEARCH_PROVIDER" upsert WEB_SEARCH_PROVIDER "$WEB_SEARCH_PROVIDER"
upsert SEARXNG_URL "$SEARXNG_URL" upsert SEARXNG_URL "$SEARXNG_URL"
upsert BRAVE_SEARCH_API_KEY "$BRAVE_SEARCH_API_KEY" upsert BRAVE_SEARCH_API_KEY "$BRAVE_SEARCH_API_KEY"
@@ -233,6 +236,16 @@ jobs:
upsert MCP_API_KEY "$MCP_API_KEY" upsert MCP_API_KEY "$MCP_API_KEY"
# Write metrics token file for Prometheus (same secret) # Write metrics token file for Prometheus (same secret)
[ -n "$METRICS_TOKEN" ] && echo "$METRICS_TOKEN" > /opt/memento/monitoring/metrics-token && chmod 600 /opt/memento/monitoring/metrics-token || true [ -n "$METRICS_TOKEN" ] && echo "$METRICS_TOKEN" > /opt/memento/monitoring/metrics-token && chmod 600 /opt/memento/monitoring/metrics-token || true
# Sanity-check: abort if a critical var is missing
for required in NEXTAUTH_URL NEXTAUTH_SECRET AUTH_GOOGLE_ID AUTH_GOOGLE_SECRET \
AI_PROVIDER_TAGS AI_MODEL_TAGS AI_PROVIDER_EMBEDDING AI_MODEL_EMBEDDING \
AI_PROVIDER_CHAT AI_MODEL_CHAT MCP_SERVER_URL; do
grep -q "^${required}=" "$ENV_FILE" || {
echo "ERROR: required var $required missing in $ENV_FILE — check Gitea vars/secrets"
exit 1
}
done
echo "env.docker sanity-check passed ($(wc -l < "$ENV_FILE") lines)"
- name: Deploy on 192.168.1.190 - name: Deploy on 192.168.1.190
env: env:

View File

@@ -66,8 +66,9 @@ jobs:
MCP_API_KEY: ${{ secrets.MCP_API_KEY }} MCP_API_KEY: ${{ secrets.MCP_API_KEY }}
run: | run: |
ENV_FILE="/opt/memento/.env.docker" ENV_FILE="/opt/memento/.env.docker"
rm -f "$ENV_FILE"
touch "$ENV_FILE" touch "$ENV_FILE"
sed -i 's/\r$//' "$ENV_FILE"
echo "## AUTO-MANAGED BY CI — do not edit manually ##" > "$ENV_FILE"
upsert() { upsert() {
local key="$1" val="$2" local key="$1" val="$2"
[ -z "$val" ] && return [ -z "$val" ] && return
@@ -103,6 +104,8 @@ jobs:
upsert SMTP_IGNORE_CERT "$SMTP_IGNORE_CERT" upsert SMTP_IGNORE_CERT "$SMTP_IGNORE_CERT"
upsert MCP_MODE "$MCP_MODE" upsert MCP_MODE "$MCP_MODE"
upsert MCP_PORT "$MCP_PORT" upsert MCP_PORT "$MCP_PORT"
upsert MCP_SERVER_MODE "$MCP_MODE"
upsert MCP_SERVER_URL "${APP_URL}/mcp"
upsert WEB_SEARCH_PROVIDER "$WEB_SEARCH_PROVIDER" upsert WEB_SEARCH_PROVIDER "$WEB_SEARCH_PROVIDER"
upsert SEARXNG_URL "$SEARXNG_URL" upsert SEARXNG_URL "$SEARXNG_URL"
upsert BRAVE_SEARCH_API_KEY "$BRAVE_SEARCH_API_KEY" upsert BRAVE_SEARCH_API_KEY "$BRAVE_SEARCH_API_KEY"
@@ -121,6 +124,16 @@ jobs:
upsert GRAFANA_ADMIN_PASSWORD "$GRAFANA_ADMIN_PASSWORD" upsert GRAFANA_ADMIN_PASSWORD "$GRAFANA_ADMIN_PASSWORD"
upsert MCP_API_KEY "$MCP_API_KEY" upsert MCP_API_KEY "$MCP_API_KEY"
[ -n "$METRICS_TOKEN" ] && echo "$METRICS_TOKEN" > /opt/memento/monitoring/metrics-token && chmod 600 /opt/memento/monitoring/metrics-token || true [ -n "$METRICS_TOKEN" ] && echo "$METRICS_TOKEN" > /opt/memento/monitoring/metrics-token && chmod 600 /opt/memento/monitoring/metrics-token || true
# Sanity-check: abort if a critical var is missing
for required in NEXTAUTH_URL NEXTAUTH_SECRET AUTH_GOOGLE_ID AUTH_GOOGLE_SECRET \
AI_PROVIDER_TAGS AI_MODEL_TAGS AI_PROVIDER_EMBEDDING AI_MODEL_EMBEDDING \
AI_PROVIDER_CHAT AI_MODEL_CHAT MCP_SERVER_URL; do
grep -q "^${required}=" "$ENV_FILE" || {
echo "ERROR: required var $required missing in $ENV_FILE — check Gitea vars/secrets"
exit 1
}
done
echo "env.docker sanity-check passed ($(wc -l < "$ENV_FILE") lines)"
- name: Deploy (full build, no CI artifact) - name: Deploy (full build, no CI artifact)
env: env:

View File

@@ -127,9 +127,16 @@ HEALTH_CHECK_SLEEP_SECONDS=5
cd "$ROOT" cd "$ROOT"
# Sanitize .env.docker: Docker Compose v2 rejects ANY quote character # Pre-deploy sanity-check: .env.docker must have critical vars
if [ -f "$ROOT/.env.docker" ]; then if [ -f "$ROOT/.env.docker" ]; then
tr -d '"' < "$ROOT/.env.docker" > "$ROOT/.env.docker.tmp" && mv "$ROOT/.env.docker.tmp" "$ROOT/.env.docker" sed -i 's/\r$//' "$ROOT/.env.docker"
for required in NEXTAUTH_URL NEXTAUTH_SECRET AUTH_GOOGLE_ID AUTH_GOOGLE_SECRET; do
grep -q "^${required}=" "$ROOT/.env.docker" || {
echo "ERROR: $required missing in .env.docker — aborting deploy"
telegram_notify "failure" "Missing $required in .env.docker"
exit 1
}
done
fi fi
load_env_docker load_env_docker