Comprehensive Guide: Deploying Strapi on AWS for Scalable Content Management
Hanzala
19 min read ⋅ Sept 27, 2024
Introduction
Deploying a robust content management system (CMS) in a scalable cloud environment is crucial for modern web applications. This comprehensive guide will walk you through deploying Strapi, a powerful headless CMS, on Amazon Web Services (AWS). We’ll cover everything from setting up your AWS environment to configuring continuous deployment.
Table of Contents
- Prerequisites
- Setting Up Your AWS Environment
- Launching an EC2 Instance
- Setting Up a PostgreSQL Database with RDS
- Configuring S3 for File Storage
- Preparing Your Strapi Project
- Deploying Strapi to EC2
- Running Strapi with PM2
- Configuring Nginx as a Reverse Proxy
- Setting Up Continuous Deployment
- Security Best Practices
- Conclusion
Prerequisites
Before we begin, ensure you have:
- An AWS account with administrative access
- A Strapi project ready for deployment
- Basic knowledge of Node.js and npm
- Familiarity with Git and GitHub
Setting Up Your AWS Environment
Creating a VPC
- Log in to your AWS Management Console.
- Navigate to the VPC dashboard.
- Click “Create VPC” and select “VPC and More”.
- Configure the following:
- Name tag:
strapi-vpc
- IPv4 CIDR block:
10.0.0.0/16
(default) - Number of Availability Zones (AZs): 2
- Number of public subnets: 2
- Number of private subnets: 2
- NAT gateways: None (to save costs, but consider adding for production)
- VPC endpoints: S3 Gateway
- Enable DNS hostnames and DNS resolution.
- Review and create the VPC.
This setup provides a secure network foundation with public subnets for your EC2 instance and private subnets for your database.
Launching an EC2 Instance
- Go to the EC2 dashboard and click “Launch Instance”.
- Choose Ubuntu Server 22.04 LTS.
- Select an instance type (at least t2.small for Strapi).
- Configure instance details:
- Network: Choose your
strapi-vpc
- Subnet: Select a public subnet
- Auto-assign Public IP: Enable
- Add storage (20GB gp2 is usually sufficient).
- Configure Security Group:
- Allow SSH (port 22) from your IP
- Allow HTTP (80) and HTTPS (443) from anywhere
- Allow custom TCP on port 1337 (for initial Strapi setup)
- Review and launch, creating or selecting an SSH key pair.
Note: Save your key pair file (.pem) securely; you’ll need it to access your instance.
Setting Up a PostgreSQL Database with RDS
- Navigate to the RDS dashboard.
- Click “Create database”.
- Choose PostgreSQL as the engine.
- Select “Free tier” for development (choose appropriately for production).
- Configure:
- DB instance identifier:
strapi-database
- Master username:
postgres
(or your preferred username) - Master password: Choose a strong password
- Under “Connectivity”:
- VPC: Choose your
strapi-vpc
- Subnet group: Create new and select your private subnets
- Public access: No
- VPC security group: Create new
- Additional configuration:
- Initial database name:
strapi
- Create database.
Note the endpoint, port, database name, username, and password.
Configuring S3 for File Storage
- Go to the S3 dashboard.
- Click “Create bucket”.
- Name your bucket (e.g.,
my-strapi-uploads
). - Choose the region closest to your users.
- Block all public access (for security).
- Enable bucket versioning.
- Create the bucket.
Preparing Your Strapi Project
On your local development machine:
- Install PostgreSQL client:
npm install pg
- Update
config/database.js
:
module.exports = ({ env }) => ({
connection: {
client: 'postgres',
connection: {
host: env('DATABASE_HOST', '127.0.0.1'),
port: env.int('DATABASE_PORT', 5432),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', ''),
password: env('DATABASE_PASSWORD', ''),
},
useNullAsDefault: true,
},
});
- Install AWS S3 upload provider:
npm install @strapi/provider-upload-aws-s3
- Configure S3 in
config/plugins.js
:
module.exports = ({ env }) => ({
upload: {
config: {
provider: 'aws-s3',
providerOptions: {
accessKeyId: env('AWS_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_ACCESS_SECRET'),
region: env('AWS_REGION'),
params: {
Bucket: env('AWS_BUCKET_NAME'),
},
},
},
},
});
- Commit these changes to your Git repository.
Deploying Strapi to EC2
- SSH into your EC2 instance:
ssh -i path/to/your-key.pem ubuntu@your-ec2-public-ip
- Update and upgrade packages:
sudo apt update && sudo apt upgrade -y
- Install Node.js and npm:
curl -fsSL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt-get install -y nodejs
- Clone your Strapi project:
git clone https://github.com/your-username/your-strapi-project.git
- Navigate to your project directory and install dependencies:
cd your-strapi-project
npm install
- Set up environment variables:
sudo nano .env
Add the following (replace with your actual values):
DATABASE_HOST=your-rds-endpoint
DATABASE_PORT=5432
DATABASE_NAME=strapi
DATABASE_USERNAME=your-db-username
DATABASE_PASSWORD=your-db-password
AWS_ACCESS_KEY_ID=your-access-key
AWS_ACCESS_SECRET=your-secret-key
AWS_REGION=your-s3-region
AWS_BUCKET_NAME=your-s3-bucket-name
Running Strapi with PM2
- Install PM2 globally:
sudo npm install pm2@latest -g
- Create an ecosystem file:
nano ecosystem.config.js
Add the following content:
module.exports = {
apps: [{
name: 'strapi',
cwd: '/home/ubuntu/your-strapi-project',
script: 'npm',
args: 'start',
env: {
NODE_ENV: 'production',
DATABASE_HOST: 'your-rds-endpoint',
DATABASE_PORT: '5432',
DATABASE_NAME: 'strapi',
DATABASE_USERNAME: 'your-db-username',
DATABASE_PASSWORD: 'your-db-password',
AWS_ACCESS_KEY_ID: 'your-access-key',
AWS_ACCESS_SECRET: 'your-secret-key',
AWS_REGION: 'your-s3-region',
AWS_BUCKET_NAME: 'your-s3-bucket-name',
},
}],
};
- Start Strapi with PM2:
pm2 start ecosystem.config.js
- Set PM2 to start on system boot:
pm2 startup systemd
Follow the command it outputs to set up the startup script.
- Save the PM2 process list:
pm2 save
Configuring Nginx as a Reverse Proxy
- Install Nginx:
sudo apt install nginx
- Create a new Nginx configuration:
sudo nano /etc/nginx/sites-available/strapi
Add the following content:
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:1337;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
- Enable the configuration:
sudo ln -s /etc/nginx/sites-available/strapi /etc/nginx/sites-enabled
- Test and restart Nginx:
sudo nginx -t
sudo systemctl restart nginx
Setting Up Continuous Deployment
- Create a webhook script:
mkdir ~/NodeWebHooks && cd ~/NodeWebHooks
nano webhook.js
Add the following content (replace with your values):
const secret = 'your-github-webhook-secret';
const repo = '/home/ubuntu/your-strapi-project';
const http = require('http');
const crypto = require('crypto');
const exec = require('child_process').exec;
const PM2_CMD = 'cd ~ && pm2 startOrRestart ecosystem.config.js';
http.createServer((req, res) => {
req.on('data', chunk => {
const signature = `sha1=${crypto
.createHmac('sha1', secret)
.update(chunk.toString())
.digest('hex')}`;
if (req.headers['x-hub-signature'] === signature) {
exec(`cd ${repo} && git pull && npm install && npm run build && ${PM2_CMD}`, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
});
}
});
res.end();
}).listen(8080);
- Set up the webhook as a system service:
sudo nano /etc/systemd/system/webhook.service
Add the following content:
[Unit]
Description=Github webhook
After=network.target
[Service]
Environment=PATH=/usr/bin:/usr/local/bin
Type=simple
User=ubuntu
ExecStart=/usr/bin/node /home/ubuntu/NodeWebHooks/webhook.js
Restart=on-failure
[Install]
WantedBy=multi-user.target
- Enable and start the webhook service:
sudo systemctl enable webhook.service
sudo systemctl start webhook
- Configure your GitHub repository to send webhook events to
http://your-domain.com:8080
.
Security Best Practices
- Keep your EC2 instance updated:
sudo apt update && sudo apt upgrade -y
- Use AWS IAM roles for EC2 instead of hard-coding AWS credentials.
- Regularly rotate database and AWS access credentials.
- Enable and configure AWS Web Application Firewall (WAF) for additional security.
- Implement HTTPS using Let’s Encrypt and Certbot.
- Regularly backup your database and Strapi uploads.
Conclusion
This comprehensive guide has walked you through deploying Strapi on AWS, from setting up your network infrastructure to configuring continuous deployment. By following these steps, you’ve created a scalable, secure, and efficient content management system.
Remember to regularly update your Strapi installation, Node.js version, and system packages to ensure you have the latest security patches and features.
As your project grows, consider implementing additional AWS services like Elastic Load Balancer for high availability, CloudFront for content delivery, and CloudWatch for monitoring and logging.
Happy building with Strapi and AWS!
Hanzala — Software Developer🎓
Thank you for reading until the end. Before you go:
- Follow me X | LinkedIn | Facebook | GitHub
- Reach Out hi@hanzala.co.in