From 3daf4619108a83e6a21dc9ca8cb0546f4fcb54c9 Mon Sep 17 00:00:00 2001 From: Laurent Gonzalez Date: Mon, 6 Apr 2026 16:23:33 +0200 Subject: [PATCH] feat(docs): provide nginx config and guidance for deployment, firewall and ssl --- README.md | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++---- nginx.conf | 40 +++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 nginx.conf diff --git a/README.md b/README.md index 6ab1b25..18b5d15 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,9 @@ When an event reaches its deadline, the share link stops working, all VM credent ```bash bash setup.sh + +cp .env.example .env + docker compose --profile master up -d --build ``` @@ -136,12 +139,7 @@ For development with hot-reloading: docker compose --profile dev up --build ``` -To run a slave node on another machine: - -```bash -bash setup.sh -docker compose --profile slave up -d --build -``` +To run a slave node on another machine, use the `slave` and follow the guide on the frontend: ## Configuration @@ -158,6 +156,77 @@ Copy `.env.example` to `.env` and adjust as needed. Key variables: | `BACKEND_PORT` | `8080` | Backend API port | | `VITE_PORT` | `3000` | Frontend port | +## Deployment + +### Reverse Proxy (nginx) + +In production, you should place nginx in front of the application to serve both the frontend and backend on a single port. A ready-to-use configuration is provided in [`nginx.conf`](./nginx.conf). + +Install it: + +```bash +sudo cp nginx.conf /etc/nginx/sites-available/distribox +sudo ln -s /etc/nginx/sites-available/distribox /etc/nginx/sites-enabled/ +sudo nginx -t && sudo systemctl reload nginx +``` + +This configuration: +- Listens on port **80** and routes traffic to the frontend (port 3000) and backend (port 8080) +- Proxies WebSocket connections for VM streaming (`/tunnel`) +- All other backend routes (`/auth`, `/vms`, `/images`, etc.) are forwarded to the API + +> Note: If you change port configuration for the deployment, we trust you will update the reverse proxy configuration accordingly. + +After enabling the reverse proxy, update your `.env` so the frontend calls the backend through nginx instead of directly: + +```env +VITE_API_DOMAIN=http://your-domain.com +FRONTEND_URL=http://your-domain.com +``` + +### Firewall + +VNC servers listen on ports 5900-5999 on the host. These must **not** be exposed to the network -- VM streaming is handled securely through the Guacamole WebSocket tunnel. Block external access with your firewall: + +```bash +# ufw +sudo ufw deny 5900:5999/tcp + +# or iptables +sudo iptables -A INPUT -p tcp --dport 5900:5999 -j DROP +``` + +### SSL is STRONGLY RECOMMENDED + +Distribox should be served over HTTPS. Without SSL: + +- **Clipboard will not work.** The browser Clipboard API (`navigator.clipboard`) is only available in [secure contexts](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API#security_considerations) (HTTPS). Copying VM credentials, event links, or any other data from the dashboard will silently fail on plain HTTP. +- **Pasting into VMs will not work.** The Guacamole client uses the Clipboard API to sync your clipboard with the remote VM. Without HTTPS, you will not be able to paste text into a VM session from your browser. + +The easiest way to set up SSL is with [Certbot](https://certbot.eff.org/) (Let's Encrypt): + +```bash +sudo apt install certbot python3-certbot-nginx +sudo certbot --nginx -d your-domain.com +``` + +Certbot will automatically modify your nginx configuration to: +- Redirect HTTP (port 80) to HTTPS (port 443) +- Install and renew your TLS certificate + +After running Certbot, update your `.env`: + +```env +VITE_API_DOMAIN=https://your-domain.com +FRONTEND_URL=https://your-domain.com +``` + +Certbot sets up automatic renewal via a systemd timer. You can verify it with: + +```bash +sudo certbot renew --dry-run +``` + ## Tech Stack - **Backend:** FastAPI, SQLModel, PostgreSQL, libvirt, KVM/QEMU diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..6e1f2ea --- /dev/null +++ b/nginx.conf @@ -0,0 +1,40 @@ +server { + listen 80; + server_name _; + + # Backend API routes (FastAPI on port 8080) + location ~ ^/(auth|vms|images|host|events|slaves|policies|users|docs|openapi\.json|redoc) { + proxy_pass http://127.0.0.1:8080; + proxy_http_version 1.1; + 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; + } + + # WebSocket tunnel for Guacamole VNC streaming + location /tunnel { + proxy_pass http://127.0.0.1:8080; + 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; + + # WebSocket connections can be long-lived + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + } + + # Frontend (React app on port 3000) — catch-all + location / { + proxy_pass http://127.0.0.1:3000; + proxy_http_version 1.1; + 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; + } +}