What is Strapi?
Strapi is the leading open-source headless CMS built on Node.js and TypeScript. It provides a powerful admin panel for managing content and exposes your data through fully customizable REST and GraphQL APIs.
- • Admin Panel: Intuitive content management UI
- • REST & GraphQL: Dual API out of the box
- • TypeScript: Full type safety support
- • Extensible: Plugin ecosystem and custom fields
- • Role-Based Access: Granular permissions system
- • Media Library: Built-in asset management
Prerequisites
- • A RamNode VPS with at least 2 GB RAM and 2 vCPUs (4 GB recommended)
- • Ubuntu 24.04 LTS installed
- • A registered domain name with DNS pointed to your VPS IP
- • SSH access with a non-root sudo user
- • Basic familiarity with the Linux command line
Initial Server Setup
ssh your_user@your_server_ip
sudo apt update && sudo apt upgrade -ysudo apt install -y build-essential curl gitInstall Node.js
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejsnode -v
npm -vYou should see Node.js v22.x and npm v10.x or later. Optionally install Yarn:
npm install -g yarnInstall and Configure PostgreSQL
PostgreSQL is recommended for production — better performance, concurrency, and data integrity than SQLite.
sudo apt install -y postgresql postgresql-contrib
sudo systemctl start postgresql
sudo systemctl enable postgresqlCreate Database & User
sudo -u postgres psqlCREATE USER strapi WITH PASSWORD 'your_secure_password';
CREATE DATABASE strapidb OWNER strapi;
GRANT ALL PRIVILEGES ON DATABASE strapidb TO strapi;
ALTER ROLE strapi CREATEDB;
\qThe CREATEDB privilege is needed because Strapi manages schema-level operations during initialization and migrations.
Create Your Strapi Project
sudo mkdir -p /var/www
cd /var/www
npx create-strapi@latest my-strapi-appWhen prompted, configure:
- • Database client: postgres
- • Database name: strapidb
- • Host: 127.0.0.1 | Port: 5432
- • Username: strapi | Password: your password
- • Enable SSL: No (local PostgreSQL)
- • TypeScript: Recommended
sudo chown -R your_user:your_user /var/www/my-strapi-appConfigure Environment Variables
cd /var/www/my-strapi-app
nano .envHOST=0.0.0.0
PORT=1337
APP_KEYS=your_app_key_1,your_app_key_2,your_app_key_3,your_app_key_4
API_TOKEN_SALT=your_api_token_salt
ADMIN_JWT_SECRET=your_admin_jwt_secret
TRANSFER_TOKEN_SALT=your_transfer_token_salt
JWT_SECRET=your_jwt_secret
DATABASE_CLIENT=postgres
DATABASE_HOST=127.0.0.1
DATABASE_PORT=5432
DATABASE_NAME=strapidb
DATABASE_USERNAME=strapi
DATABASE_PASSWORD=your_secure_password
DATABASE_SSL=falseGenerate each secret with:
openssl rand -base64 32Build and Test Strapi
NODE_ENV=production npm run buildNODE_ENV=production npm run startNavigate to http://your_server_ip:1337/admin to confirm the admin panel loads. Create your first administrator account. Press Ctrl+C to stop.
Set Up PM2 Process Manager
npm install -g pm2module.exports = {
apps: [
{
name: 'strapi',
cwd: '/var/www/my-strapi-app',
script: 'npm',
args: 'run start',
env: {
NODE_ENV: 'production',
},
exp_backoff_restart_delay: 100,
max_memory_restart: '1G',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
error_file: '/var/www/my-strapi-app/logs/error.log',
out_file: '/var/www/my-strapi-app/logs/output.log',
},
],
};mkdir -p /var/www/my-strapi-app/logs
cd /var/www/my-strapi-app
pm2 start ecosystem.config.jspm2 startup systemd
pm2 savepm2 status
pm2 logs strapiConfigure Nginx Reverse Proxy
sudo apt install -y nginxupstream strapi {
server 127.0.0.1:1337;
}
server {
listen 80;
server_name your_domain.com;
client_max_body_size 50M;
location / {
proxy_pass http://strapi;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}sudo ln -s /etc/nginx/sites-available/strapi /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginxEnable SSL with Let's Encrypt
sudo apt install -y certbot python3-certbot-nginxsudo certbot --nginx -d your_domain.comsudo certbot renew --dry-runYour Strapi instance is now accessible at https://your_domain.com/admin with a valid SSL certificate.
Configure the Firewall
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw statusThis allows SSH (port 22) and HTTP/HTTPS (ports 80/443). Strapi's port 1337 is only accessible through the Nginx reverse proxy.
Configure Production URLs
module.exports = ({ env }) => ({
host: env('HOST', '0.0.0.0'),
port: env.int('PORT', 1337),
url: env('PUBLIC_URL', 'https://your_domain.com'),
app: {
keys: env.array('APP_KEYS'),
},
});Add to your .env file:
PUBLIC_URL=https://your_domain.comcd /var/www/my-strapi-app
NODE_ENV=production npm run build
pm2 restart strapiMaintenance & Management
Updating Strapi
cd /var/www/my-strapi-app
npm update
NODE_ENV=production npm run build
pm2 restart strapiDatabase Backups
pg_dump -U strapi -h 127.0.0.1 strapidb > /backups/strapidb_$(date +%Y%m%d).sqlAdd this to a cron job for automated daily backups. Store backups off-server for disaster recovery.
Monitoring Logs
pm2 logs strapi --lines 100Health Check
Strapi exposes a built-in health check at /_health (HTTP 204). Integrate with monitoring tools like UptimeRobot or your own Grafana stack.
Recommended VPS Specifications
| Use Case | RAM | vCPUs | Storage |
|---|---|---|---|
| Small blog or personal site | 2 GB | 2 | 30 GB SSD |
| Medium business site or API | 4 GB | 4 | 60 GB SSD |
| High-traffic application | 8 GB+ | 4+ | 100 GB+ SSD |
Your Stack
- • Runtime: Node.js v22 LTS
- • Database: PostgreSQL
- • Process Manager: PM2 with automatic restart
- • Web Server: Nginx reverse proxy with SSL
- • SSL: Let's Encrypt with auto-renewal
- • Firewall: UFW (SSH, HTTP, HTTPS only)
From here, extend your deployment with Strapi plugins, external media storage (Cloudinary, MinIO), or connect frontends like Next.js, Nuxt, or Astro.
