Terraform scaffolding for the R|P infrastructure stack.
This scaffold is set up for:
- one EC2 instance per API
t2.smallinstances for bothrp-apiand Hermes- default VPC usage to keep costs and complexity down
- host-level Nginx terminating TLS and proxying to the app container
- CodeDeploy-managed app deployments onto EC2
- stable Elastic IPs so Cloudflare DNS can point directly at each API host
Right now, the production entrypoint is intentionally wired for Hermes only. The rp-api module blocks are still in the Terraform files, but commented out so they can be re-enabled later.
environments/prod: production entrypointmodules/ec2_api_service: reusable EC2 + Nginx + CodeDeploy app module.github/workflows: R|P-owned deployment automation that builds public app repos and deploys them into the AWS environment
This scaffold intentionally does not write application secrets into Terraform state.
Instead, both APIs are expected to keep a host-side .env file in the deployment directory:
- Hermes:
/home/ubuntu/hermes/.env - rp-api:
/home/ubuntu/rp-api/.envwhen that deployment is turned back on
That matches the current operational pattern more closely than pushing secrets through Terraform. It is still less secure than a managed secret store, but it avoids the larger mistake of baking secrets into Terraform state or user data.
- Copy
environments/prod/terraform.tfvars.exampleto a localterraform.tfvars - Fill in the domain names and, if needed, an EC2 key pair name
- From
environments/prod, run:
terraform init
terraform plan
terraform apply- Cloudflare DNS is not yet managed in this scaffold. Terraform outputs the Elastic IPs you can point A records at.
- Nginx is configured to use stable per-service cert paths. The bootstrap script creates a temporary self-signed cert so Nginx can start cleanly before Certbot issues a real certificate.
- Hermes now ships its own
appspec.ymland CodeDeploy scripts, matching therp-apideployment model. - Hermes deployment automation should live here, not in the Hermes repo itself. This repo can safely hold AWS-specific GitHub Actions secrets/vars because it is the infrastructure owner.
- Hermes is configured to install Certbot on the host. If
hermes_letsencrypt_emailis set, first boot will try to obtain a Let's Encrypt certificate and future renewals will be synced back into the Nginx cert paths automatically.
Hermes now uses host-managed Let's Encrypt certificates rather than long-lived self-signed certs or a cert copied in from Terraform.
- Set
hermes_letsencrypt_emailinterraform.tfvars - Keep the DNS record for
hermes_domain_namepointed at the instance - The instance bootstrap will:
- start Nginx with a temporary self-signed certificate
- install Certbot
- attempt
certbot certonly --nginx - copy the issued certificate into the stable Nginx paths Terraform manages
- install a Certbot renewal hook so renewals keep those paths fresh
If first-boot issuance happens before DNS is ready, you can rerun it on the box with:
sudo /usr/local/bin/hermes-api-issue-letsencrypt-cert.shAfter the origin has a real certificate, Cloudflare should be set to Proxied with SSL/TLS mode Full (strict).
The intended Hermes deploy flow is:
- Terraform provisions the EC2 instance, Nginx, PM2, and CodeDeploy resources
- A GitHub Actions workflow in
rp-infrachecks out the public Hermes repo - The workflow builds
dist/ - The workflow creates a CodeDeploy bundle and uploads it to
s3://rp-hermes-codedeploy-artifacts - The workflow starts a CodeDeploy deployment against the Hermes application and deployment group
The workflow needs the following repository configuration in rp-infra:
- Secrets:
AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY
- Variables:
AWS_REGIONHERMES_CODEDEPLOY_BUCKETHERMES_CODEDEPLOY_APP_NAMEHERMES_CODEDEPLOY_DEPLOYMENT_GROUPHERMES_REPOSITORYHERMES_REF
Suggested values:
AWS_REGION=us-east-2HERMES_CODEDEPLOY_BUCKET=rp-hermes-codedeploy-artifactsHERMES_CODEDEPLOY_APP_NAME=hermes-api-codedeploy-appHERMES_CODEDEPLOY_DEPLOYMENT_GROUP=hermes-api-deployment-groupHERMES_REPOSITORY=HackIllinois/HermesHERMES_REF=main