Skip to content

Stage EC2 Deployment Guide ​

Overview ​

Stage backend deployment on Amazon Linux EC2 instance.

  • Domain: stage-backend.oktivo.com
  • IP: 13.235.46.242
  • Region: ap-south-1
  • Services: client_backend, analysis, agent, valkey

Architecture ​

Internet → Nginx (host) → Docker containers
                ├── /client   → cb-client-backend (port 3000)
                └── /analysis → cb-analysis (port 8001)

EC2 Instance Setup ​

1. Install Docker & Docker Compose ​

bash
sudo yum update -y
sudo yum install -y docker
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker ec2-user

# Docker Compose plugin
sudo mkdir -p /usr/local/lib/docker/cli-plugins
sudo curl -SL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 \
  -o /usr/local/lib/docker/cli-plugins/docker-compose
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose

# Log out and back in for group changes
exit

2. Install Nginx & Certbot ​

bash
sudo yum install -y nginx certbot python3-certbot-nginx
sudo systemctl start nginx
sudo systemctl enable nginx

3. Docker Hub Login ​

bash
docker login -u dheerajoptimusprime
# Token: dckr_pat_pLgvvJqP_WFAPa-HWMi6eGB8a4s

4. Project Directory ​

bash
mkdir -p /home/ec2-user/oktivo-backend/credentials
cd /home/ec2-user/oktivo-backend

Configuration Files ​

.env ​

env
DEPLOY_ENV=stage
AWS_REGION=ap-south-1
REDIS_PASSWORD=abc123#
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

Note: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are intentionally blank. Containers use the EC2 instance IAM role for AWS credentials via the metadata service.

docker-compose.yml ​

See docker-compose-stage.yml in this repo for the full file.

AWS Secrets Manager ​

Secrets are loaded at container startup via the EC2 instance IAM role:

Secret NameUsed By
oktivo/stage/sharedAll services
oktivo/stage/analysisanalysis
oktivo/stage/agentagent
oktivo/stage/client-backendclient_backend

IAM Role Requirements ​

The EC2 instance must have an IAM role with:

  • secretsmanager:GetSecretValue on arn:aws:secretsmanager:ap-south-1:*:secret:oktivo/stage/*

Instance Metadata (IMDSv2) ​

Docker containers need hop limit = 2 to reach the EC2 metadata service:

bash
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
aws ec2 modify-instance-metadata-options \
  --instance-id $INSTANCE_ID \
  --http-put-response-hop-limit 2 \
  --http-endpoint enabled \
  --region ap-south-1

Or set this in AWS Console: EC2 → Instance → Actions → Instance Settings → Modify instance metadata options → Hop limit = 2.

Nginx Configuration ​

File: /etc/nginx/conf.d/oktivo-backend.conf

nginx
server {
    listen 80;
    server_name stage-backend.oktivo.com;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name stage-backend.oktivo.com;

    ssl_certificate /etc/letsencrypt/live/stage-backend.oktivo.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/stage-backend.oktivo.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Client Backend
    location /client/ {
        proxy_pass http://127.0.0.1:3000/;
        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_read_timeout 86400;
    }

    # Analysis Backend
    location /analysis/ {
        proxy_pass http://127.0.0.1:8001/;
        proxy_http_version 1.1;
        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_read_timeout 300;
    }
}

SSL Certificate ​

bash
# Initial setup
sudo mkdir -p /var/www/certbot
sudo certbot certonly --webroot -w /var/www/certbot \
  -d stage-backend.oktivo.com \
  --non-interactive --agree-tos --email [email protected]

# Auto-renewal (add to crontab: sudo crontab -e)
0 0,12 * * * certbot renew --quiet --post-hook "systemctl reload nginx"

Docker Images (Docker Hub) ​

Image TagService
dheerajoptimusprime/oktivo:analysis-stage-latestanalysis
dheerajoptimusprime/oktivo:agent-stage-latestagent
dheerajoptimusprime/oktivo:client-backend-stage-latestclient_backend

Operations ​

Deploy / Update ​

bash
cd /home/ec2-user/oktivo-backend
docker compose pull
docker compose up -d

View Logs ​

bash
docker compose logs -f              # all services
docker compose logs -f client_backend  # single service

Restart ​

bash
docker compose down
docker compose up -d

Check Status ​

bash
docker compose ps
docker ps

Ports ​

PortServiceExposed To
80Nginx (HTTP → HTTPS redirect)Public
443Nginx (SSL termination)Public
3000client_backendLocalhost only (via Nginx)
8001analysisLocalhost only (via Nginx)
6379Valkey (Redis)Localhost only

Security Group (EC2) ​

Inbound rules required:

  • Port 80 (HTTP) 0.0.0.0/0
  • Port 443 (HTTPS) 0.0.0.0/0
  • Port 22 (SSH) Your IP only

Troubleshooting ​

Secrets Manager AccessDenied ​

  • Verify IAM role is attached to EC2 instance
  • Verify IMDSv2 hop limit is set to 2
  • Do NOT pass AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY in env (they override the instance role)

Valkey Connection Refused ​

  • Redis password contains # must be URL-encoded as %23 in REDIS_URL
  • Ensure depends_on with condition: service_healthy is set

Docker Compose Warnings about blank AWS vars ​

  • Harmless. The blank values in .env silence them while allowing the instance role to work.

Key Decisions ​

  1. No AWS keys in environment Uses EC2 instance IAM role instead of static credentials
  2. Host Nginx SSL termination on host, not in Docker (simpler certbot management)
  3. Valkey password Uses abc123# from Secrets Manager (oktivo/stage/shared), URL-encoded in REDIS_URL
  4. No Docker nginx/certbot containers Removed from compose since host handles SSL

Last updated: