Skip to main content

Deployment Guide

Overview

This guide covers deployment strategies, environment setup, and best practices for deploying the www application in different environments.

Deployment Architecture

Infrastructure Components

  • Web Server: Node.js application server
  • Reverse Proxy: Nginx for load balancing and SSL termination
  • Database/Cache: Redis for session storage and caching
  • Container Platform: Docker and Docker Compose

Environment Structure

┌─ Production ─┐    ┌─ Staging ─┐    ┌─ Development ─┐
│ Live App │ │ Testing │ │ Local │
│ Real Data │ │ Sandbox │ │ Hot Reload │
│ SSL/CDN │ │ Testing │ │ Debug Mode │
└──────────────┘ └───────────┘ └──────────────┘

Docker Deployment

Docker Configuration

Located in docker/www/Dockerfile:

FROM node:20.11.1-alpine

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production

# Copy application code
COPY . .

# Build assets
RUN npm run build

# Expose port
EXPOSE 8081

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8081/health || exit 1

# Start application
CMD ["npm", "start"]

Docker Compose Setup

# docker-compose.yml
version: '3.8'

services:
www:
build:
context: ./www
dockerfile: ../docker/www/Dockerfile
ports:
- "8081:8081"
environment:
- NODE_ENV=production
- REDIS_URL=redis://redis:6379
depends_on:
- redis
restart: unless-stopped
volumes:
- ./logs:/app/logs

redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: unless-stopped

nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- www
restart: unless-stopped

volumes:
redis_data:

Environment Setup

Production Environment

Prerequisites

  • Docker and Docker Compose
  • SSL certificates
  • Domain name configuration
  • Environment variables configured

Deployment Steps

# 1. Clone repository
git clone <repository-url>
cd tunnelflight

# 2. Set up environment variables
cp .env.example .env.production
# Edit .env.production with production values

# 3. Build and start services
docker-compose -f docker-compose.prod.yml up -d

# 4. Verify deployment
docker-compose ps
curl -f http://localhost:8081/health

Staging Environment

Configuration

# Staging-specific environment
NODE_ENV=staging
APP_PORT=8082
REDIS_URL=redis://staging-redis:6379

# Build and deploy
docker-compose -f docker-compose.staging.yml up -d

Development Environment

Local Setup

# Install dependencies
cd www
npm install

# Set up local environment
cp .env.example .env
# Edit .env with development values

# Start development server
npm run dev

Nginx Configuration

Reverse Proxy Setup

# /etc/nginx/sites-available/tunnelflight
server {
listen 80;
listen 443 ssl http2;
server_name yourdomain.com;

# SSL Configuration
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

# Security Headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

# Gzip Compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

# Static Assets
location /css/ {
alias /var/www/tunnelflight/public/css/;
expires 1y;
add_header Cache-Control "public, immutable";
}

location /js/ {
alias /var/www/tunnelflight/public/js/;
expires 1y;
add_header Cache-Control "public, immutable";
}

location /img/ {
alias /var/www/tunnelflight/public/img/;
expires 1y;
add_header Cache-Control "public, immutable";
}

# Proxy to Node.js App
location / {
proxy_pass http://www:8081;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}

# Health Check
location /health {
proxy_pass http://www:8081/health;
access_log off;
}
}

Environment Variables

Production Variables

# Application
NODE_ENV=production
APP_PORT=8081
IS_PRODUCTION=true

# Database/Cache
REDIS_URL=redis://prod-redis:6379
REDIS_PASSWORD=secure_redis_password

# Authentication
JWT_SECRET=your_production_jwt_secret
GOOGLE_CLIENT_ID=prod_google_client_id
GOOGLE_CLIENT_SECRET=prod_google_client_secret

# External Services
INFISICAL_CLIENT_ID=prod_infisical_client_id
INFISICAL_CLIENT_SECRET=prod_infisical_client_secret
INFISICAL_PROJECT_ID=prod_project_id

# Monitoring
LOG_LEVEL=info
SENTRY_DSN=your_sentry_dsn

Staging Variables

# Application
NODE_ENV=staging
APP_PORT=8082

# Use staging credentials and endpoints
GOOGLE_CLIENT_ID=staging_google_client_id
API_BASE_URL=https://staging-api.yourdomain.com

CI/CD Pipeline

GitHub Actions Example

# .github/workflows/deploy.yml
name: Deploy to Production

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20.11.1'
cache: 'npm'
cache-dependency-path: www/package-lock.json

- name: Install dependencies
run: |
cd www
npm ci

- name: Run tests
run: |
cd www
npm test

- name: Build assets
run: |
cd www
npm run build

- name: Build Docker image
run: docker build -t tunnelflight-www:${{ github.sha }} -f docker/www/Dockerfile ./www

- name: Deploy to production
run: |
# Deploy logic (e.g., push to registry, update services)
echo "Deploying to production..."

Health Checks and Monitoring

Application Health Check

// Health check endpoint
app.get('/health', (req, res) => {
const health = {
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
version: process.env.npm_package_version,
environment: process.env.NODE_ENV
};

// Check Redis connection
redisClient.ping((err, result) => {
if (err) {
health.status = 'unhealthy';
health.redis = 'disconnected';
} else {
health.redis = 'connected';
}

const statusCode = health.status === 'healthy' ? 200 : 503;
res.status(statusCode).json(health);
});
});

Docker Health Check

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8081/health || exit 1

Monitoring Integration

  • Application Monitoring: Sentry for error tracking
  • Performance Monitoring: APM tools integration
  • Log Aggregation: Centralized logging setup
  • Uptime Monitoring: External service monitoring

SSL/TLS Configuration

Certificate Management

# Let's Encrypt with Certbot
certbot --nginx -d yourdomain.com

# Or manual certificate installation
sudo cp cert.pem /etc/nginx/ssl/
sudo cp private.key /etc/nginx/ssl/

SSL Best Practices

  • Use TLS 1.2 or higher
  • Strong cipher suites
  • HSTS headers
  • Certificate auto-renewal

Database Migrations and Seeding

Redis Data Management

# Backup Redis data
redis-cli --rdb /backup/dump.rdb

# Restore Redis data
redis-cli --pipe < /backup/restore.redis

Data Seeding

# Seed initial data
npm run seed:production

Troubleshooting

Common Deployment Issues

Container Won't Start

# Check container logs
docker-compose logs www

# Verify environment variables
docker-compose exec www env | grep NODE_ENV

Redis Connection Issues

# Test Redis connectivity
docker-compose exec www redis-cli -h redis ping

# Check Redis logs
docker-compose logs redis

Nginx Configuration Issues

# Test Nginx configuration
docker-compose exec nginx nginx -t

# Reload Nginx configuration
docker-compose exec nginx nginx -s reload

Performance Optimization

Application Optimization

  • Enable gzip compression
  • Optimize asset loading
  • Implement caching strategies
  • Monitor memory usage

Database Optimization

  • Redis memory optimization
  • Connection pooling
  • Query optimization
  • Index management

Rollback Procedures

Application Rollback

# Tag current version before deployment
docker tag tunnelflight-www:latest tunnelflight-www:backup

# Rollback to previous version
docker-compose down
docker-compose up -d tunnelflight-www:previous-version

Database Rollback

# Restore Redis from backup
redis-cli flushall
redis-cli --pipe < /backup/previous-state.redis