Skip to main content

Introduction

This guide explains a safe production strategy for Docusaurus when your VPS has limited resources.

If your VPS often shows high CPU and RAM usage, the root cause is usually running npm run build directly on the server. Docusaurus build uses Node.js tooling (bundling, minification, optimization) that can be heavy for small VPS plans.

The solution is simple: build outside the VPS, deploy only static output, and let the VPS serve files.


Pain points (what usually goes wrong)

When build runs on VPS, common issues are:

  1. CPU spikes to near 100% during asset bundling.
  2. Memory pressure from Node.js process during production build.
  3. Swap usage increases, making server very slow.
  4. OOM kills or failed deploys on small VPS.
  5. Unstable uptime because deploy workload competes with live traffic.

In short: your VPS is doing two jobs at once (build machine + web server), and small servers are not designed for that.


Offered solution

Use a static deployment workflow:

  1. Build on local machine or CI runner (GitHub Actions).
  2. Copy generated build/ files to VPS.
  3. Serve those files through Nginx/Apache.

With this approach, VPS handles only lightweight static file serving.


Step-by-step implementation

Step 1 - Build outside VPS

Run build on your laptop or CI:

npm ci
npm run build

Expected result:

  • A build/ directory is created.
  • Heavy CPU/RAM usage happens on your machine/CI, not on VPS.

Good practice:

  • Use npm ci (faster and deterministic for deployment).
  • Keep Node.js version consistent between local and CI.

Step 2 - Prepare VPS static directory

Choose a web root folder, for example:

/var/www/docusaurus

Create it once (on VPS):

sudo mkdir -p /var/www/docusaurus
sudo chown -R $USER:$USER /var/www/docusaurus

Expected result:

  • VPS has a dedicated folder for published static files.

Step 3 - Upload built files

From your local machine, sync build/ to VPS:

rsync -avz --delete ./build/ user@your-vps-ip:/var/www/docusaurus/

What flags mean:

  • -a: preserve file structure and metadata.
  • -v: verbose output.
  • -z: compress during transfer.
  • --delete: remove old files on VPS that are not in latest build.

Expected result:

  • VPS content matches exactly your latest successful build.

Step 4 - Configure Nginx to serve static files

Example Nginx server block:

server {
listen 80;
server_name your-domain.com;

root /var/www/docusaurus;
index index.html;

location / {
try_files $uri $uri/ /index.html;
}

location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?)$ {
expires 7d;
add_header Cache-Control "public, max-age=604800";
try_files $uri =404;
}
}

Then validate and reload:

sudo nginx -t
sudo systemctl reload nginx

Expected result:

  • Website is served as static files.
  • Very low memory and CPU usage in steady state.

Step 5 - Verify resource improvement

After switching workflow, check VPS metrics:

top
free -h

You should see:

  • No long-running Node build process on VPS.
  • Lower CPU spikes.
  • More stable memory usage.

Optional: automate with GitHub Actions

You can automate build + deploy so every push to main publishes automatically:

  1. GitHub Actions runs npm ci && npm run build.
  2. Action uploads/syncs build/ to VPS via SSH.
  3. Nginx instantly serves the new files.

This gives reproducible deployments and removes manual steps.


Troubleshooting quick notes

  • If deploy is slow, use rsync with SSH key auth.
  • If old files remain, ensure --delete is present.
  • If page refresh returns 404, confirm try_files ... /index.html is configured.
  • If you still run npm run build on VPS via cron/PM2, disable that job.

Final recommendation

For small VPS, treat Docusaurus as a static site:

code change -> build local/CI -> rsync build/ -> Nginx serves

This is the safest way to reduce CPU/RAM usage and keep production stable.