Deploying PackyTrace¶
The app runs on one AWS EC2 box: Terraform builds the infrastructure, cloud-init prepares the host, Docker Compose runs the containers, Caddy serves it over HTTPS. This page is the runbook — what to type, in order. For why it is shaped this way, see ADR-014.
All commands assume the AWS profile admin and region eu-central-1. Run Terraform from
deployment/aws/terraform.
Prerequisites (one-time)¶
- AWS CLI configured with an
adminprofile that can reach the account. terraform(>= 1.10) and theghCLI installed.deployment/aws/terraform/terraform.tfvarsfilled in from the example (domain + GHCR token). Never commit it.
First deploy¶
- Publish the images once:
bash
gh workflow run deploy-images.yml
- Apply the infrastructure:
bash
cd deployment/aws/terraform
terraform init
terraform apply
- Add the DNS A record it prints at your registrar:
bash
terraform output dns_record
- Watch the first boot until containers are healthy:
bash
$(terraform output -raw ssm_session_command)
sudo tail -f /var/log/packytrace-bootstrap.log
sudo docker compose -f /opt/packytrace/docker-compose.yml ps
- Open the app:
bash
terraform output -raw app_url
Deploy a new version¶
This is the everyday path. Merging does not change the box — it only publishes images. The box updates only when you bump the tag and redeploy.
-
Merge to
main. Semantic-release builds and pushes images to GHCR asvX.Y.Zandlatest. Note the new version (git describe --tags --abbrev=0). -
Point the box at the new version:
bash
aws ssm put-parameter \
--name /packytrace/config/image_tag \
--type String --overwrite \
--value vX.Y.Z \
--profile admin --region eu-central-1
- Redeploy:
bash
$(terraform output -raw redeploy_command)
- Verify before calling it done: open
terraform output -raw app_url, confirm/healthresponds, and run one real barcode scan.
Roll back¶
Same mechanic, pointed at the previous good version: set image_tag back and redeploy.
aws ssm put-parameter \
--name /packytrace/config/image_tag \
--type String --overwrite \
--value vX.Y.Z-previous \
--profile admin --region eu-central-1
$(terraform output -raw redeploy_command)
Caveat: this rolls back code, not the database. Services apply migrations forward at startup with no automatic down step (ADR-012), so a rollback is only clean if the migration was backward-compatible. Keep migrations additive (nullable/defaulted columns, deprecate before delete) so a rollback never strands the schema.
Everyday operations¶
| Task | Command |
|---|---|
| Open shell | $(terraform output -raw ssm_session_command) |
| Check containers | sudo docker compose -f /opt/packytrace/docker-compose.yml ps |
| Stream logs | sudo docker compose -f /opt/packytrace/docker-compose.yml logs -f |
| Re-render config | sudo /opt/packytrace/render-config.sh |
| Stop spending, keep data | Stop the EC2 instance |
| Tear everything down | terraform destroy |
If something breaks¶
- Boot looks stuck:
sudo tail -f /var/log/packytrace-bootstrap.log. - A service is unhealthy:
... compose psto see which, then... compose logs -f <service>. - Config/secret looks wrong: re-run
sudo /opt/packytrace/render-config.sh, then... compose up -d. - Data is safe across restarts: all state lives on the separate
/dataEBS volume, so it survives instance replacement.terraform destroyis the only thing that removes it.
Known limits¶
- No high availability — one box, single point of failure.
- No automated backups yet — until then,
/datais the one irreplaceable thing; never runterraform destroycasually. - Keycloak still ships demo setup that must be reviewed before real users.