diff --git a/.env.example b/.env.example index b281a558..53e81c1f 100644 --- a/.env.example +++ b/.env.example @@ -40,6 +40,14 @@ MAIL_RECIPIENTS=info@klz-cables.com # ──────────────────────────────────────────────────────────────────────────── LOG_LEVEL=info +# ──────────────────────────────────────────────────────────────────────────── +# Deployment Configuration (CI/CD only) +# ──────────────────────────────────────────────────────────────────────────── +# These are typically set by the CI/CD workflow +IMAGE_TAG=latest +TRAEFIK_HOST=klz-cables.com +ENV_FILE=.env + # ──────────────────────────────────────────────────────────────────────────── # Varnish Cache (Docker only) # ──────────────────────────────────────────────────────────────────────────── @@ -61,7 +69,11 @@ VARNISH_CACHE_SIZE=256m # ────────────────── # 1. Build-time: Only NEXT_PUBLIC_* vars are needed (via --build-arg) # 2. Runtime: All vars are loaded from .env file on the server -# 3. The .env file should exist at: /home/deploy/sites/klz-cables.com/.env +# 3. Branch Deployments: +# - main branch uses .env.prod +# - staging branch uses .env.staging +# - CI/CD supports STAGING_ prefix for all secrets to override defaults +# - TRAEFIK_HOST is automatically derived from NEXT_PUBLIC_BASE_URL # # Security: # ───────── diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index b3b473c5..2f1e264a 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -67,15 +67,21 @@ jobs: MAIL_RECIPIENTS: ${{ github.ref_name == 'main' && secrets.MAIL_RECIPIENTS || (secrets.STAGING_MAIL_RECIPIENTS || secrets.MAIL_RECIPIENTS) }} run: | BRANCH=${{ github.ref_name }} + + # Derive domain from NEXT_PUBLIC_BASE_URL (strip https:// and trailing slash) + DOMAIN=$(echo "$NEXT_PUBLIC_BASE_URL" | sed -E 's|https?://||' | sed -E 's|/.*||') + if [ "$BRANCH" = "main" ]; then ENV_FILE=.env.prod - TRAEFIK_HOST="klz-cables.com, www.klz-cables.com" + # For production, we want both root and www + TRAEFIK_HOST="\`$DOMAIN\`, \`www.$DOMAIN\`" else ENV_FILE=.env.staging - TRAEFIK_HOST="staging.klz-cables.com" + TRAEFIK_HOST="\`$DOMAIN\`" fi echo "🚀 Deploying branch $BRANCH to $ENV_FILE..." + echo "🌐 Domain: $DOMAIN" # Setup SSH mkdir -p ~/.ssh diff --git a/README.md b/README.md index 7dda3a0f..f42cea76 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ app/ ├── api/ │ └── contact/route.ts # Contact API ├── sitemap.ts # Sitemap generator -└── robots.ts # Robots.txt generator +├── robots.ts # Robots.txt generator lib/ ├── data.ts # Data access @@ -114,7 +114,7 @@ components/ ├── LocaleSwitcher.tsx # Language switcher ├── ContactForm.tsx # Contact form ├── CookieConsent.tsx # GDPR banner -└── SEO.tsx # SEO utilities +├── SEO.tsx # SEO utilities data/ ├── raw/ # WordPress export @@ -222,21 +222,30 @@ GET /robots.txt ### Automatic Deployment (Current Setup) -The project uses **Gitea Actions** for CI/CD. Every push to `main` triggers: +The project uses **Gitea Actions** for CI/CD. Every push to `main` or `staging` triggers: -1. **Build**: Docker image built for `linux/arm64` -2. **Push**: Image pushed to `registry.infra.mintel.me` -3. **Deploy**: SSH to production server, pull and restart containers +1. **Build**: Docker image built for `linux/arm64` with branch-specific build args +2. **Push**: Image pushed to `registry.infra.mintel.me` with commit SHA tag +3. **Deploy**: SSH to production server, pull and restart containers using branch-specific `.env` files **Workflow**: `.gitea/workflows/deploy.yml` +**Branch Deployments**: +- `main` branch: Deploys to production using `.env.prod` +- `staging` branch: Deploys to staging using `.env.staging` + +**Environment Overrides**: +The CI/CD workflow supports `STAGING_`-prefixed secrets (e.g., `STAGING_NEXT_PUBLIC_BASE_URL`) to override default secrets when deploying the `staging` branch. + **Required Secrets** (configure in Gitea repository settings): - `REGISTRY_USER` - Docker registry username - `REGISTRY_PASS` - Docker registry password - `ALPHA_SSH_KEY` - SSH private key for deployment +- `NEXT_PUBLIC_BASE_URL` - Application base URL (e.g., `https://klz-cables.com`) - `NEXT_PUBLIC_UMAMI_WEBSITE_ID` - Analytics ID - `NEXT_PUBLIC_UMAMI_SCRIPT_URL` - Analytics script URL - `SENTRY_DSN` - Error tracking DSN +- `MAIL_HOST`, `MAIL_PORT`, `MAIL_USERNAME`, `MAIL_PASSWORD`, `MAIL_FROM`, `MAIL_RECIPIENTS` - Email configuration ### Manual Deployment diff --git a/docker-compose.yml b/docker-compose.yml index 39cd00b1..3698f13a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,11 +11,11 @@ services: labels: - "traefik.enable=true" # HTTP ⇒ HTTPS redirect - - "traefik.http.routers.klz-cables-web.rule=Host(`${TRAEFIK_HOST}`) && !PathPrefix(`/.well-known/acme-challenge/`)" + - "traefik.http.routers.klz-cables-web.rule=Host(${TRAEFIK_HOST}) && !PathPrefix(`/.well-known/acme-challenge/`)" - "traefik.http.routers.klz-cables-web.entrypoints=web" - "traefik.http.routers.klz-cables-web.middlewares=redirect-https" # HTTPS router - - "traefik.http.routers.klz-cables.rule=Host(`${TRAEFIK_HOST}`)" + - "traefik.http.routers.klz-cables.rule=Host(${TRAEFIK_HOST})" - "traefik.http.routers.klz-cables.entrypoints=websecure" - "traefik.http.routers.klz-cables.tls.certresolver=le" - "traefik.http.routers.klz-cables.tls=true"