Guides · Deploy
From the zip to a live HTTPS server
Put the backend you generated on a small server with HTTPS, keep it running, and check it with the self-test. It works the same on Hetzner, DigitalOcean, OVHcloud, Linode or any other host, with Ubuntu or Windows Server.
- About 20 minutes the first time
- Ubuntu 24.04 or Windows Server
- Base or Advanced
- Tested on Ubuntu 24.04 and Windows Server 2025
What you need
- A server (VPS) with Ubuntu 24.04 (or Windows Server 2019 or newer: see the Windows route). The smallest plan is plenty to start (1 to 2 GB of memory; 2 GB or more for Windows). You'll get its IP address and a root (or Administrator) password or SSH key.
- A domain name for your backend, for example
api.mygame.com. HTTPS needs one. - Your download from BackendGen.dev, unzipped. These steps use the backend folder, for example
MyGame_Backend.
verify-backend.js, and it comes in every backend you download, in the same folder as server.js. There's nothing extra to install: it runs with the same Node.js.
- On the server:
node verify-backend.js https://api.mygame.comin the backend folder (step 9). - On your own PC: the same command in your copy of the backend folder (run
npm installthere once). It signs in as admin with the password in.env, so use the same.envas the server. - In Unity: the generator's Verify My Backend button runs this same file and shows the report in a window.
- Business backends:
npm run self-test.
The steps
Point your domain at the server
Where you bought the domain, add a DNS record: type A, name
api(forapi.mygame.com), value your server's IP address. Do this first: it can take a few minutes to start working, and the HTTPS step needs it.Connect and update
From your PC (Windows PowerShell, macOS or Linux terminal), connect over SSH and bring the server up to date. Replace the IP with yours.
ssh root@203.0.113.10 sudo apt update && sudo apt upgrade -yFirewall
Allow SSH (so you can still connect), plus HTTP and HTTPS for Caddy. Your backend's own port stays closed: only Caddy talks to it. When
ufw enableasks whether to proceed, answer y.sudo ufw allow OpenSSH sudo ufw allow 80 sudo ufw allow 443 sudo ufw enableInstall Node.js
Your backend needs Node.js 22 or newer. Ubuntu's own package is older, so install Node.js 22 (a supported LTS version) from NodeSource:
curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh sudo -E bash nodesource_setup.sh sudo apt-get install -y nodejs node -vIt prints a version starting with
v22.Copy your backend
On your PC, in the folder that contains your backend folder, copy it to the server.
scpis built into Windows 10 and 11, macOS and Linux. (Prefer a window? WinSCP or FileZilla work too.)scp -r MyGame_Backend root@203.0.113.10:/opt/mygameCopy it with its
.envfile (it holds your admin password and keys), but without anode_modulesfolder if you ran it on your PC: that gets installed on the server in the next step.Install and set it up
Back on the server:
cd /opt/mygame npm install --omit=dev nano .envIn
.env, find the line# TRUST_PROXY=1and remove the#so it readsTRUST_PROXY=1. That lets the backend see players' real IP addresses behind Caddy, so its rate limits work. Save with Ctrl+O, Enter, then Ctrl+X.Keep it running (PM2)
Don't use
start-localhere: it stops when you close the window. PM2 keeps your backend running in the background, restarts it if it crashes, and starts it again after a reboot.sudo npm install -g pm2 pm2 start server.js --name mygame pm2 save pm2 startupIf
pm2 startupprints a line starting withsudo env PATH=…, copy that line and run it. (As root it sets itself up straight away.)curl http://127.0.0.1:3000/healthzIt answers with
{"ok":true,...}. Your backend uses port 3000 unless you chose another one in the generator.HTTPS with Caddy
Caddy gets a free HTTPS certificate for your domain and renews it by itself. Install it with the commands from Caddy's own instructions:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curlcurl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpgcurl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.listsudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpgsudo chmod o+r /etc/apt/sources.list.d/caddy-stable.listsudo apt updatesudo apt install caddyThen replace Caddy's settings with your domain:
sudo nano /etc/caddy/CaddyfileDelete what's there and put in these three lines (with your domain and port):
api.mygame.com { reverse_proxy 127.0.0.1:3000 }Advanced licence? Use the ready-made
deploy/Caddyfilefrom your backend folder instead (put your domain in place ofgame.example.com): it also keeps live updates flowing. Then reload Caddy:sudo systemctl reload caddyOpen
https://api.mygame.com/healthzin your browser: a padlock, and{"ok":true,...}.Run the self-test
On the server, in your backend folder, point the self-test (
verify-backend.js, it came in your download) at your live address. It checks the server from the outside, the way players reach it, and prints a pass/fail report.cd /opt/mygame node verify-backend.js https://api.mygame.comIt ends with something like
31 passed, 0 warning(s), 0 failed. The exact number depends on the features you chose. Anything that fails comes with a hint on how to fix it.Connect your game
- Unity: on your client component, untick Use Localhost, set Production Ip to
api.mygame.comand tick Use Https. - Godot: set
Backend.url = "https://api.mygame.com". - JavaScript: give the client
url: "https://api.mygame.com".
- Unity: on your client component, untick Use Localhost, set Production Ip to
We ran these steps on Ubuntu 24.04 with a freshly generated backend: installing it, PM2 (including a crash and a restart), Caddy with HTTPS in front, and the self-test, which passed all 31 checks. The Node.js and Caddy install commands are the official ones from NodeSource and Caddy.
Advanced: the Docker Compose route
With the Advanced licence your download also has a Dockerfile and docker-compose.yml (the backend plus Redis). Instead of steps 4, 6 and 7:
- Install Docker with Docker's own instructions for Ubuntu.
- Copy the backend folder to the server (step 5) and set
TRUST_PROXY=1in.env(step 6). - Check the backend's
portsline indocker-compose.ymlreads"127.0.0.1:3000:3000/tcp"(downloads from 30 October 2026 already do). If it says"3000:3000/tcp", add127.0.0.1:in front. - Start it:
docker compose up -d --build. It restarts by itself after crashes and reboots.
Why 127.0.0.1:? Docker opens published ports past Ubuntu's firewall. With 127.0.0.1: in front, only Caddy on the same server can reach the backend, and everyone else has to come in over HTTPS.
Then carry on with Caddy (step 8), the self-test (step 9) and your game (step 10). The PM2 route above was tested end to end on Ubuntu 24.04; this route uses the Docker files in your Advanced download.
The Windows Server route
Prefer Windows Server (2019, 2022 or 2025)? It's the same pieces: Node.js, PM2 to keep the backend running, Caddy for HTTPS, then the self-test. You work over Remote Desktop, in PowerShell.
When you paste several lines at once, Windows Terminal may ask whether to paste them anyway. Click Paste anyway, then press Enter if the last line doesn't run by itself.
Point your domain at the server
The same as step 1: an A record, name
api, value your server's IP address.Connect with Remote Desktop
On your PC, open Remote Desktop Connection, type the server's IP address and sign in as Administrator. On the server, right-click the Start button and open Windows PowerShell (Admin) or Terminal (Admin). Run the commands below there.
Firewall
Open HTTP and HTTPS for Caddy. Your backend's own port gets no rule, so Windows keeps it closed to the outside.
New-NetFirewallRule -DisplayName "Caddy HTTP" -Direction Inbound -Protocol TCP -LocalPort 80 -Action AllowNew-NetFirewallRule -DisplayName "Caddy HTTPS" -Direction Inbound -Protocol TCP -LocalPort 443 -Action AllowIf your host has its own firewall in its control panel, open ports 80 and 443 there too. If Windows ever asks whether to let Node.js through the firewall, say no: only Caddy needs to reach it.
Install Node.js
On the server, download the LTS Windows installer (
.msi) from nodejs.org and run it with the default options. You don't need the extra "tools for native modules". Then close PowerShell, open it again as Admin, and check:node -vIt prints a version,
v22or newer.Copy your backend
Copy the backend folder on your PC and paste it into the server's Remote Desktop window, for example as
C:\Games\MyGame_Backend. Remote Desktop copies files through the clipboard.Copy it with its
.envfile (it holds your admin password and keys), but without anode_modulesfolder: that gets installed on the server in the next step.Install and set it up
cd C:\Games\MyGame_Backend npm install --omit=dev notepad .envIn
.env, change# TRUST_PROXY=1toTRUST_PROXY=1(remove the#), then save and close Notepad.Keep it running (PM2)
Start the backend with PM2, the same as on Linux:
npm install -g pm2 pm2 start server.js --name mygame pm2 savePM2 has no built-in way to start itself when Windows boots, so add a scheduled task that brings your saved backend back after every restart, before anyone signs in. Paste this as one block. It asks for your Windows password once, so the task can run while you're signed out:
$action = New-ScheduledTaskAction -Execute "$env:APPDATA\npm\pm2.cmd" -Argument "resurrect"$trigger = New-ScheduledTaskTrigger -AtStartup$cred = Get-Credential -UserName "$env:USERDOMAIN\$env:USERNAME" -Message "Your Windows password, so PM2 can start before anyone signs in"Register-ScheduledTask -TaskName "PM2 resurrect" -Action $action -Trigger $trigger -User $cred.UserName -Password $cred.GetNetworkCredential().Password -RunLevel HighestNow hand the backend over to that task, so it keeps running when you sign out of Remote Desktop, and check it:
pm2 kill Start-ScheduledTask -TaskName "PM2 resurrect" Start-Sleep -Seconds 5 pm2 status curl.exe http://127.0.0.1:3000/healthzpm2 statusshowsmygameas online, and the last line answers with{"ok":true,...}. Typecurl.exe, notcurl: in Windows PowerShell,curlis a different command.HTTPS with Caddy
Download Caddy for Windows amd64 from caddyserver.com/download, and save it as
C:\caddy\caddy.exe. Then write its settings with your domain and port. Paste the whole block:New-Item -ItemType Directory -Force C:\caddy | Out-Null @" api.mygame.com { reverse_proxy 127.0.0.1:3000 } "@ | Set-Content C:\caddy\Caddyfile C:\caddy\caddy.exe fmt --overwrite C:\caddy\CaddyfileAdvanced licence? Copy
deploy\Caddyfilefrom your backend folder toC:\caddy\Caddyfileinstead, and put your domain in place ofgame.example.com. Then check the settings and install Caddy as a Windows service, using Caddy's own instructions:C:\caddy\caddy.exe validate --config C:\caddy\Caddyfilesc.exe create caddy start= auto binPath= "C:\caddy\caddy.exe run --config C:\caddy\Caddyfile"sc.exe start caddyOpen
https://api.mygame.com/healthzin your browser: a padlock, and{"ok":true,...}. Caddy starts by itself after a restart. If you change the Caddyfile later, apply it withC:\caddy\caddy.exe reload --config C:\caddy\Caddyfile.Run the self-test
cd C:\Games\MyGame_Backend node verify-backend.js https://api.mygame.comIt ends with something like
31 passed, 0 warning(s), 0 failed. Then connect your game as in step 10.
We ran these steps on Windows Server 2025 with a generated backend: npm install (no extra build tools needed), PM2 with the start-up task (the backend then runs outside your Remote Desktop session, and PM2 restarted it after a crash), Caddy as a Windows service, and the self-test through Caddy, which passed.
Windows: if something doesn't work
| What you see | What to do |
|---|---|
"running scripts is disabled on this system" when you type npm or pm2 | Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, then try again. |
| Caddy won't start, or port 80 or 443 is "already in use" | Something else is using it, often IIS (the built-in web server). Stop it with Stop-Service W3SVC; Set-Service W3SVC -StartupType Disabled, or put your backend behind IIS instead. To see Caddy's messages, run sc.exe stop caddy, then C:\caddy\caddy.exe run --config C:\caddy\Caddyfile in the window (Ctrl+C, then sc.exe start caddy when you're done). |
| The Caddy service stops straight after it starts | Run it in the window to see why (as in the row above). If another copy of Caddy already runs on this server, both want Caddy's control port: add { admin localhost:2020 } as the first lines of C:\caddy\Caddyfile. |
| The backend isn't running after a restart | Get-ScheduledTaskInfo -TaskName "PM2 resurrect" shows when the task last ran and its result. Check you ran pm2 save after pm2 start. If you changed your Windows password, register the task again with the new one. |
Updates work the same as on Linux (below): node update.js finds your backend's PM2 process and restarts it for you.
Updates and troubleshooting
Updating later
Open your saved project on BackendGen.dev and click Download update package. Copy that folder onto the server and run node update.js in it. It finds your backend and its PM2 process by itself, backs up what it replaces, restarts the server, and rolls back if it doesn't come back healthy. Your database, .env and settings files are never touched.
If something doesn't work
| What you see | What to do |
|---|---|
The browser can't reach https://api.mygame.com | Check the DNS record points at the server (it can take a while to work) and that ports 80 and 443 are open (step 3). sudo journalctl -u caddy --no-pager -n 50 shows Caddy's messages. |
| 502 Bad Gateway | Caddy is fine but the backend isn't running, or the port differs. pm2 status, pm2 logs mygame, and check the port in the Caddyfile. |
| The self-test says the admin password is weak | Generate a new one in the generator (the New button), put it in .env as ADMIN_PASSWORD, then pm2 restart mygame. |
Changes to .env or settings don't show | pm2 restart mygame. |
| "Could not locate the bindings file" (better-sqlite3) | In the backend folder: npm rebuild better-sqlite3, then pm2 restart mygame. |
Running a business backend? The steps are the same. Check it with npm run self-test, and set publicUrl in business-config.json to your address.
Haven't got a backend yet?
Try the generator free with an account: fill in your settings and see exactly what you'd get. Buy a licence when you want to download.
Try the generator freeRead the help