diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index c5907807..0fa4e611 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -170,8 +170,6 @@ jobs: REDIS_URL=${{ secrets.REDIS_URL }} REDIS_KEY_PREFIX=${{ secrets.REDIS_KEY_PREFIX }} - # Varnish Cache Size - VARNISH_CACHE_SIZE=256m EOF echo "✅ Environment file prepared" @@ -230,14 +228,14 @@ jobs: echo "⏳ Waiting for services to be healthy..." MAX_RETRIES=12 RETRY_COUNT=0 - until curl -s -f http://localhost:3000/health > /dev/null || [ $RETRY_COUNT -eq $MAX_RETRIES ]; do - echo " • Waiting for health check... ($((RETRY_COUNT + 1))/$MAX_RETRIES)" + until curl -s -f http://localhost:3000/health > /dev/null || [ \$RETRY_COUNT -eq \$MAX_RETRIES ]; do + echo " • Waiting for health check... (\$((RETRY_COUNT + 1))/\$MAX_RETRIES)" sleep 5 - RETRY_COUNT=$((RETRY_COUNT + 1)) + RETRY_COUNT=\$((RETRY_COUNT + 1)) done - if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then - echo "❌ Health check failed after $MAX_RETRIES retries" + if [ \$RETRY_COUNT -eq \$MAX_RETRIES ]; then + echo "❌ Health check failed after \$MAX_RETRIES retries" echo "🔍 Container logs:" docker-compose logs --tail=50 exit 1 diff --git a/README.md b/README.md index c467646e..4390287d 100644 --- a/README.md +++ b/README.md @@ -266,7 +266,7 @@ bash scripts/deploy-webhook.sh ### Architecture ``` -Client → Traefik (TLS) → Varnish (Cache) → Next.js App +Client → Traefik (TLS) → Next.js App ``` **Domains**: @@ -276,7 +276,6 @@ Client → Traefik (TLS) → Varnish (Cache) → Next.js App **Services**: - `app`: Next.js application (port 3000) -- `varnish`: HTTP cache layer - `traefik`: Reverse proxy (external) For detailed deployment documentation, see [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md). diff --git a/docker-compose.yml b/docker-compose.yml index de4afbd5..3a906539 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,55 +1,11 @@ services: - # Varnish sits between Traefik and the application. - # - # Flow: - # Client -> Traefik -> Varnish -> app - # - # Traefik keeps TLS + compression; Varnish adds HTTP caching for static assets. - varnish: - image: varnish:7 - restart: always - networks: - - infra - depends_on: - - app - command: >- - varnishd - -F - -f /etc/varnish/default.vcl - -s malloc,${VARNISH_CACHE_SIZE:-256m} - volumes: - - ./varnish/default.vcl:/etc/varnish/default.vcl:ro - healthcheck: - test: ["CMD-SHELL", "wget --quiet --tries=1 --spider http://localhost:80/health || wget --quiet --tries=1 --spider http://localhost:80/ || true"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - labels: - - "traefik.enable=true" - # HTTP → HTTPS redirect (Challenge-Schutz für ALLE) - - "traefik.http.routers.klz-cables-web.rule=(Host(`klz-cables.com`) || Host(`www.klz-cables.com`) || Host(`staging.klz-cables.com`)) && !PathPrefix(`/.well-known/acme-challenge/`)" - - "traefik.http.routers.klz-cables-web.entrypoints=web" - - "traefik.http.routers.klz-cables-web.middlewares=redirect-https" - # HTTPS router (für ALLE drei Domains) - - "traefik.http.routers.klz-cables.rule=Host(`klz-cables.com`) || Host(`www.klz-cables.com`) || Host(`staging.klz-cables.com`)" - - "traefik.http.routers.klz-cables.entrypoints=websecure" - - "traefik.http.routers.klz-cables.tls.certresolver=le" - - "traefik.http.routers.klz-cables.tls=true" - - "traefik.http.routers.klz-cables.service=klz-cables" - - "traefik.http.services.klz-cables.loadbalancer.server.port=80" - - "traefik.http.services.klz-cables.loadbalancer.server.scheme=http" - # Forwarded Headers (für Apps, die HTTPS erwarten) - - "traefik.http.middlewares.klz-forward.headers.customrequestheaders.X-Forwarded-Proto=https" - - "traefik.http.middlewares.klz-forward.headers.customrequestheaders.X-Forwarded-Ssl=on" - # Middlewares anhängen - - "traefik.http.routers.klz-cables.middlewares=klz-forward,compress" - app: image: registry.infra.mintel.me/mintel/klz-cables.com:latest restart: always networks: - infra + ports: + - "3000:3000" env_file: - .env healthcheck: @@ -58,6 +14,25 @@ services: timeout: 5s retries: 5 start_period: 30s + labels: + - "traefik.enable=true" + # HTTP ⇒ HTTPS redirect + - "traefik.http.routers.klz-cables-web.rule=(Host(`klz-cables.com`) || Host(`www.klz-cables.com`) || Host(`staging.klz-cables.com`)) && !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(`klz-cables.com`) || Host(`www.klz-cables.com`) || Host(`staging.klz-cables.com`)" + - "traefik.http.routers.klz-cables.entrypoints=websecure" + - "traefik.http.routers.klz-cables.tls.certresolver=le" + - "traefik.http.routers.klz-cables.tls=true" + - "traefik.http.routers.klz-cables.service=klz-cables" + - "traefik.http.services.klz-cables.loadbalancer.server.port=3000" + - "traefik.http.services.klz-cables.loadbalancer.server.scheme=http" + # Forwarded Headers + - "traefik.http.middlewares.klz-forward.headers.customrequestheaders.X-Forwarded-Proto=https" + - "traefik.http.middlewares.klz-forward.headers.customrequestheaders.X-Forwarded-Ssl=on" + # Middlewares + - "traefik.http.routers.klz-cables.middlewares=klz-forward,compress" networks: infra: diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index 55424b15..06269c1b 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -36,8 +36,7 @@ The application uses a clean, robust, **fully automated** environment variable s │ │ │ /home/deploy/sites/klz-cables.com/ │ │ ├── .env ← Runtime environment vars │ -│ ├── docker-compose.yml ← Loads .env file │ -│ └── varnish/ │ +│ └── docker-compose.yml ← Loads .env file │ └─────────────────────────────────────────────────────────────┘ ``` @@ -71,7 +70,6 @@ These are loaded from the `.env` file at runtime and are only available on the s | `MAIL_RECIPIENTS` | ❌ No | Comma-separated list of recipient emails | | `REDIS_URL` | ❌ No | Redis connection URL (e.g., `redis://redis:6379/2`) | | `REDIS_KEY_PREFIX` | ❌ No | Redis key prefix (default: `klz:`) | -| `VARNISH_CACHE_SIZE` | ❌ No | Varnish cache size (default: `256m`) | ## Local Development diff --git a/docs/SERVER_SETUP.md b/docs/SERVER_SETUP.md index 3b12afce..0c689046 100644 --- a/docs/SERVER_SETUP.md +++ b/docs/SERVER_SETUP.md @@ -56,9 +56,6 @@ MAIL_RECIPIENTS=info@klz-cables.com # Redis Cache REDIS_URL=redis://redis:6379/2 REDIS_KEY_PREFIX=klz: - -# Varnish Cache Size -VARNISH_CACHE_SIZE=256m EOF ``` @@ -86,47 +83,13 @@ ls -la /home/deploy/sites/klz-cables.com/.env # Or manually: cat > /home/deploy/sites/klz-cables.com/docker-compose.yml << 'EOF' services: - varnish: - image: varnish:7 - restart: always - networks: - - infra - depends_on: - - app - command: >- - varnishd - -F - -f /etc/varnish/default.vcl - -s malloc,${VARNISH_CACHE_SIZE:-256m} - volumes: - - ./varnish/default.vcl:/etc/varnish/default.vcl:ro - healthcheck: - test: ["CMD-SHELL", "wget --quiet --tries=1 --spider http://localhost:80/health || wget --quiet --tries=1 --spider http://localhost:80/ || true"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - labels: - - "traefik.enable=true" - - "traefik.http.routers.klz-cables-web.rule=(Host(\`klz-cables.com\`) || Host(\`www.klz-cables.com\`) || Host(\`staging.klz-cables.com\`)) && !PathPrefix(\`/.well-known/acme-challenge/\`)" - - "traefik.http.routers.klz-cables-web.entrypoints=web" - - "traefik.http.routers.klz-cables-web.middlewares=redirect-https" - - "traefik.http.routers.klz-cables.rule=Host(\`klz-cables.com\`) || Host(\`www.klz-cables.com\`) || Host(\`staging.klz-cables.com\`)" - - "traefik.http.routers.klz-cables.entrypoints=websecure" - - "traefik.http.routers.klz-cables.tls.certresolver=le" - - "traefik.http.routers.klz-cables.tls=true" - - "traefik.http.routers.klz-cables.service=klz-cables" - - "traefik.http.services.klz-cables.loadbalancer.server.port=80" - - "traefik.http.services.klz-cables.loadbalancer.server.scheme=http" - - "traefik.http.middlewares.klz-forward.headers.customrequestheaders.X-Forwarded-Proto=https" - - "traefik.http.middlewares.klz-forward.headers.customrequestheaders.X-Forwarded-Ssl=on" - - "traefik.http.routers.klz-cables.middlewares=klz-forward,compress" - app: image: registry.infra.mintel.me/mintel/klz-cables.com:latest restart: always networks: - infra + ports: + - "3000:3000" env_file: - .env healthcheck: @@ -135,6 +98,21 @@ services: timeout: 5s retries: 5 start_period: 30s + labels: + - "traefik.enable=true" + - "traefik.http.routers.klz-cables-web.rule=(Host(`klz-cables.com`) || Host(`www.klz-cables.com`) || Host(`staging.klz-cables.com`)) && !PathPrefix(`/.well-known/acme-challenge/`)" + - "traefik.http.routers.klz-cables-web.entrypoints=web" + - "traefik.http.routers.klz-cables-web.middlewares=redirect-https" + - "traefik.http.routers.klz-cables.rule=Host(`klz-cables.com`) || Host(`www.klz-cables.com`) || Host(`staging.klz-cables.com`)" + - "traefik.http.routers.klz-cables.entrypoints=websecure" + - "traefik.http.routers.klz-cables.tls.certresolver=le" + - "traefik.http.routers.klz-cables.tls=true" + - "traefik.http.routers.klz-cables.service=klz-cables" + - "traefik.http.services.klz-cables.loadbalancer.server.port=3000" + - "traefik.http.services.klz-cables.loadbalancer.server.scheme=http" + - "traefik.http.middlewares.klz-forward.headers.customrequestheaders.X-Forwarded-Proto=https" + - "traefik.http.middlewares.klz-forward.headers.customrequestheaders.X-Forwarded-Ssl=on" + - "traefik.http.routers.klz-cables.middlewares=klz-forward,compress" networks: infra: @@ -142,17 +120,7 @@ networks: EOF ``` -### 5. Create Varnish Configuration - -```bash -# Create varnish directory -mkdir -p /home/deploy/sites/klz-cables.com/varnish - -# Copy varnish configuration from repository -# This should be in the repository at varnish/default.vcl -``` - -### 6. Create Deployment Script +### 5. Create Deployment Script ```bash cat > /home/deploy/deploy.sh << 'EOF' @@ -162,7 +130,7 @@ set -e PROJECT_DIR="/home/deploy/sites/klz-cables.com" echo "╔══════════════════════════════════════════════════════════════════════════════╗" -echo "║ KLZ Cables - Deployment Script ║" +echo "║ KLZ Cables - Deployment Script ║" echo "╚══════════════════════════════════════════════════════════════════════════════╝" echo "" @@ -206,7 +174,7 @@ EOF chmod +x /home/deploy/deploy.sh ``` -### 7. Configure Docker Registry Access +### 6. Configure Docker Registry Access The deployment script needs registry credentials. These are passed as environment variables from the CI/CD workflow: diff --git a/varnish/default.vcl b/varnish/default.vcl deleted file mode 100644 index c88eed17..00000000 --- a/varnish/default.vcl +++ /dev/null @@ -1,90 +0,0 @@ -vcl 4.1; - -# Minimal, safe Varnish config for a Next.js-style app. -# - Cache static assets aggressively -# - Avoid caching HTML/auth/api by default -# - Preserve websockets / upgrade - -backend default { - .host = "app"; - .port = "3000"; -} - -sub vcl_recv { - # Health endpoint should always work. - if (req.url == "/health") { - return (pass); - } - - # Websocket / Upgrade should not be cached. - if (req.http.Upgrade ~ "(?i)websocket") { - return (pipe); - } - - # Only cache GET/HEAD. - if (req.method != "GET" && req.method != "HEAD") { - return (pass); - } - - # If cookies are present, do not cache (safe default). - if (req.http.Cookie) { - return (pass); - } - - # Never cache Next.js data requests (often personalized) unless you explicitly want to. - if (req.url ~ "^/_next/data/") { - return (pass); - } - - # Cache immutable build assets. - if (req.url ~ "^/_next/static/") { - unset req.http.Cookie; - return (hash); - } - - # Cache common static files. - if (req.url ~ "\.(?:css|js|mjs|map|png|jpg|jpeg|gif|webp|svg|ico|woff2?|ttf|otf)$") { - unset req.http.Cookie; - return (hash); - } - - # Default: don't cache HTML. - return (pass); -} - -sub vcl_backend_response { - # Cache immutable Next build assets for a long time. - if (bereq.url ~ "^/_next/static/") { - set beresp.ttl = 365d; - set beresp.grace = 1h; - set beresp.http.Cache-Control = "public, max-age=31536000, immutable"; - unset beresp.http.Set-Cookie; - return (deliver); - } - - # Cache static files for 7 days (safe default). - if (bereq.url ~ "\.(?:css|js|mjs|map|png|jpg|jpeg|gif|webp|svg|ico|woff2?|ttf|otf)$") { - set beresp.ttl = 7d; - set beresp.grace = 1h; - if (!beresp.http.Cache-Control) { - set beresp.http.Cache-Control = "public, max-age=604800"; - } - unset beresp.http.Set-Cookie; - return (deliver); - } - - # Everything else: don't cache by default. - set beresp.ttl = 0s; - set beresp.uncacheable = true; - return (deliver); -} - -sub vcl_deliver { - # Helpful debug header; remove if you don't want this visible. - if (obj.hits > 0) { - set resp.http.X-Cache = "HIT"; - } else { - set resp.http.X-Cache = "MISS"; - } -} -