Deployment Guide
Deploy CloudAtlas on a Linux VPS with Docker Compose and Traefik in under 10 minutes.
Provision a VPS
Any cloud VPS works: AWS EC2 (t3.small+), DigitalOcean Droplet, Hetzner CX22, etc. Minimum: 1 vCPU, 1 GB RAM, Ubuntu 22.04 or Debian 12.
Open inbound ports: 22 (SSH), 80 (HTTP/ACME), 443 (HTTPS).
Install Docker
curl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER newgrp docker docker --version && docker compose version
Point your domain at the VPS
Add an A record in your DNS provider:
| Type | Name | Value | TTL |
|---|---|---|---|
| A | cloudatlas.example.com | YOUR_VPS_IP | 300 |
Create the Traefik Docker network
docker network create traefik-public 2>/dev/null || true
Clone and configure
git clone https://github.com/babathakur855/CloudAtlas.git cd CloudAtlas cp .env.example .env # Edit .env with your values, then: docker compose build docker compose up -d
Edit .env with your values:
# VPS domain (Traefik HTTPS) VPS_DOMAIN=cloudatlas.example.com # Base AWS credentials β leave blank if using an EC2 instance role AWS_ACCESS_KEY_ID=AKIA... AWS_SECRET_ACCESS_KEY=... # Management account role CloudAtlas will assume as its identity ROOT_ROLE_ARN=arn:aws:iam::123456789012:role/CloudAtlasRootRole # Primary region for Organizations and STS calls AWS_PRIMARY_REGION=us-east-1 # Role name created in child accounts (CloudAtlas creates this via Setup Roles) INVENTORY_ROLE_NAME=CloudAtlasInventoryRole # Role currently used when scanning each child account # Automatically updated to INVENTORY_ROLE_NAME after a successful Setup Roles run CROSS_ACCOUNT_ROLE=OrganizationAccountAccessRole # AWS Organizations default admin role β used only during setup ORG_ROLE_NAME=OrganizationAccountAccessRole # Parallel scan threads per account (keep 5β10 to avoid throttling) SCAN_MAX_WORKERS=5 # SQLite database path (inside the container volume) DB_PATH=/app/data/cloudatlas.db
.env file to Git. Add it to .gitignore before pushing.Complete IAM setup
Before starting a scan, the inventory role must exist in every child account. You have two options:
Option A β Automated (greenfield / admin access)
Open Settings and click Setup Cross-Account Roles. CloudAtlas will assume OrganizationAccountAccessRole in each account and create the inventory role automatically.
Option B β Manual (client-managed environments)
Follow the IAM Setup Guide to get the exact policy JSON and CloudFormation template to give to your client.
Start the services
docker compose up -d
Verify the deployment:
# Backend curl http://localhost:8025/health # Frontend (via Traefik domain) curl https://cloudatlas.example.com/health
Run your first scan
Navigate to Dashboard and click Start Scan. The scan bar shows real-time progress per account.
A typical organisation with 10 accounts and 5 regions completes in 3β5 minutes.
GitHub Actions CI/CD
The repository includes a CI/CD pipeline at .github/workflows/deploy.yml that runs type-checking, then deploys automatically on every push to main.
Required GitHub Secrets
Go to Repository β Settings β Secrets and variables β Actions β New repository secret and add each of the following. AWS secrets use the CLOUDATLAS_ prefix so they never overlap with credentials from any other project. The Anthropic key is intentionally unprefixed and can be shared.
| Secret name | Value | Shared? |
|---|---|---|
| VPS_HOST | VPS IP or hostname | Maybe |
| VPS_USER | SSH user (root, ubuntu, deployβ¦) | Maybe |
| VPS_SSH_KEY | SSH private key β Ed25519 recommended | No |
| VPS_DOMAIN | cloudatlas.example.com | No |
| CLOUDATLAS_AWS_ACCESS_KEY_ID | Access key for cloudatlas-deployer IAM user | No |
| CLOUDATLAS_AWS_SECRET_ACCESS_KEY | Secret key for cloudatlas-deployer IAM user | No |
| CLOUDATLAS_AWS_REGION | us-east-1 (or your primary region) | No |
| CLOUDATLAS_ROOT_ROLE_ARN | arn:aws:iam::ACCT:role/CloudAtlasRootRole | No |
| CLOUDATLAS_CROSS_ACCOUNT_ROLE | OrganizationAccountAccessRole | No |
| CLOUDATLAS_INVENTORY_ROLE_NAME | CloudAtlasInventoryRole | No |
| CLOUDATLAS_ORG_ROLE_NAME | OrganizationAccountAccessRole | No |
| CLOUDATLAS_SCAN_MAX_WORKERS | 5 | No |
| ANTHROPIC_API_KEY | sk-ant-β¦ (shared across projects, no CLOUDATLAS_ prefix) | Yes |
Dedicated deployer IAM user
Create an IAM user called cloudatlas-deployer in the management account. This user's only permission is to assume CloudAtlasRootRole. All real permissions live on the role, not the user.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::MGMT_ACCOUNT_ID:role/CloudAtlasRootRole"
}]
}Then add this user as a trusted principal in CloudAtlasRootRole's trust policy:
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::MGMT_ACCOUNT_ID:user/cloudatlas-deployer"
},
"Action": "sts:AssumeRole"
}Pipeline jobs
CIDeploySummaryOperations
View logs
docker compose logs -f backend docker compose logs -f frontend
Update CloudAtlas
git pull origin main docker compose build --no-cache docker compose up -d
Backup the database
docker compose cp backend:/app/data/cloudatlas.db ./cloudatlas-backup.db