Skip to content

AWS

This guide walks you through deploying Voquill Enterprise on AWS using ECS with Fargate.

  • An AWS account with permissions to create ECS clusters, task definitions, load balancers, and RDS instances.
  • The AWS CLI installed and configured.
  • Your Voquill Enterprise license key.

If you don’t already have a VPC configured, create one with public and private subnets. The gateway and admin services will run in private subnets behind a load balancer, and the RDS instance should only be accessible from within the VPC.

Terminal window
aws ec2 create-vpc --cidr-block 10.0.0.0/16

Create at least two subnets across different availability zones for high availability.

Create an RDS PostgreSQL instance within your VPC:

Terminal window
aws rds create-db-instance \
--db-instance-identifier voquill-db \
--db-instance-class db.t3.micro \
--engine postgres \
--engine-version 16 \
--master-username postgres \
--master-user-password your-db-password \
--allocated-storage 20 \
--vpc-security-group-ids your-sg-id \
--db-subnet-group-name your-subnet-group \
--no-publicly-accessible

Note the endpoint once the instance is available. You’ll use it as the DATABASE_URL for the gateway.

Terminal window
aws ecs create-cluster --cluster-name voquill

Create a task definition for the gateway service. Save this as gateway-task.json:

{
"family": "voquill-gateway",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"containerDefinitions": [
{
"name": "gateway",
"image": "ghcr.io/josiahsrc/voquill/enterprise-gateway:latest",
"portMappings": [{ "containerPort": 4630 }],
"environment": [
{ "name": "DATABASE_URL", "value": "postgres://postgres:your-db-password@your-rds-endpoint:5432/voquill" },
{ "name": "JWT_SECRET", "value": "your-jwt-secret" },
{ "name": "ENCRYPTION_SECRET", "value": "your-encryption-secret" },
{ "name": "LICENSE_KEY", "value": "your-license-key" }
]
}
]
}

Create a similar task definition for the admin portal. The VITE_GATEWAY_URL environment variable must be set to the public URL of your gateway service so the admin portal can communicate with it.

{
"family": "voquill-admin",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "admin",
"image": "ghcr.io/josiahsrc/voquill/enterprise-admin:latest",
"portMappings": [{ "containerPort": 5173 }],
"environment": [
{ "name": "VITE_GATEWAY_URL", "value": "https://your-gateway-url" }
]
}
]
}

Register both:

Terminal window
aws ecs register-task-definition --cli-input-json file://gateway-task.json
aws ecs register-task-definition --cli-input-json file://admin-task.json

For production deployments, store secrets like JWT_SECRET, ENCRYPTION_SECRET, and LICENSE_KEY in AWS Secrets Manager and reference them using the secrets field instead of environment.

Create an ALB with target groups for both the gateway (port 4630) and admin portal (port 5173). Route traffic using host-based or path-based rules depending on your DNS setup.

Terminal window
aws elbv2 create-load-balancer \
--name voquill-alb \
--subnets subnet-xxx subnet-yyy \
--security-groups sg-xxx

Create target groups and listeners for each service.

Terminal window
aws ecs create-service \
--cluster voquill \
--service-name gateway \
--task-definition voquill-gateway \
--desired-count 1 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-xxx],securityGroups=[sg-xxx],assignPublicIp=DISABLED}" \
--load-balancers "targetGroupArn=arn:aws:...,containerName=gateway,containerPort=4630"

Repeat for the admin service.

To deploy a new version, pull the latest image and update the ECS service to force a new deployment:

Terminal window
aws ecs update-service \
--cluster voquill \
--service gateway \
--force-new-deployment

ECS will pull the latest image and perform a rolling update with zero downtime. Repeat for the admin service.