Skip to content

AWS Deployment

Deploy Artifact Keeper on a single EC2 instance using Docker Compose. The AMI comes with Docker pre-installed, all images pre-pulled, and a first-boot service that generates secrets and starts everything automatically.

Architecture

┌──────────────────────────────────────────────────┐
│ EC2 Instance │
│ │
│ ┌───────────┐ │
│ │ Nginx │ (host — handles SSL/TLS) │
│ │ (80/443) │ │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼──────────── Docker Compose ───────────┐ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────────────────────┐ │ │
│ │ │ Frontend │ │ Backend (8080) │ │ │
│ │ │ (3000) │ └────────┬─────────────────┘ │ │
│ │ └──────────┘ │ │ │
│ │ ┌─────────┼──────────┐ │ │
│ │ ┌─────▼───┐ ┌───▼─────┐ ┌─▼──────┐ │ │
│ │ │Postgres │ │Meili- │ │ Trivy │ │ │
│ │ │ (5432) │ │search │ │ (8090) │ │ │
│ │ └─────────┘ └─────────┘ └────────┘ │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ /data/ (EBS gp3 volume) │
└──────────────────────────────────────────────────┘

Nginx runs on the host for SSL termination. All application services run as Docker containers managed by Docker Compose. Data is persisted to /data/ on a dedicated EBS volume.

Prerequisites

  • AWS account with permissions to launch EC2 instances
  • An EC2 key pair for SSH access
  • AWS CLI configured (aws configure)

Option 1: Pre-Built AMI (Quickest)

Launch the official Artifact Keeper AMI directly from the AWS console or CLI.

Find the AMI

Check the latest release for the AMI ID, or search in the EC2 console:

Terminal window
aws ec2 describe-images \
--owners self \
--filters "Name=name,Values=artifact-keeper-*" \
--query 'Images | sort_by(@, &CreationDate) | [-1].[ImageId,Name]' \
--output table

Launch an Instance

Terminal window
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type t3.medium \
--key-name my-key-pair \
--security-group-ids sg-abc123 \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":30,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=artifact-keeper}]' \
--query 'Instances[0].InstanceId' \
--output text

Retrieve Credentials

On first boot, the instance generates random credentials for all services. SSH in to retrieve them:

Terminal window
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<PUBLIC_IP>
sudo cat /opt/artifact-keeper/.credentials

Output:

=====================================
Artifact Keeper Credentials
=====================================
Access URL: http://<PUBLIC_IP>
Database Password: <generated>
Meilisearch Key: <generated>
JWT Secret: <generated>
Docker Compose Dir: /opt/artifact-keeper
Manage services:
cd /opt/artifact-keeper
docker compose ps
docker compose logs -f backend
docker compose restart
=====================================

Open http://<PUBLIC_IP> in your browser to access the UI.


The Terraform module provisions the full infrastructure: VPC, security groups, IAM roles, EC2 instance, and a dedicated EBS data volume.

1. Clone the Repository

Terminal window
git clone https://github.com/artifact-keeper/artifact-keeper.git
cd artifact-keeper/deploy/aws/terraform

2. Configure Variables

Terminal window
cp terraform.tfvars.example terraform.tfvars

Edit terraform.tfvars:

ami_id = "ami-0123456789abcdef0" # From latest release
aws_region = "us-east-1"
instance_type = "t3.medium"
key_name = "my-key-pair"
# Restrict SSH to your IP
allowed_ssh_cidrs = ["203.0.113.0/32"]
# Optional: auto-SSL with Let's Encrypt
# domain = "artifacts.example.com"
# admin_email = "admin@example.com"
# Artifact storage volume (GB)
data_volume_size = 100

3. Deploy

Terminal window
terraform init
terraform plan
terraform apply

4. Access Your Instance

Terraform outputs everything you need:

Terminal window
terraform output url
# http://54.123.45.67
terraform output ssh_command
# ssh -i ~/.ssh/my-key-pair.pem ubuntu@54.123.45.67
terraform output credentials_command
# ssh -i ~/.ssh/my-key-pair.pem ubuntu@54.123.45.67 'sudo cat /opt/artifact-keeper/.credentials'

5. Tear Down

Terminal window
terraform destroy

Option 3: Build Your Own AMI with Packer

Use the Packer template to build a custom AMI with your own modifications.

1. Install Packer

Terminal window
# macOS
brew install hashicorp/tap/packer
# Ubuntu/Debian
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt-get update && sudo apt-get install packer

2. Configure the Build

Terminal window
cd deploy/aws/packer
cp variables.auto.pkrvars.hcl.example variables.auto.pkrvars.hcl

Edit variables.auto.pkrvars.hcl:

artifact_keeper_version = "0.2.0"
aws_region = "us-east-1"
instance_type = "t3.medium"
# Copy to additional regions
# ami_regions = ["us-west-2", "eu-west-1"]

3. Build

Terminal window
packer init .
packer validate .
packer build .

Packer will:

  1. Launch a temporary EC2 instance from Ubuntu 24.04
  2. Install Docker, Nginx, and certbot
  3. Copy the Docker Compose file and pull all container images
  4. Configure systemd services for first-boot and compose
  5. Snapshot the instance as a new AMI
  6. Terminate the temporary instance

The AMI ID is printed at the end of the build. Use it with the Terraform module or launch directly.

Customizing the Build

The provisioning scripts are in deploy/aws/scripts/:

ScriptPurpose
01-docker.shInstall Docker, Nginx, certbot, firewall
02-artifact-keeper.shCopy compose file, pull images, configure systemd
99-cleanup.shRemove caches and SSH keys for clean AMI

Supporting files:

FilePurpose
docker-compose.ymlProduction compose with GHCR images
nginx-host.confHost Nginx config for SSL termination
first-boot.shGenerate secrets, configure Nginx, optional SSL

Modify any file before building to customize the installation.


Post-Deployment

Configure SSL with Let’s Encrypt

If you didn’t set a domain during launch, you can configure SSL manually:

Terminal window
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<PUBLIC_IP>
# Update Nginx server_name
sudo sed -i 's/server_name _;/server_name artifacts.example.com;/' \
/etc/nginx/sites-available/artifact-keeper
sudo nginx -t && sudo systemctl reload nginx
# Request certificate
sudo certbot --nginx -d artifacts.example.com \
--non-interactive --agree-tos -m admin@example.com --redirect

Certbot automatically renews certificates via a systemd timer.

Configure Package Managers

Once running, configure your package managers to point at the instance. See the Package Formats Overview for client configuration guides.

Example — configure npm:

Terminal window
npm config set registry http://<YOUR_IP_OR_DOMAIN>/npm/my-npm-repo/
npm login --registry http://<YOUR_IP_OR_DOMAIN>/npm/my-npm-repo/

Check Service Status

Terminal window
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<PUBLIC_IP>
# Container status
cd /opt/artifact-keeper
docker compose ps
# Artifact Keeper logs
docker compose logs -f backend
# All logs
docker compose logs -f
# Health check
curl http://localhost/health

Backup

Artifacts are stored on the EBS data volume at /data/storage. Create EBS snapshots for point-in-time backups:

Terminal window
# Find the volume ID
INSTANCE_ID=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=artifact-keeper" \
--query 'Reservations[0].Instances[0].InstanceId' --output text)
VOLUME_ID=$(aws ec2 describe-volumes \
--filters "Name=attachment.instance-id,Values=${INSTANCE_ID}" \
"Name=tag:Name,Values=*data*" \
--query 'Volumes[0].VolumeId' --output text)
# Create snapshot
aws ec2 create-snapshot \
--volume-id "$VOLUME_ID" \
--description "artifact-keeper-backup-$(date +%Y%m%d)" \
--tag-specifications "ResourceType=snapshot,Tags=[{Key=Name,Value=artifact-keeper-backup}]"

Instance Sizing

WorkloadInstance TypevCPURAMArtifacts
Small team (< 20 devs)t3.medium24 GBUp to 100 GB
Medium team (20–100 devs)t3.large28 GBUp to 500 GB
Large team (100+ devs)m6i.xlarge416 GB1 TB+

All instances use gp3 EBS volumes. Increase the data_volume_size Terraform variable for more artifact storage.


Troubleshooting

First-boot didn’t complete

Terminal window
# Check first-boot log
sudo journalctl -u artifact-keeper-first-boot
# Re-run manually
sudo /opt/artifact-keeper/first-boot.sh

Artifact Keeper won’t start

Terminal window
cd /opt/artifact-keeper
# Check container status
docker compose ps
# Check backend logs
docker compose logs backend
# Check if database is healthy
docker compose logs postgres
# Restart everything
docker compose down && docker compose up -d

Can’t connect to the instance

  1. Verify the security group allows inbound HTTP (port 80) and HTTPS (port 443)
  2. Check that the instance has a public IP or Elastic IP
  3. Confirm UFW is allowing traffic: sudo ufw status

SSL certificate issues

Terminal window
# Test renewal
sudo certbot renew --dry-run
# Force renewal
sudo certbot renew --force-renewal

See Also