
How I set up Strapi on my VPS for My Portfolio
TL;DR
- Problem: Images from Strapi were blocked due to Mixed Content when my portfolio ran on HTTPS.
- Solution: Use Nginx Reverse Proxy to serve Strapi over HTTPS.
- Result: Portfolio can fetch blog posts and images securely and reliably.
This post is to document my experience setting up Strapi CMS on a VPS and connecting it to my portfolio website.
It's written for:
- Anyone who wants to self-host their own CMS.
- Or simply curious about how to set up VPS + Strapi + Nginx Reverse Proxy.
When I worked on this project, I wanted everything to be basic and self-built, without relying on PaaS services or pre-made templates.
You might need to adjust some steps depending on where you purchased your domain.
1. Renting a VPS and Initial Setup
I rented a VPS running Ubuntu.
The very first thing to do after accessing the VPS is to update the system:
sudo apt update && sudo apt upgrade -y
This ensures your system is fully updated before installing Strapi or other software.
2. Installing Strapi
Next, I installed Strapi as usual:
npx create-strapi-app@latest my-project
cd my-project
npm run develop
At this point, Strapi runs at:
http://<VPS-IP>:1337/
Everything worked perfectly during development.
I then created two basic Collection Types:
Article
→ for blog posts.Category
→ for classifying posts.
After that, I opened API Permissions to allow read access, so my portfolio site could fetch the blog data.
3. The Issue When Going Public
When I finished development and deployed my portfolio, I encountered a critical problem:
- My portfolio runs on HTTPS (thanks to Cloudflare).
- Strapi only runs on HTTP at
http://<VPS-IP>:1337/
.
This caused the browser to block all images fetched from Strapi due to Mixed Content — browsers don't allow HTTP content inside an HTTPS site.
Result: Blog images could not load on my portfolio.
4. The Solution: Nginx Reverse Proxy
To fix this, I used Nginx Reverse Proxy.
Here's how it works:
- Nginx sits between the client and Strapi.
- It takes HTTPS requests and forwards them internally to HTTP port 1337 on the VPS.
This way, users only see a clean HTTPS domain like:
https://strapi.jokholk.dev
While internally, Strapi continues to run on HTTP.
5. Setting Up Cloudflare
I used Cloudflare to manage my domain jokholk.dev
.
First, I created an A Record:
- Type:
A
- Name:
strapi
- IPv4 address: VPS IP
- Proxy status: DNS Only (disable the orange proxy icon)
Now, strapi.jokholk.dev
points to the VPS.
Note:
- You can use any subdomain, like
cms.yourdomain.com
.- It doesn't have to be exactly
strapi
.
6. Running Strapi with PM2
To keep Strapi running in the background even after I close the terminal, I used PM2:
npm install -g pm2
pm2 start "npm run start" --name my-strapi
pm2 save
Check status:
pm2 status
PM2 ensures Strapi stays alive and restarts automatically if it crashes — perfect for production environments.
7. Installing and Configuring Nginx
Install Nginx:
sudo apt install nginx -y
Create a new config file for strapi.jokholk.dev
:
sudo nano /etc/nginx/sites-available/strapi
Add the following configuration:
server {
listen 80;
server_name strapi.jokholk.dev;
location / {
proxy_pass http://127.0.0.1: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 config:
sudo ln -s /etc/nginx/sites-available/strapi /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
8. Adding SSL with Certbot
Finally, I used Certbot to enable free SSL for my domain:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d strapi.jokholk.dev
Once completed, you can access Strapi via:
https://strapi.jokholk.dev
9. Testing the Result
- Access the CMS admin panel via:
https://strapi.jokholk.dev/admin
10. How Nginx Reverse Proxy Works
The current data flow looks like this:
[Browser] --HTTPS--> [Nginx Reverse Proxy] --HTTP:1337--> [Strapi]
- The user only interacts with a clean HTTPS domain.
- Nginx acts as the middle layer, so Strapi doesn't need to manage SSL directly.
This completely solves the Mixed Content issue in a clean way.
11. Summary of Steps
Here's what I did from start to finish:
- Rent a VPS → Install Ubuntu → Update system.
- Install Strapi and set up basic collections (
Article
,Category
). - Use PM2 to keep Strapi running.
- Configure Nginx Reverse Proxy for HTTPS access.
- Manage domain via Cloudflare using an
A
record. - Final result: Portfolio can safely fetch data from Strapi via HTTPS.