Skip to content

Deployment Overview

High-Level Deployment Architecture

Jubiloop uses a GitHub Actions-centric deployment system that prioritizes simplicity and single source of truth over complex orchestration. Everything flows through GitHub Actions, making it easy for developers to work without deep infrastructure knowledge.

Core Principle: One source of truth (env.deploy.yml) → GitHub Actions → Everywhere

Architecture Components

1. Configuration Management

All deployment configuration is centralized in a single source of truth with dynamic generation scripts:

infra/deploy/
├── env.deploy.yml              # Single source of truth for all configuration
├── scripts/                    # Dynamic configuration generation
│   ├── generate-env-files.js   # Generate .env files from env.deploy.yml
│   ├── extract-config.js       # Extract terraform, ansible, and docs config
│   └── common.js               # Shared utilities for config parsing
├── terraform/                  # Infrastructure as code
├── ansible/                    # Server configuration
├── dev-qa-docker-compose/      # Dev and QA Docker compositions
└── prod-docker-compose/        # Production Docker composition

The env.deploy.yml file is processed by scripts that:

  • Generate environment files for all services dynamically
  • Extract infrastructure configuration for Terraform
  • Create Ansible inventories from Terraform state
  • Document all required secrets and variables
  • Support both auto-generated and explicit secret references

2. Infrastructure Stack

Development/QA Environment (Shared Infrastructure)

┌─────────────────────────────────────────────────────────────┐
│                    Cloudflare                                │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────┐ │
│  │ Cloudflare Pages│  │ Cloudflare Pages│  │   DNS/CDN   │ │
│  │ (Dev Web App)   │  │ (QA Web App)    │  │             │ │
│  └─────────────────┘  └─────────────────┘  └─────────────┘ │
└───────────────────────────┬─────────────────────────────────┘
                            │ API Requests
┌───────────────────────────▼─────────────────────────────────┐
│         DigitalOcean Droplet ($6/month)                      │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              Docker Containers                       │    │
│  │  ┌─────────────────┐  ┌─────────────────┐          │    │
│  │  │   Caddy Proxy   │  │   Caddy Proxy   │          │    │
│  │  │  (dev.domain)   │  │  (qa.domain)    │          │    │
│  │  └────────┬────────┘  └────────┬────────┘          │    │
│  │           │                     │                    │    │
│  │  ┌────────▼────────┐  ┌────────▼────────┐          │    │
│  │  │  Dev API Server │  │  QA API Server  │          │    │
│  │  │   (Port 3333)   │  │   (Port 3334)   │          │    │
│  │  └────────┬────────┘  └────────┬────────┘          │    │
│  │           │                     │                    │    │
│  │  ┌────────▼──────────────────────────────┐         │    │
│  │  │         Database Services              │         │    │
│  │  │  ┌─────────┐  ┌─────────┐  ┌────────┐│         │    │
│  │  │  │Postgres │  │Postgres │  │ Redis  ││         │    │
│  │  │  │  (Dev)  │  │  (QA)   │  │ (Dev)  ││         │    │
│  │  │  └─────────┘  └─────────┘  └────────┘│         │    │
│  │  │              ┌────────┐                │         │    │
│  │  │              │ Redis  │                │         │    │
│  │  │              │  (QA)  │                │         │    │
│  │  │              └────────┘                │         │    │
│  │  └───────────────────────────────────────┘         │    │
│  └─────────────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────────────┘

Production Environment (Dedicated Infrastructure)

┌─────────────────────────────────────────────────────────────┐
│                    Cloudflare                                │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────┐ │
│  │ Cloudflare Pages│  │ Cloudflare Pages│  │   DNS/CDN   │ │
│  │ (Prod Web App)  │  │ (Prod Marketing)│  │             │ │
│  └─────────────────┘  └─────────────────┘  └─────────────┘ │
└───────────────────────────┬─────────────────────────────────┘
                            │ API Requests
┌───────────────────────────▼─────────────────────────────────┐
│         DigitalOcean Droplet ($6/month)                      │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              Docker Containers                       │    │
│  │  ┌─────────────────────────────────────────┐       │    │
│  │  │            Caddy Proxy                   │       │    │
│  │  │         (api.jubiloop.ca)               │       │    │
│  │  └────────────────┬─────────────────────────┘       │    │
│  │                   │                                  │    │
│  │  ┌────────────────▼─────────────────────────┐       │    │
│  │  │         Production API Server            │       │    │
│  │  │            (Port 3333)                   │       │    │
│  │  └────────────────┬─────────────────────────┘       │    │
│  │                   │                                  │    │
│  │  ┌────────────────▼─────────────────────────┐       │    │
│  │  │              Redis Cache                 │       │    │
│  │  └──────────────────────────────────────────┘       │    │
│  └─────────────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────────────┘

                            │ Database Connection
┌───────────────────────────▼─────────────────────────────────┐
│                    Neon Database                             │
│                 (Managed PostgreSQL)                         │
│               Region: US East (Ohio)                         │
└──────────────────────────────────────────────────────────────┘

3. CI/CD Pipeline

Developer Push → GitHub Actions → Build & Test → Deploy

                       ├─→ Terraform (Infrastructure for Backend)
                       ├─→ Docker Build (Backend API only)
                       ├─→ Cloudflare Pages (Frontend Apps)
                       └─→ Ansible (Backend Configuration)

Environment Overview

For detailed environment information including URLs, infrastructure, and costs, see the Environment Reference.

Key Environment Features

Development & QA (Shared Infrastructure):

  • Automatic deployment on branch push
  • Containerized PostgreSQL and Redis
  • Let's Encrypt SSL certificates
  • Isolated services on same server
  • Production-like configuration

Production:

  • Dedicated infrastructure
  • Managed PostgreSQL (Neon)
  • Enhanced security
  • Automated backups
  • Health monitoring

Deployment Flow

1. Configuration Phase

All environment variables and secrets are defined in env.deploy.yml:

yaml
DEV:
  server:
    PORT: 3333
    DATABASE_URL: from_secrets # Auto-generates DEV_SERVER_DATABASE_URL
    APP_KEY: '${{ secrets.DEV_APP_KEY }}' # Explicit secret reference
  webapp:
    REACT_APP_API_URL: 'https://dev-api.jubiloop.ca'

2. Infrastructure Provisioning

Terraform manages infrastructure with state stored in Cloudflare R2:

bash
terraform apply  # Creates/updates infrastructure
# → Provisions DigitalOcean droplets
# → Configures Cloudflare DNS
# → Sets up networking
# → Stores state in R2 bucket

3. Application Build

GitHub Actions builds and packages applications:

bash
# Docker images built and pushed to GitHub Container Registry
docker build -t ghcr.io/org/jubiloop-server:latest .
docker push ghcr.io/org/jubiloop-server:latest

4. Configuration Deployment

Dynamic configuration generation and deployment via Ansible:

bash
# Generate environment files from env.deploy.yml
node scripts/generate-env-files.js DEV --server

# Deploy with Ansible using dynamic inventory
ansible-playbook -i inventory.ini playbook.yml

5. Service Orchestration

Backend services are managed via Docker Compose:

yaml
services:
  caddy: # Reverse proxy with automatic HTTPS for API
  server: # AdonisJS API
  postgres: # Database (dev/qa only, production uses managed DB)
  redis: # Cache layer

Frontend apps are deployed separately to Cloudflare Pages:

  • Web App: Built and deployed via deploy-web-app.yml workflow
  • Marketing: Built and deployed via deploy-marketing.yml workflow

Key Features

Dynamic Configuration System

  • Single Source of Truth: All configuration in env.deploy.yml
  • Automatic Secret Management: Generates secret names from patterns
  • Environment Inheritance: Share common configs across environments
  • Validation: Built-in configuration validation and documentation

Infrastructure State Management

Terraform → Cloudflare R2 → Application Deployment
    │              │                │
    └── Creates ───┴── Stores IP ──┴── Reads State
  • No hardcoded server addresses
  • Dynamic inventory generation
  • State-driven deployments

Security Architecture

  1. Network Security

    • Cloudflare DDoS protection
    • Firewall rules via DigitalOcean
    • Internal Docker networks
    • SSL/TLS everywhere
  2. Application Security

    • Environment variable isolation
    • Secrets never in code
    • Automated security updates
    • Fail2ban for intrusion prevention
  3. Access Control

    • SSH key-based authentication
    • Deploy user with minimal permissions
    • GitHub Actions OIDC for cloud access
    • Role-based deployment permissions

Monitoring and Observability

  • Health Checks: Application and infrastructure health endpoints
  • Logging: Centralized Docker logging with rotation
  • Metrics: Resource usage and performance monitoring
  • Alerting: Automated alerts for failures

Deployment Automation

GitHub Actions Workflows

  1. Infrastructure Deployment (terraform-deploy.yml)

    • Manual trigger with environment selection
    • Plans and applies Terraform changes
    • Updates infrastructure state in R2
  2. Application Deployment (deploy-app.yml)

    • Automatic on branch push
    • Builds and tests applications
    • Deploys via Ansible
    • Runs post-deployment checks

Deployment Triggers

BranchEnvironmentTrigger Type
developDevelopmentAutomatic
qaQAAutomatic
mainProductionAutomatic
anyanyManual

Cost Optimization

Development/QA Strategy

  • Shared Infrastructure: Single droplet for both environments
  • Container Isolation: Separate services via Docker
  • Resource Efficiency: ~60% cost savings vs separate servers

Production Strategy

  • Dedicated Resources: Isolated production environment
  • Managed Services: DigitalOcean managed database
  • Auto-scaling Ready: Infrastructure supports horizontal scaling

Disaster Recovery

Backup Strategy

  • Database: Automated daily backups with 7-day retention
  • Configuration: Version controlled in Git
  • State Files: Redundant storage in Cloudflare R2
  • Application Data: File storage not yet implemented

Recovery Procedures

  1. Infrastructure Recovery: Terraform can recreate from state
  2. Data Recovery: Restore from managed database backups
  3. Configuration Recovery: Redeploy from Git repository
  4. Zero-downtime Updates: Rolling deployments supported

Built with ❤️ by the Jubiloop team