# Server Setup Guide - KLZ Cables This guide explains how to set up the production environment on the deployment server. ## Prerequisites - Server: `alpha.mintel.me` - User: `deploy` (with sudo access) - Docker and Docker Compose installed - Traefik reverse proxy running - External network `infra` created ## Initial Server Setup ### 1. Create Project Directory ```bash # SSH to the server as root or deploy user ssh root@alpha.mintel.me # Create project directory mkdir -p /home/deploy/sites/klz-cables.com cd /home/deploy/sites/klz-cables.com ``` ### 2. Create Environment File Create the `.env` file with production configuration: ```bash # Create .env file from template cat > /home/deploy/sites/klz-cables.com/.env << 'EOF' # ============================================================================ # KLZ Cables - Production Environment Configuration # ============================================================================ # Application NODE_ENV=production NEXT_PUBLIC_BASE_URL=https://klz-cables.com # Analytics (Umami) NEXT_PUBLIC_UMAMI_WEBSITE_ID=your-umami-website-id NEXT_PUBLIC_UMAMI_SCRIPT_URL=https://analytics.infra.mintel.me/script.js # Error Tracking (GlitchTip/Sentry) SENTRY_DSN=https://your-sentry-dsn@errors.infra.mintel.me/project-id # Email Configuration (Mailgun) MAIL_HOST=smtp.eu.mailgun.org MAIL_PORT=587 MAIL_USERNAME=your-mailgun-username MAIL_PASSWORD=your-mailgun-password MAIL_FROM=KLZ Cables MAIL_RECIPIENTS=info@klz-cables.com # Redis Cache REDIS_URL=redis://redis:6379/2 REDIS_KEY_PREFIX=klz: EOF ``` **Important**: Replace all placeholder values with actual production credentials. ### 3. Secure the Environment File ```bash # Set proper permissions (readable only by owner) chmod 600 /home/deploy/sites/klz-cables.com/.env # Verify ownership chown deploy:deploy /home/deploy/sites/klz-cables.com/.env # Verify permissions ls -la /home/deploy/sites/klz-cables.com/.env # Should show: -rw------- 1 deploy deploy ``` ### 4. Create Docker Compose File ```bash # Copy docker-compose.yml from repository # This should be done automatically by the deployment script # Or manually: cat > /home/deploy/sites/klz-cables.com/docker-compose.yml << 'EOF' services: app: image: registry.infra.mintel.me/mintel/klz-cables.com:latest restart: always networks: - infra ports: - "3000:3000" env_file: - .env healthcheck: test: ["CMD-SHELL", "wget --quiet --tries=1 --spider http://localhost:3000/health || wget --quiet --tries=1 --spider http://localhost:3000/ || true"] interval: 10s 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: external: true EOF ``` ### 5. Create Deployment Script ```bash cat > /home/deploy/deploy.sh << 'EOF' #!/bin/bash set -e PROJECT_DIR="/home/deploy/sites/klz-cables.com" echo "╔══════════════════════════════════════════════════════════════════════════════╗" echo "║ KLZ Cables - Deployment Script ║" echo "╚══════════════════════════════════════════════════════════════════════════════╝" echo "" cd "$PROJECT_DIR" # Check if .env file exists if [ ! -f .env ]; then echo "❌ ERROR: .env file not found at $PROJECT_DIR/.env" echo "Please create the .env file before deploying." exit 1 fi echo "🔐 Logging into Docker registry..." echo "$REGISTRY_PASS" | docker login registry.infra.mintel.me -u "$REGISTRY_USER" --password-stdin echo "🔄 Pulling latest image..." docker pull registry.infra.mintel.me/mintel/klz-cables.com:latest echo "🔄 Stopping existing containers..." docker-compose down echo "🚀 Starting new containers..." docker-compose up -d echo "⏳ Waiting for services to be healthy..." sleep 10 echo "🔍 Checking service status..." docker-compose ps echo "" echo "✅ Deployment complete!" echo "" echo "📊 Service URLs:" echo " • Production: https://klz-cables.com" echo " • Staging: https://staging.klz-cables.com" echo "" EOF # Make script executable chmod +x /home/deploy/deploy.sh ``` ### 6. Configure Docker Registry Access The deployment script needs registry credentials. These are passed as environment variables from the CI/CD workflow: ```bash # The workflow passes these variables: # REGISTRY_USER - from Gitea secrets # REGISTRY_PASS - from Gitea secrets ``` ## Verification ### Check Environment File ```bash # Verify .env file exists and has correct permissions ls -la /home/deploy/sites/klz-cables.com/.env # Check content (be careful not to expose secrets in logs) head -n 5 /home/deploy/sites/klz-cables.com/.env ``` ### Test Deployment Script ```bash # Run deployment script manually (requires registry credentials) REGISTRY_USER=your-user REGISTRY_PASS=your-pass /home/deploy/deploy.sh ``` ### Check Running Containers ```bash cd /home/deploy/sites/klz-cables.com docker-compose ps docker-compose logs -f app ``` ### Verify Environment Variables in Container ```bash # Check that environment variables are loaded docker-compose exec app env | grep -E "NODE_ENV|NEXT_PUBLIC|MAIL|REDIS" ``` ## Updating Environment Variables When you need to update environment variables: ```bash # 1. SSH to the server ssh root@alpha.mintel.me # 2. Edit the .env file nano /home/deploy/sites/klz-cables.com/.env # 3. Restart the containers to pick up changes cd /home/deploy/sites/klz-cables.com docker-compose down docker-compose up -d # 4. Verify the changes docker-compose logs -f app ``` **Note**: Changes to `NEXT_PUBLIC_*` variables require rebuilding the Docker image, as they are baked into the client bundle at build time. ## Troubleshooting ### .env File Not Found ```bash # Check if file exists ls -la /home/deploy/sites/klz-cables.com/.env # If missing, create it from template cp .env.production /home/deploy/sites/klz-cables.com/.env # Then edit with actual values ``` ### Permission Denied ```bash # Fix ownership chown -R deploy:deploy /home/deploy/sites/klz-cables.com # Fix .env permissions chmod 600 /home/deploy/sites/klz-cables.com/.env ``` ### Container Won't Start ```bash # Check logs docker-compose logs app # Check if .env is loaded docker-compose config # Verify environment variables docker-compose exec app env ``` ### Network Issues ```bash # Verify infra network exists docker network ls | grep infra # If missing, create it docker network create infra ``` ## Security Checklist - [ ] `.env` file has `600` permissions (readable only by owner) - [ ] `.env` file is owned by `deploy:deploy` - [ ] `.env` file is NOT in git repository - [ ] All sensitive credentials are filled in - [ ] SSH keys are properly secured - [ ] Firewall rules are configured - [ ] HTTPS is enforced via Traefik - [ ] Regular backups of `.env` file are maintained ## Backup Create a secure backup of the environment file: ```bash # Backup .env file cp /home/deploy/sites/klz-cables.com/.env \ /home/deploy/backups/klz-cables.env.$(date +%Y%m%d) # Set proper permissions on backup chmod 600 /home/deploy/backups/klz-cables.env.* ``` ## Additional Resources - [Deployment Guide](./DEPLOYMENT.md) - [Docker Compose Documentation](https://docs.docker.com/compose/) - [Traefik Documentation](https://doc.traefik.io/traefik/)