Skip to content

OpenTofu infra for deploying on ec2 #232

Merged
paigewilliams merged 45 commits intodevelopfrom
docker-nginx
Mar 5, 2026
Merged

OpenTofu infra for deploying on ec2 #232
paigewilliams merged 45 commits intodevelopfrom
docker-nginx

Conversation

@paigewilliams
Copy link
Copy Markdown
Collaborator

@paigewilliams paigewilliams commented Feb 3, 2026

Adds OpenTofu and docker set up for deploying on EC2

Instructions for deploying to EC2 (to be added to wiki when this is merged)

How to deploy to EC2:

  1. Install OpenTofu
  2. From the /infra/ directory initialize OpenTofu: tofu init
  3. run apply the resources: tofu apply
  4. Wait for the resources to spin up, make sure they successfully spin up
  5. ssh into the ec2 instance: ssh -i ~/.ssh/id_ed25519 ubuntu@<public_ip>
  6. navigate into the tekdb folder: cd tekdb
  7. git clone the TEKDB repo: git clone https://github.com/Ecotrust/TEKDB.git
  8. optional: navigate to the branch you want to deploy: git checkout <branch-name>
  9. copy over environment variables into docker/.env.prod. contact your system admin for these:
cat > .env.prod << EOF
DEBUG=0
SECRET_KEY=<secret-key>
ALLOWED_HOSTS=<ip-address>
SQL_ENGINE=django.contrib.gis.db.backends.postgis
SQL_DATABASE=<database>
SQL_USER=<postgres-user>
SQL_PASSWORD=<postgres-password>
SQL_HOST=<postgres-host>
SQL_PORT=<postgres-port>
ITKDB_ECR_PATH=<web-ecr-path>
ITKDB_PROXY_ECR_PATH=<proxy-ecr-path>
EOF
  1. log in to aws
    a. aws ecr get-login-password --region us-west-2 | sudo docker login --username AWS --password-stdin <web-ecr-path>
    b. aws ecr get-login-password --region us-west-2 | sudo docker login --username AWS --password-stdin <proxy-ecr-path>
  2. pull docker images
    a. sudo docker pull <web-ecr-path>:latest
    b. sudo docker pull <proxy-ecr-path>:latest
  3. from TEKDB/ , spin up the containers with the prod docker compose file: docker compose --env-file docker/.env.prod -f docker/docker-compose.prod.yaml up -d

@paigewilliams paigewilliams changed the title Docker nginx OpenTofu infra for deploying on ec2 Feb 27, 2026
@paigewilliams paigewilliams self-assigned this Feb 27, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds OpenTofu (Terraform-compatible) infrastructure-as-code for deploying the TEKDB application on AWS EC2, along with restructured Docker Compose files that separate dev/prod configurations, and a new GitHub Actions workflow to publish Docker images.

Changes:

  • New infra/ directory with complete OpenTofu configuration for AWS EC2, ECR, IAM, networking, and outputs.
  • Restructured Docker Compose setup using a shared common.yaml base with environment-specific overrides (docker-compose.yaml, docker-compose.prod.yaml, docker-compose.prod.local.yaml).
  • Application changes: nginx upstream renamed from app to web, uWSGI switched from HTTP to socket mode for production, new CI/CD workflow for building and publishing Docker images.

Reviewed changes

Copilot reviewed 18 out of 20 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
infra/terraform.tf OpenTofu backend (S3) and provider version constraints
infra/main.tf AWS provider, variable declarations
infra/ec2.tf EC2 instance, key pair, and Elastic IP resources
infra/ecr.tf ECR repositories for web and proxy images
infra/iam.tf IAM role and instance profile for ECR access
infra/networking.tf Security group with HTTP/HTTPS/SSH ingress
infra/outputs.tf Terraform outputs for EC2 IP and ECR URLs
infra/user_data.sh EC2 bootstrap script installing Docker, AWS CLI, Git
infra/.terraform.lock.hcl Lock file pinning AWS provider to 5.100.0
proxy/default.conf Nginx upstream renamed from app to web
proxy/Dockerfile Reordered to copy-then-chmod and moved USER root before COPY
TEKDB/Dockerfile Removed default CMD ["dev"]
TEKDB/TEKDB/settings.py SQL_PORT default changed from None to 5432
TEKDB/entrypoint.sh Added prod-local mode using HTTP (vs socket) uWSGI
docker/common.yaml Shared base service definitions extracted for DRY compose setup
docker/docker-compose.yaml Dev compose using common.yaml base
docker/docker-compose.prod.yaml Production compose using ECR images and nginx proxy
docker/docker-compose.prod.local.yaml New prod-local variant for local production testing
.github/workflows/create-and-publish-docker-images.yml CI workflow to build and push web Docker image to GHCR
.gitignore Added .env.prod, OpenTofu state files, and .tfvars patterns
Files not reviewed (1)
  • infra/.terraform.lock.hcl: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/web:latest,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/web:${{ github.sha }}
labels: ${{ steps.meta.outputs.labels }}

Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow only builds and pushes the web image to GHCR. However, docker/docker-compose.prod.yaml references ${ITKDB_PROXY_ECR_PATH}:latest for the proxy service, and infra/ecr.tf creates an aws_ecr_repository for the proxy. There is no step in this workflow (or any other visible workflow) that builds and pushes the proxy image. Without a published proxy image, the production deployment will fail when it attempts to pull it. A separate build step for the proxy image (context: ./proxy, file: ./proxy/Dockerfile) should be added.

Suggested change
- name: Build and push proxy Docker image
id: push_proxy
uses: docker/build-push-action@v6
with:
context: ./proxy
file: ./proxy/Dockerfile
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/proxy:latest,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/proxy:${{ github.sha }}
labels: ${{ steps.meta.outputs.labels }}

Copilot uses AI. Check for mistakes.
@@ -42,5 +42,3 @@ ENV DJANGO_SETTINGS_MODULE=TEKDB.settings

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TEKDB/Dockerfile removes the default CMD ["dev"] with no replacement. With no CMD, and ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] set, running the container with no command argument means entrypoint.sh receives no arguments. The entrypoint.sh else branch does exec "$@", which with no arguments will try to execute an empty string and fail. A default CMD should be provided (e.g. CMD ["dev"]) or the entrypoint script should handle the no-argument case gracefully.

Suggested change
CMD ["dev"]

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +14
env_file:
- .env.prod
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The web service in docker-compose.prod.yaml adds env_file: [.env.prod] via extends from common.yaml which already has env_file: [.env.dev]. Docker Compose merges list-type keys when using extends, so both .env.dev and .env.prod will be loaded. Values from .env.prod will take precedence over .env.dev (last file wins) when both define the same key, but the development secrets from .env.dev will still be passed into the container as well. If .env.dev is not present on the production server this may cause a startup failure. Consider explicitly overriding env_file to only include .env.prod rather than relying on merge behavior.

Copilot uses AI. Check for mistakes.
extends:
file: common.yaml
service: web
image: ${ITKDB_ECR_PATH}:latest
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow pushes images to GHCR (GitHub Container Registry at ghcr.io), but the production Docker Compose file uses ${ITKDB_ECR_PATH} and ${ITKDB_PROXY_ECR_PATH}, which are Amazon ECR paths. The infra code also provisions ECR repositories (infra/ecr.tf). There is a mismatch: this workflow doesn't publish to ECR at all, and there's no workflow in place to authenticate with AWS ECR and push there. Either the docker-compose.prod.yaml should point to GHCR images, or this workflow needs to be updated to authenticate and push to ECR.

Copilot uses AI. Check for mistakes.
@paigewilliams paigewilliams marked this pull request as ready for review February 27, 2026 22:20
@paigewilliams
Copy link
Copy Markdown
Collaborator Author

@rhodges @pollardld would love your eyes on this if you have a chance!

Some new things that I have added in the past two days:

  • user_data.tftpl does the following:

    • installs system requirements
    • clones the TEKDB repo
    • pulls the docker images from ECR
    • pulls environment variables from tfvars (terraform variables)
    • spins up the database, web-app, and proxy docker containers using docker compose
  • github action that runs on a published release:

    • authenticates to AWS
    • builds the multi architecture docker images using docker buildx and pushes those to ECR
    • uses AWS SSM to pull the latest images, and deploy them in the EC2 instance
    • final steps to verify that this was successful

@pollardld
Copy link
Copy Markdown
Member

I will asap. Probably tmrw morning.

Comment on lines +3 to +6
on:
push:
branches:
- develop
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to deploy to ec2 staging on push to the develop branch. Need to add to the ec2 user data script to switch to the develop branch. But this needs to be merged first. kind of a 🐔 and 🥚 situation

Copy link
Copy Markdown
Member

@pollardld pollardld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome. Excited to learn and use this!

@paigewilliams paigewilliams merged commit 8c00426 into develop Mar 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants