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:
@@ -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>
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user