This repository contains a minimalist AWS deployment strategy for a full-stack web application. The infrastructure is designed to showcase AWS knowledge while minimizing costs.
The simplified architecture consists of:
-
Single EC2 Instance (t2.micro): Hosts both frontend and backend applications
- Nginx as a reverse proxy to route traffic
- Docker for running the backend service
- Static frontend files served directly from Nginx
-
Simple VPC Setup:
- 1 VPC with public subnets across 2 availability zones
- Internet Gateway for public internet access
- Security group with necessary rules
-
S3 Bucket: For deployment artifacts and file storage
-
CI/CD Pipeline: GitHub Actions workflow for automated deployment
-
Multi-Environment Support:
- Uses Terraform workspaces for environment isolation
- Development environment runs locally only (not deployed to AWS)
- Supports staging and production environments in AWS
- Environment-specific configuration and deployment
The development environment runs locally to save costs and AWS resources:
-
Local Setup:
# Install dependencies pnpm install # Start local development servers pnpm dev
-
Local Database:
- Use a local PostgreSQL instance for development
- Configure connection details in your local
.envfile
This project uses two AWS deployment environments:
-
Staging: For pre-production testing and validation
- Hosts the shared PostgreSQL database for both environments
- Deployed from the
developbranch
-
Production: For live application
- Uses the database hosted on the staging environment
- Deployed from tagged releases (
v*tags)
This project requires the following GitHub secrets to be configured for successful deployment:
-
AWS_ACCESS_KEY_ID(Required)- Your AWS IAM user access key
- The IAM user must have permissions to create EC2, VPC, and S3 resources
-
AWS_SECRET_ACCESS_KEY(Required)- The secret key associated with your AWS access key ID
-
SSH_PRIVATE_KEY(Required)- Your private SSH key for connecting to the EC2 instance
- Include the entire key including BEGIN/END lines
-
EC2_KEY_NAME(Optional but recommended)- The name of your EC2 key pair in the AWS region
- Required for SSH access to your instance
- Example:
my-aws-keypair
-
AMI_ID(Optional)- Custom AMI ID if you want to use a different base image
- Defaults to Ubuntu 22.04 LTS in us-west-2 if not provided
-
DB_USERNAME(Required)- Username for the PostgreSQL database
- Example:
swashflag_user
-
DB_PASSWORD(Required)- Password for the PostgreSQL database user
- Should be a secure, random password
- Example: Generate with:
openssl rand -base64 16
- Go to your GitHub repository
- Click on "Settings" tab
- In the left sidebar, click "Secrets and variables" > "Actions"
- Click "New repository secret" and add each secret with its value
For proper environment isolation, this project uses GitHub Environments to store environment-specific secrets:
- Go to your GitHub repository
- Click on "Settings" tab
- In the left sidebar, click "Environments"
- Create three environments:
dev,staging, andprod - For each environment, add the following secrets:
DB_USERNAME: Environment-specific database username (e.g.,swashflag_dev_userfor dev)DB_PASSWORD: Environment-specific secure passwordJWT_SECRET: Environment-specific JWT secret for authenticationENCRYPTION_KEY: Environment-specific encryption key
This ensures each environment has its own set of credentials and secrets, improving security and isolation.
This infrastructure is specifically designed to minimize AWS costs while still showcasing AWS services:
- Uses only free tier eligible resources (t2.micro instance)
- Eliminates expensive managed services (RDS, ECS, etc.)
- Consolidates frontend and backend on a single instance
- Minimizes data transfer costs
- Avoids costly multi-AZ deployments
- Shares infrastructure code across environments with minimal duplication
- AWS account with appropriate permissions
- GitHub repository with necessary secrets (see GitHub Secrets Configuration section)
- AWS EC2 Key Pair for SSH access
- Local environment for development
The infrastructure supports two AWS environments plus local development:
-
Development: Runs locally, not deployed to AWS
- Use local server and database
- Run with
pnpm devcommand - Saves costs by avoiding AWS resources for development
-
Staging (staging): For pre-production validation
- Deployed automatically from the
developbranch - Prefix:
swashflag-staging - Hosts the PostgreSQL database used by both environments
- Deployed automatically from the
-
Production (prod): For live application
- Deployed when a version tag is pushed (e.g.,
v1.0.0) - Prefix:
swashflag-prod - Connects to the database hosted in the staging environment
- Deployed when a version tag is pushed (e.g.,
The AWS environments are isolated using Terraform workspaces and have:
- Their own set of AWS resources
- Environment-specific resource naming
- Environment-specific configuration
- Visual indicators in the UI to distinguish environments
-
Navigate to the terraform directory:
cd terraform -
Initialize Terraform:
terraform init -
Select the target environment workspace:
terraform workspace select dev # or staging or prod(Create it first with
terraform workspace new devif it doesn't exist) -
Apply the Terraform configuration:
terraform apply -
Build and deploy your applications to the EC2 instance
The GitHub Actions workflow automatically determines the target environment:
-
Development Environment:
- Trigger: Push to
developbranch - Command:
git push origin develop
- Trigger: Push to
-
Staging Environment:
- Trigger: Push to
mainbranch - Command:
git push origin main
- Trigger: Push to
-
Production Environment:
- Trigger: Push a version tag
- Command:
git tag v1.0.0 && git push origin v1.0.0
-
Manual Deployment:
- Trigger: Manual workflow dispatch
- Select the environment in GitHub Actions UI
The workflow will:
- Build the frontend and backend applications with environment-specific configuration
- Deploy the infrastructure to the appropriate environment
- Package and deploy the applications to the EC2 instance
This repository is set up as a monorepo using PNPM workspaces:
-
Install dependencies:
pnpm install -
Run development servers:
pnpm run dev
.
├── .github/workflows # GitHub Actions workflows
│ └── front-and-back-deploy.yml # Multi-environment deployment workflow
├── apps # Application code
│ ├── backend # Backend application (Node.js)
│ └── frontend # Frontend application (React)
├── packages # Shared packages
└── terraform # Infrastructure as Code
├── main.tf # Main Terraform configuration with environment support
├── variables.tf # Variable definitions
└── terraform.tfvars # Default variable values
This minimalist infrastructure can be extended to include more AWS services as needed:
- Add RDS for a managed database
- Implement S3 + CloudFront for static content delivery
- Add Auto Scaling for high availability
- Implement ECS/Fargate for container orchestration
This project is licensed under the MIT License - see the LICENSE file for details.
SwashFlag is a full-stack web application designed to manage feature flags efficiently. It provides a user-friendly interface for developers and product managers to toggle features on and off without deploying new code. This capability is crucial for A/B testing, gradual feature rollouts, and quick rollbacks.
- Feature Management: Easily create, update, and delete feature flags.
- User Authentication: Secure login and signup functionality.
- API Token Management: Generate and manage API tokens for secure access.
- Environment-Specific Configurations: Automatically adapts to different environments (development, staging, production) using dynamic configuration.
- Frontend: Built with modern JavaScript frameworks, providing a responsive and intuitive user interface.
- Backend: Node.js-based API server, handling authentication, feature flag operations, and more.
- Infrastructure: Deployed on AWS using a cost-effective architecture, leveraging EC2, S3, and Terraform for infrastructure as code.
- A/B Testing: Enable or disable features for specific user segments to test different versions of a feature.
- Gradual Rollouts: Roll out new features to a small percentage of users before a full release.
- Quick Rollbacks: Instantly disable a feature if issues are detected, without redeploying the application.
To optimize costs while maintaining proper environment isolation, this project uses a shared database strategy:
-
Single Database Host: The
stagingenvironment hosts a PostgreSQL database server that is used by both AWS environments.- Reduces costs by running only one database instance
- Development uses a local database for faster development
- All AWS database connections are secured within the VPC
-
Environment-Specific Databases: While sharing the same database server, each environment has its own dedicated database:
- Local database for development (not on AWS)
swash_flag_stagingfor stagingswash_flag_prodfor production
-
Proper Isolation: Each environment is fully isolated from others:
- Local development runs entirely on your machine
- Separate EC2 instances for staging and production
- Individual S3 buckets for deployment artifacts
- Environment-specific databases on the shared database server
This approach allows you to maintain a complete testing workflow (local → staging → prod) while minimizing AWS costs by:
- Eliminating the AWS dev environment entirely
- Consolidating database resources in the staging environment
We have implemented a simplified AWS deployment workflow that uses manually created AWS resources instead of Terraform-managed infrastructure. This new approach:
- Reduces complexity and deployment times
- Leverages existing manually created AWS resources
- Uses Terraform only for deployment orchestration, not infrastructure creation
- Securely manages secrets through GitHub Actions secrets
For detailed documentation on the new workflow, see Simplified AWS Workflow Documentation.