Skip to main content

🚀 Deploying Docusaurus with Nginx (English)

This document is a clear, practical, and concise guide for building, running and deploying a Docusaurus site on a Linux server (Debian/Ubuntu) with Nginx. It includes setup, build, production deployment, HTTPS with Certbot, serving at a subpath, updating, troubleshooting, and useful tips for automation and CI/CD.


Quick Overview

  • Build the static site locally or in CI: npm run buildbuild/ folder.
  • Serve static files with Nginx from /var/www/<site>.
  • Use Certbot to obtain and auto-renew HTTPS certificates.
  • For SPAs, configure Nginx to fallback to index.html (try_files).
  • For subpath hosting, set baseUrl in docusaurus.config.js and adjust Nginx.

Requirements

  • Docusaurus project source.
  • Node.js >= 20 (or project-specified).
  • npm, npx (or yarn/pnpm).
  • Linux server (Debian/Ubuntu recommended).
  • SSH + sudo access.
  • Domain name (recommended) or server IP.
  • Nginx installed.
  • Certbot (optional but recommended for HTTPS).

1. Install & Scaffold (if needed)

Create a new Docusaurus site:

npx create-docusaurus@latest my-website classic
# For TypeScript:
npx create-docusaurus@latest my-website classic --typescript

Directory structure (classic template):

  • blog/ — optional blog Markdown files
  • docs/ — documentation Markdown files
  • src/ — non-doc pages, components, and styles
  • static/ — static assets copied to final build
  • docusaurus.config.js — site config
  • sidebars.js — docs sidebar structure
  • package.json — dependencies and npm scripts

Run the dev server:

cd my-website
npm run start # opens http://localhost:3000 by default

Build production files:

npm install
npm run build # outputs static site to build/

2. Prepare Server & Nginx

Install Nginx on Debian/Ubuntu:

sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx

Create a web root and copy build output:

sudo mkdir -p /var/www/gnott
sudo rsync -av --delete build/ /var/www/gnott/
sudo chown -R www-data:www-data /var/www/gnott
sudo chmod -R 755 /var/www/gnott

Use rsync to minimize downtime during updates.


3. Nginx Configuration (HTTP → HTTPS-ready)

Create /etc/nginx/sites-available/gnott:

server {
listen 80;
server_name example.com www.example.com; # replace with your domain or use _

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

# Serve files directly, fallback for SPA routing
location / {
try_files $uri $uri/ /index.html;
}

# Long caching for static assets
location ~* \.(css|js|jpg|jpeg|gif|png|svg|ico|woff2?)$ {
try_files $uri =404;
access_log off;
add_header Cache-Control "public, max-age=31536000, immutable";
}
}

Enable and test the site:

sudo ln -s /etc/nginx/sites-available/gnott /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

4. Enable HTTPS with Certbot (Let's Encrypt)

Install Certbot and run the Nginx plugin:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
sudo certbot renew --dry-run

Open firewall ports if using UFW:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Certbot updates Nginx config automatically and sets up auto-renewal.


5. Serving from a Subpath (/docs/ or /project/)

If hosting under a subpath, update docusaurus.config.js:

module.exports = {
// ...
baseUrl: '/docs/', // trailing slash required for subpath
// ...
};

Build, then either copy build/ into /var/www/gnott/docs/ or configure Nginx:

location /docs/ {
alias /var/www/gnott/;
try_files $uri $uri/ /docs/index.html;
}

Note: alias semantics differ from root. Test paths carefully.


6. Updating / Deploy Workflow

Manual update:

cd ~/gnott
git pull
npm ci # or npm install
npm run build
sudo rsync -av --delete build/ /var/www/gnott/
sudo chown -R www-data:www-data /var/www/gnott
sudo systemctl reload nginx

CI/CD suggestions:

  • Build in CI (GitHub Actions, GitLab CI).
  • Upload build/ to server via rsync or S3 + CloudFront.
  • Use atomic deployment directories and symlink swap to avoid partial states.
  • Run linter and tests before deploying.

Example small GitHub Actions job:

# build-and-deploy.yml (sketch)
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: node-version: '20'
- run: npm ci && npm run build
- uses: appleboy/rsync-[email protected]
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
source: "build/"
target: "/var/www/gnott/"

7. Troubleshooting (Common Issues)

  • 404 on refresh (SPA): Check try_files $uri $uri/ /index.html;.
  • Wrong paths / broken links: Verify baseUrl and any subpath config.
  • Permissions: Ensure ownership www-data:www-data and read access.
  • Nginx errors: sudo tail -n 200 /var/log/nginx/error.log and sudo nginx -t.
  • Certbot issues: Check sudo journalctl -u certbot and domain DNS records.

Useful commands:

sudo systemctl status nginx
sudo nginx -t
sudo tail -n 200 /var/log/nginx/error.log
sudo journalctl -u nginx -b

8. Security & Maintenance

  • Keep OS and packages updated: sudo apt update && sudo apt upgrade.
  • Use HTTPS and HSTS (carefully).
  • Restrict SSH (keys, disable password auth, change default port if needed).
  • Monitor logs and cert renewal.
  • Limit file write access to deployment user only.

9. Performance & Caching Tips

  • Serve static assets with long Cache-Control and use content hashing (Docusaurus does this by default).
  • Enable gzip/Brotli in Nginx (use gzip on; or a Brotli plugin).
  • Use a CDN for global delivery when traffic or latency matters.

Example gzip (add to http or server block):

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 256;

10. References & Further Reading


If you want, I can:

  • Convert this to Norwegian as well.
  • Generate a production-ready GitHub Actions workflow.
  • Create a script to automate build + rsync deploy.