AWS
A starter recipe for self-hosted Flux on AWS — ECS Fargate, RDS Postgres, Secrets Manager, ALB.
A starter recipe — the smallest viable AWS shape that respects Flux’s constraints (durable Postgres, persistent bootstrap-token, sticky routing for worker connections when the server runs more than one task). Production hardening — multi-AZ workers, blue/green deploys, IAM least-privilege per task — is on top of this.
Topology
- ECS Fargate, two task definitions:
flux-server— start withdesired_count: 1; raise it for availability once target-group stickiness is on (server replicas coordinate through PostgreSQL — see High availability).flux-worker— N tasks, scaled by an ECS Service Auto Scaling policy.
- RDS PostgreSQL 14+, multi-AZ.
db.t4g.mediumis a reasonable starting size; size up based on load testing, and keepmax_connections ≥ server tasks × 40(each replica’s pool defaults to 20 + 20 overflow). - AWS Secrets Manager for three values: the bootstrap token, the encryption key, and the RDS master password (or the per-app DB password).
- Application Load Balancer in front of the server task. Target group health check on
/ready— the ALB inspects the status code only, and that is sufficient:/readyperforms a database round-trip and returns 503 when the DB is unreachable, so a server with a dead DB fails the ALB check and is taken out of rotation. - CloudWatch Logs for both task families.
- VPC with private subnets for RDS and ECS tasks; a public ALB in front.
Provisioning order
Roughly in this order:
1. Networking
VPC, public + private subnets across two AZs, NAT gateway (or VPC endpoints if minimizing NAT cost), security groups. Three groups suffice: ALB (allow 443 from 0.0.0.0/0), Server tasks (allow 8000 from the ALB SG), RDS (allow 5432 from the Server and any admin bastion SG).
2. RDS Postgres
Create the instance in the private subnets. Take note of the endpoint, port, master credentials. Create the flux database and the flux user with CREATE permission — Flux will create its own tables on first connect.
3. Secrets Manager
Generate and store three secrets:
# Bootstrap token
aws secretsmanager create-secret \
--name flux/bootstrap-token \
--secret-string "$(python -c 'import secrets; print(secrets.token_hex(32))')"
# Encryption key
aws secretsmanager create-secret \
--name flux/encryption-key \
--secret-string "$(python -c 'import secrets; print(secrets.token_hex(32))')"
# DB password (or import the RDS-generated one)
aws secretsmanager create-secret \
--name flux/database-url \
--secret-string "postgresql://flux:PASSWORD@flux-db.xxx.rds.amazonaws.com:5432/flux"
4. ECS cluster
Create a Fargate cluster. The flux-server task definition references the secrets via the task role’s secrets: block, which injects them as env vars at task start:
"secrets": [
{ "name": "FLUX_DATABASE_URL",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:flux/database-url" },
{ "name": "FLUX_WORKERS__BOOTSTRAP_TOKEN",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:flux/bootstrap-token" },
{ "name": "FLUX_SECURITY__ENCRYPTION__ENCRYPTION_KEY",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:flux/encryption-key" }
]
The task role needs secretsmanager:GetSecretValue on those ARNs and kms:Decrypt on the KMS key encrypting them.
The flux-worker task definition needs only the bootstrap-token and FLUX_WORKERS__SERVER_URL (or pass --server-url in the container command). Set it to the internal Service Discovery endpoint (Cloud Map) or the ALB’s internal DNS, depending on whether you want workers to traverse the ALB or hit the server tasks directly.
5. ECS Services
flux-serverService:desired_count: 1to start; rolling deploys are safe (replicas coordinate through PostgreSQL, so brief overlap during a deploy cannot double-fire schedules). Register it with the ALB target group. Raisingdesired_countabove 1 is supported for availability — turn on target-group stickiness first (next section) and runflux db upgradeonce before the first multi-task deploy. Keep auto scaling off the server Service regardless: replica count is an availability decision, and each task adds ~40 connections of PostgreSQL pool ceiling.flux-workerService:desired_count: 3(or whatever your starting pool size is). Attach an Auto Scaling policy with target tracking on CPU or a custom CloudWatch metric (e.g., worker queue depth published from/metrics). Set the task’sstopTimeoutto at leastdrain_timeout + 30s(90s at the default) so SIGTERM-drain can finish running executions.
6. ALB
Listener on 443 with an ACM cert. Target group pointing at the server tasks on port 8000. Health check path /ready. The ALB inspects the status code, which is all you need: /ready returns 200 when the server can reach the database and 503 when it can’t, so the ALB check reflects real readiness on its own.
At desired_count > 1, enable target-group stickiness (stickiness.enabled=true, lb_cookie): a worker’s SSE stream (GET /workers/{name}/connect) and its dispatch queue live on the task it connected to, so worker traffic must keep landing there. Plain round-robin is fine for everything else, but one target group with stickiness for all traffic is the simpler shape. Also raise the ALB idle timeout (60s+) so the long-lived SSE stream isn’t severed between heartbeats.
Terminate TLS at the ALB. Flux’s flux start server has no --ssl-keyfile flag — it serves plain HTTP and relies on the ALB for transport security.
Secrets
Two distinct kinds of “secret” exist in a Flux-on-AWS deployment, and conflating them causes confusion.
- AWS Secrets Manager holds the bootstrap configuration that brings Flux up: bootstrap token, encryption key, DB password. The ECS task role reads these at container start and injects them as env vars.
- Flux’s
secretsprimitive (theflux secretsCLI,Secret(...)references in workflows) stores application secrets inside the Flux database, encrypted at rest with the encryption key. These are not in AWS Secrets Manager — they’re inside Flux’s Postgres, encrypted with the key you stored above.
The relationship: AWS Secrets Manager bootstraps Flux; once Flux is up, application workflows pull their own credentials from Flux’s secrets table. The encryption key you put in AWS Secrets Manager is the master key that makes those workflow secrets readable.
Networking notes
- Workers reaching the server: prefer internal Service Discovery (Cloud Map) over the public ALB to keep worker→server traffic on the VPC backbone.
- RDS in private subnets, no public access. Use a bastion or AWS Systems Manager Session Manager for admin access.
- VPC endpoints for Secrets Manager and ECR cut NAT egress costs significantly at scale.
What can go wrong
Server task keeps replacing
Symptom. ECS shows the flux-server Service cycling tasks every few minutes; CloudWatch shows them failing the ALB health check.
Cause. Most commonly: ALB health check timeout too aggressive, or the task is failing to start because Secrets Manager retrieval is slow or IAM-blocked.
Fix. Bump the ALB health check Healthy threshold to 2 and Interval to 30s. Check the task’s startup logs in CloudWatch — AccessDeniedException from Secrets Manager points at task-role IAM.
Workers stay OFFLINE
Symptom. flux worker list (run from a bastion against the server) shows workers as OFFLINE.
Cause. Most commonly: bootstrap-token mismatch — the server and worker task definitions reference different versions of the Secrets Manager secret, or the secret was rotated and one Service wasn’t redeployed.
Fix. Confirm both task definitions reference the same secret ARN (without a version suffix, so they pick up the current version on each task start), then redeploy both Services.
Workers flap after scaling the server Service
Symptom. After raising desired_count on flux-server, workers cycle between ONLINE and OFFLINE and executions sit unclaimed longer than before.
Cause. Target-group stickiness is off, so each worker request lands on a random server task while its SSE stream and dispatch queue live on one specific task.
Fix. Enable lb_cookie stickiness on the target group, then restart the workers once. See High availability.
This recipe is derived from AWS service documentation and Flux’s deployment requirements; the author hasn’t personally validated it end-to-end on AWS as of 2026-07. Treat IAM policies, VPC topology, and ALB tuning as starting points to validate against your account’s guardrails.