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.

What you need

Where's the self-test? It's 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.

The steps

  1. Point your domain at the server

    Where you bought the domain, add a DNS record: type A, name api (for api.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.

  2. 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 -y
  3. Firewall

    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 enable asks whether to proceed, answer y.

    sudo ufw allow OpenSSH
    sudo ufw allow 80
    sudo ufw allow 443
    sudo ufw enable
  4. Install 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 -v

    It prints a version starting with v22.

  5. Copy your backend

    On your PC, in the folder that contains your backend folder, copy it to the server. scp is 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/mygame

    Copy it with its .env file (it holds your admin password and keys), but without a node_modules folder if you ran it on your PC: that gets installed on the server in the next step.

  6. Install and set it up

    Back on the server:

    cd /opt/mygame
    npm install --omit=dev
    nano .env

    In .env, find the line # TRUST_PROXY=1 and remove the # so it reads TRUST_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.

  7. Keep it running (PM2)

    Don't use start-local here: 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 startup

    If pm2 startup prints a line starting with sudo env PATH=…, copy that line and run it. (As root it sets itself up straight away.)

    curl http://127.0.0.1:3000/healthz

    It answers with {"ok":true,...}. Your backend uses port 3000 unless you chose another one in the generator.

  8. 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 caddy

    Then replace Caddy's settings with your domain:

    sudo nano /etc/caddy/Caddyfile

    Delete 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/Caddyfile from your backend folder instead (put your domain in place of game.example.com): it also keeps live updates flowing. Then reload Caddy:

    sudo systemctl reload caddy

    Open https://api.mygame.com/healthz in your browser: a padlock, and {"ok":true,...}.

  9. 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.com

    It 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.

  10. Connect your game

    • Unity: on your client component, untick Use Localhost, set Production Ip to api.mygame.com and tick Use Https.
    • Godot: set Backend.url = "https://api.mygame.com".
    • JavaScript: give the client url: "https://api.mygame.com".

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:

  1. Install Docker with Docker's own instructions for Ubuntu.
  2. Copy the backend folder to the server (step 5) and set TRUST_PROXY=1 in .env (step 6).
  3. Check the backend's ports line in docker-compose.yml reads "127.0.0.1:3000:3000/tcp" (downloads from 30 October 2026 already do). If it says "3000:3000/tcp", add 127.0.0.1: in front.
  4. 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.

  1. Point your domain at the server

    The same as step 1: an A record, name api, value your server's IP address.

  2. 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.

  3. 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 Allow

    If 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.

  4. 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 -v

    It prints a version, v22 or newer.

  5. 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 .env file (it holds your admin password and keys), but without a node_modules folder: that gets installed on the server in the next step.

  6. Install and set it up

    cd C:\Games\MyGame_Backend
    npm install --omit=dev
    notepad .env

    In .env, change # TRUST_PROXY=1 to TRUST_PROXY=1 (remove the #), then save and close Notepad.

  7. 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 save

    PM2 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 Highest

    Now 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/healthz

    pm2 status shows mygame as online, and the last line answers with {"ok":true,...}. Type curl.exe, not curl: in Windows PowerShell, curl is a different command.

  8. 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\Caddyfile

    Advanced licence? Copy deploy\Caddyfile from your backend folder to C:\caddy\Caddyfile instead, and put your domain in place of game.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 caddy

    Open https://api.mygame.com/healthz in your browser: a padlock, and {"ok":true,...}. Caddy starts by itself after a restart. If you change the Caddyfile later, apply it with C:\caddy\caddy.exe reload --config C:\caddy\Caddyfile.

  9. Run the self-test

    cd C:\Games\MyGame_Backend
    node verify-backend.js https://api.mygame.com

    It 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 seeWhat to do
"running scripts is disabled on this system" when you type npm or pm2Set-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 startsRun 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 restartGet-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 seeWhat to do
The browser can't reach https://api.mygame.comCheck 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 GatewayCaddy 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 weakGenerate 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 showpm2 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