Introduction: Why Self-Hosting Strapi 5 Makes Business Sense
In today's digital landscape, content management systems (CMS) form the backbone of most modern websites and applications. While cloud-hosted solutions offer convenience, self-hosting on a Virtual Private Server (VPS) provides unparalleled control, security, and cost-effectiveness for growing businesses.
Strapi 5, the latest iteration of the popular open-source headless CMS, delivers exceptional flexibility for developers while maintaining an intuitive interface for content editors. When deployed correctly on a VPS, it creates a powerful foundation for scalable content-driven experiences across web, mobile, and IoT platforms.
This comprehensive guide walks technical teams through establishing a production-ready Strapi 5 instance on a VPS in under 60 minutes. Whether you're migrating from a cloud-hosted solution or building from scratch, these battle-tested steps ensure a secure, optimized deployment that maximizes performance while minimizing operational costs.
Key Benefit: Self-hosting Strapi 5 on a VPS typically reduces monthly hosting costs by 40-70% compared to equivalent managed services while providing complete control over your infrastructure and data.
Prerequisites: What You'll Need
Before diving into the deployment process, ensure you have:
- A VPS instance with at least 2GB RAM and 1 vCPU (recommended providers: DigitalOcean, Linode, or Vultr)
- Domain name with DNS management access
- SSH access to your VPS (terminal for Mac/Linux or PuTTY for Windows)
- Basic command line knowledge and familiarity with Node.js ecosystems
- Existing Strapi project (or create one with
npx create-strapi-app@latest my-project
)
Pro Tip: While 2GB RAM is the minimum recommendation, allocating 4GB significantly improves build performance when working with complex content types or numerous API endpoints.
Step 1: Initial VPS Configuration and Security Hardening
Your VPS security forms the foundation of your Strapi deployment. Let's establish a robust environment before installing any application components.
1.1 Accessing Your VPS via SSH
Connect to your newly provisioned server using:
ssh username@YOUR_SERVER_IP
If you encounter connection issues due to known_hosts
errors, apply these permissions:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/known_hosts
1.2 Setting the Hostname and Configuring DNS
Establish a proper hostname for system identification:
sudo hostnamectl set-hostname content.yourdomain.com
Next, update your hosts file to reflect this configuration:
sudo nano /etc/hosts
Add the following line:
1YOUR_SERVER_IP content.yourdomain.com
In your domain registrar's DNS settings, create an A record that points content.yourdomain.com
to your server's IP address. This configuration typically propagates within 30 minutes to 24 hours, depending on your DNS provider.
1.3 System Updates and Essential Packages
Ensure your system packages are current to patch potential security vulnerabilities:
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git unzip ufw
Step 2: Setting Up the Database Environment
Strapi 5 supports multiple database systems, but PostgreSQL offers the best combination of performance, reliability, and feature support for production deployments.
2.1 PostgreSQL Installation
Install PostgreSQL server and client tools:
sudo apt install -y postgresql postgresql-contrib
2.2 Database and User Configuration
Create a dedicated database and user for your Strapi application:
sudo -i -u postgres
psql
Inside the PostgreSQL console, execute:
1CREATE DATABASE strapidb;
2CREATE USER strapiuser WITH ENCRYPTED PASSWORD 'YOUR_SECURE_PASSWORD';
3GRANT ALL PRIVILEGES ON DATABASE strapidb TO strapiuser;
4\q
5exit
Security Note: Generate a strong, unique password for your database user. Consider using
openssl rand -hex 16
to create a cryptographically secure random string.
Step 3: Node.js Environment Setup
Strapi 5 requires Node.js 18 or higher. Let's install the LTS version for optimal stability.
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
Verify the installation with:
node -v # Should show v18.x.x or higher
npm -v # Should show 8.x.x or higher
Step 4: Deploying Your Strapi 5 Application
With our environment prepared, we can now deploy the Strapi application itself.
4.1 Clone Your Repository
If your Strapi project is hosted in a Git repository (recommended for team environments):
cd ~
git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git strapi-production
cd strapi-production
Alternatively, you can transfer your local project via SCP or SFTP.
4.2 Installing Dependencies
Install required packages and production dependencies:
npm install
npm install pg dotenv --save
4.3 Environment Configuration for Production
Create a dedicated production environment configuration:
mkdir -p config/env/production
touch config/env/production/.env
Edit this file with your preferred text editor and add:
1HOST=0.0.0.0
2PORT=1337
3APP_KEYS=key1,key2,key3,key4
4API_TOKEN_SALT=YOUR_TOKEN_SALT
5ADMIN_JWT_SECRET=YOUR_ADMIN_JWT
6JWT_SECRET=YOUR_JWT_SECRET
7TRANSFER_TOKEN_SALT=YOUR_TRANSFER_SALT
8
9# Database
10DATABASE_CLIENT=postgres
11DATABASE_HOST=localhost
12DATABASE_PORT=5432
13DATABASE_NAME=strapidb
14DATABASE_USERNAME=strapiuser
15DATABASE_PASSWORD=YOUR_SECURE_PASSWORD
16DATABASE_SSL=false
For the various secret keys, generate random strings:
openssl rand -hex 32 # Run this multiple times for each key
4.4 Database Connection Configuration
Create a database configuration file specific to production:
nano config/env/production/database.ts
Add the following configuration:
1export default ({ env }) => ({
2 connection: {
3 client: env('DATABASE_CLIENT', 'postgres'),
4 connection: {
5 host: env('DATABASE_HOST', 'localhost'),
6 port: env.int('DATABASE_PORT', 5432),
7 database: env('DATABASE_NAME', 'strapidb'),
8 user: env('DATABASE_USERNAME', 'strapiuser'),
9 password: env('DATABASE_PASSWORD'),
10 ssl: env.bool('DATABASE_SSL', false),
11 },
12 debug: false,
13 },
14});
4.5 Building for Production
Build your Strapi application for production deployment:
NODE_ENV=production npm run build
This process may take several minutes, especially on VPS instances with limited resources.
Step 5: Process Management with PM2
To ensure your Strapi application runs continuously and restarts automatically after server reboots, we'll implement PM2.
5.1 Installing PM2
npm install -g pm2
5.2 Starting Strapi with PM2
pm2 start npm --name "strapi-production" -- run start
5.3 Configuring PM2 Startup
pm2 save
pm2 startup systemd
Follow the instructions provided by the pm2 startup
command to enable automatic startup.
Step 6: Reverse Proxy with Nginx and SSL
To expose your Strapi instance securely to the internet, we'll use Nginx as a reverse proxy with SSL encryption.
6.1 Installing Nginx
sudo apt install -y nginx
6.2 Configuring Nginx
Create a new Nginx configuration file:
sudo nano /etc/nginx/sites-available/strapi
Add the following configuration:
1server {
2 server_name content.yourdomain.com;
3
4 location / {
5 proxy_pass http://localhost:1337;
6 proxy_http_version 1.1;
7 proxy_set_header X-Forwarded-Host $host;
8 proxy_set_header X-Forwarded-Server $host;
9 proxy_set_header X-Real-IP $remote_addr;
10 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
11 proxy_set_header X-Forwarded-Proto $scheme;
12 proxy_set_header Host $http_host;
13 proxy_set_header Upgrade $http_upgrade;
14 proxy_set_header Connection "Upgrade";
15 proxy_pass_request_headers on;
16 }
17}
Enable this configuration:
sudo ln -s /etc/nginx/sites-available/strapi /etc/nginx/sites-enabled/
sudo nginx -t # Test configuration
sudo systemctl restart nginx
6.3 SSL Certificate with Let's Encrypt
Secure your application with a free SSL certificate:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d content.yourdomain.com
Follow the prompts to complete the SSL configuration.
Step 7: Firewall Configuration
Implement a basic firewall to protect your server:
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
Verify the firewall status:
sudo ufw status
Step 8: Data Migration (For Existing Projects)
If you're migrating from Strapi Cloud or another hosting provider, you'll need to transfer your data.
8.1 Using Strapi's Transfer Tool
For automated migration from another Strapi instance:
npx strapi transfer --from=remote --url=https://YOUR_EXISTING_STRAPI/admin --token=YOUR_TRANSFER_TOKEN
8.2 Manual Database Migration
If automatic transfer isn't available:
-
Export from source:
bashpg_dump -h SOURCE_HOST -U SOURCE_USER -d SOURCE_DB -F c -f backup.dump
-
Transfer to your VPS:
bashscp backup.dump username@YOUR_SERVER_IP:/home/username/
-
Restore on your VPS:
bashpg_restore -U strapiuser -d strapidb -F c backup.dump
8.3 Media Files Transfer
For transferring uploads and media files:
rsync -avz -e ssh /path/to/local/uploads/ username@YOUR_SERVER_IP:/home/username/strapi-production/public/uploads/
Step 9: Performance Optimization
Fine-tune your Strapi deployment for optimal performance:
9.1 Node.js Memory Allocation
Edit your PM2 configuration:
pm2 stop strapi-production
pm2 start npm --name "strapi-production" --node-args="--max_old_space_size=2048" -- run start
pm2 save
9.2 Nginx Caching for Static Assets
Enhance Nginx configuration for static asset caching:
sudo nano /etc/nginx/sites-available/strapi
Add within the server block:
1location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
2 proxy_pass http://localhost:1337;
3 expires 30d;
4 add_header Cache-Control "public, no-transform";
5}
Restart Nginx:
sudo systemctl restart nginx
Step 10: Maintenance and Update Strategy
Establish a robust maintenance routine for long-term stability:
10.1 Regular Backups
Set up automated daily database backups:
mkdir -p ~/backups
crontab -e
Add:
10 0 * * * pg_dump -U strapiuser -d strapidb -F c -f ~/backups/strapi-backup-$(date +\%Y\%m\%d).dump
10.2 Update Procedure
When updating your Strapi application:
-
Pull latest changes:
bashcd ~/strapi-production git pull origin main
-
Install dependencies:
bashnpm install
-
Rebuild and restart:
bashNODE_ENV=production npm run build pm2 restart strapi-production
10.3 Monitoring
Implement basic monitoring with PM2:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7
Conclusion: Your Strapi Deployment is Complete
Following this guide, you've successfully deployed a production-ready Strapi 5 instance on your VPS with:
- PostgreSQL database integration
- Process management with PM2
- Secure HTTPS access through Nginx
- Automated backups
- Performance optimizations
Your Strapi CMS is now ready to power your content-driven digital experiences with maximum flexibility and control at a fraction of the cost of cloud-hosted alternatives.
Did you know? Self-hosting Strapi can reduce your total cost of ownership by up to 65% compared to equivalent managed SaaS alternatives over a two-year period.
Need Expert Development Support?
At Ideaflow Studio, we specialize in crafting exceptional digital experiences powered by modern headless CMS architectures. Our team of certified Strapi experts can help you:
- Design and implement custom content models optimized for your business needs
- Develop feature-rich front-end applications using Next.js, Nuxt, or React
- Optimize your existing Strapi deployment for maximum performance and security
- Migrate from legacy CMS platforms to a modern headless architecture
Contact us today at hello@ideaflow.studio to discuss how we can help accelerate your digital transformation with Strapi.
*[VPS]: Virtual Private Server *[CMS]: Content Management System