🚀 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 build→build/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
baseUrlindocusaurus.config.jsand 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
baseUrland any subpath config. - Permissions: Ensure ownership
www-data:www-dataand read access. - Nginx errors:
sudo tail -n 200 /var/log/nginx/error.logandsudo nginx -t. - Certbot issues: Check
sudo journalctl -u certbotand 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
- Docusaurus: https://docusaurus.io/
- Nginx docs: https://nginx.org/en/docs/
- Certbot: https://certbot.eff.org/
- Let’s Encrypt: https://letsencrypt.org/
- Deployment patterns: rsync, S3 + CloudFront, Netlify, Vercel
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.