Backenderer is a lightweight AWS deployment template for running a single backend app per environment on an EC2 host with Docker and Nginx.
- Provisions AWS infrastructure with Terraform
- Uses GitHub Actions + OIDC for infra, deploy, and destroy workflows
- Registers app containers on the host through AWS Systems Manager
- Supports two deploy modes:
source: build from./appand publish to the managed env-scoped ECR repoimage: deploy a prebuilt image URI directly
backenderer.config.yaml: canonical deploy config consumed by workflowsapp/: source build context formode: sourceexamples/single-app.yaml: runnable image-mode example configbootstrap/: one-time Terraform bootstrap for remote state + shared GitHub OIDC providerinfra/terraform/envs/{dev,prod}: environment rootsinfra/terraform/modules/: shared Terraform modulesinfra/docs/: quickstart, bootstrap, remote state, and cost notesscripts/: host bootstrap and app registration scriptstests/: shell smoke tests for helpers and rollout behavior.github/workflows/:infra,deploy,remove, andsecurity
backenderer.config.yaml is the single deploy contract:
deploy:
mode: image
app_name: hello-web
container_port: 80
health_path: /
server_name: _
image_uri: nginx:1.27-alpinehealth_path is optional and defaults to /. The deploy workflow and ALB target group both use it as the application success signal.
Start with the bootstrap guide:
That flow creates:
- the shared Terraform state bucket
- the shared GitHub OIDC provider ARN
The per-environment GitHub Actions role ARNs are created by the dev and prod env stacks and then stored in GitHub secrets.
Required secrets:
AWS_ROLE_ARN_DEVAWS_ROLE_ARN_PROD
Required repository or environment variables:
TFSTATE_BUCKETTFSTATE_REGIONGITHUB_OIDC_PROVIDER_ARNAWS_REGION_DEVAWS_REGION_PRODDEV_AMI_IDPROD_AMI_ID
Optional variables with defaults:
DEV_INSTANCE_TYPEdefaultt3.microPROD_INSTANCE_TYPEdefaultt3.smallDEV_NAME_PREFIXdefaultbackendererPROD_NAME_PREFIXdefaultbackendererDEV_TLS_MODEdefaultnonePROD_TLS_MODEdefaultalb_acm
Conditional variables:
DEV_ROUTE53_ZONE_IDrequired only whenserver_nameis a real DNS name and DNS records should be createdPROD_ROUTE53_ZONE_IDrequired only for DNS-backedalb_acmDEV_INSTANCE_PROFILEonly if you are reusing an existing instance profilePROD_INSTANCE_PROFILEonly if you are reusing an existing instance profile
Use the Infra workflow for CI-driven plans and applies.
The generated env roles trust refs/heads/main by default, so Infra, Deploy, and Remove Stack are expected to run from main unless you widen the allowed refs in Terraform.
For local Terraform runs:
cd infra/terraform/envs/dev
cp backend.hcl.example backend.hcl
cp dev.tfvars.example dev.tfvars
# edit backend.hcl + dev.tfvars with bootstrap outputs and env values
terraform init -backend-config=backend.hcl
terraform plan -var-file=dev.tfvarsFor a full local repo check, run:
./scripts/preflight.shUse the Deploy workflow with env=dev or env=prod.
mode: sourcebuilds./app, pushes tobackenderer-apps-<env>, and registers that image on the hostmode: imageskips the build and registers the provided image URI directly- Private authenticated registry support in this repo is limited to ECR
- The deploy workflow fails unless it finds exactly one running instance tagged
Backenderer=<env>
The deploy workflow now treats success as:
- SSM registration command succeeds
- the configured
deploy.health_pathreturns success through the app vhost
For alb_acm, the same health_path is also used by the ALB target group.
Supported modes:
nonealb_acm
none keeps a single public EC2 host and no ALB.
alb_acm creates a public ALB and a private EC2 host behind it.
The Remove Stack workflow performs a full Terraform destroy for the selected environment and requires an explicit confirmation input.
The Security workflow runs on pull requests and relevant pushes.
- Secret scanning: Trivy filesystem secret scan fails the workflow on detected secrets.
- Terraform/IaC scanning: Trivy config scan summarizes
HIGHandCRITICALfindings in the workflow summary during the staged rollout. See Security Baseline.
.env is treated as a local-only convenience file for scripts and workflow emulation. It should not be committed.