Nakama on Ubuntu 24.04 on Azure User Guide
Overview
This image runs Nakama 3.40.0, the open source realtime backend for games and apps by Heroic Labs, on Ubuntu 24.04 LTS. Nakama gives your client SDKs one backend for user authentication, realtime multiplayer over WebSocket, a matchmaker, parties and chat, leaderboards and tournaments, friends and groups, and a flexible storage engine, and it can be extended with server side runtime code in Lua, Go or JavaScript. A built in admin Console web UI lets you inspect players, storage, leaderboards, matches and server configuration. It ships as a single self-contained Go binary, run by an unprivileged nakama system account under a systemd service that starts it on boot and restarts it on failure, backed by a local PostgreSQL 16 database.
Nakama exposes two network surfaces. The client API on port 7350 is what your game and app clients connect to (REST, gRPC and WebSocket). The admin Console listens on the loopback address 127.0.0.1:7351 by design and is never exposed directly; nginx is installed as a reverse proxy on port 80 that forwards Console requests to it, including the WebSocket connections the dashboard uses for live updates. PostgreSQL is bound to loopback only.
What is included:
- Nakama 3.40.0 (official release binary), run by systemd as the unprivileged
nakamauser - The client API on
:7350(REST / gRPC / WebSocket) for your game and app clients - The admin Console on
:80(nginx reverse proxy to127.0.0.1:7351) - Per-VM secrets generated on first boot: a Console admin username and password, the client server key, the session and runtime keys, and the PostgreSQL password. No default login ships
- PostgreSQL 16, bound to loopback, holding accounts, storage, leaderboards, matches and more
postgresql.service,nakama.serviceandnginx.serviceas systemd units, enabled and active- An unauthenticated
/healthzendpoint for Azure Load Balancer health probes - 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point; size up for busier titles. NSG inbound: allow 22/tcp from your management network, 80/tcp for the admin Console, and 7350/tcp for the client API your game clients connect to. Nakama serves plain HTTP; for production, terminate TLS in front of it with your own domain.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Nakama by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22), HTTP (80) and custom TCP 7350. Then Review + create then Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name nakama \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name nakama --port 80 --priority 1010
az vm open-port --resource-group <your-rg> --name nakama --port 7350 --priority 1020
Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 - Confirm the services are running
Nakama is run by systemd as the nakama user. The admin Console is served by nginx on port 80, which reverse-proxies to the Console on 127.0.0.1:7351; the client API listens on :7350; both talk to PostgreSQL on 127.0.0.1:5432. Confirm all three services are active, and note that only nginx (:80) and the client API (:7350) listen on a public address - the Console and PostgreSQL are bound to loopback:
systemctl is-active postgresql nakama nginx nakama-firstboot
sudo ss -tlnp | grep -E ':80 |:7350 |:7351 |:5432 '
Expected output:
active
active
active
active
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 200 127.0.0.1:5432 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:7351 0.0.0.0:*
LISTEN 0 511 [::]:80 [::]:*
LISTEN 0 4096 *:7350 *:*

Step 5 - Retrieve your Console credentials and server key
On the first boot of every VM, nakama-firstboot.service generates a unique Console admin username and password, a client server key, the session and runtime keys, and the PostgreSQL password, then runs the database migrations. It writes the Console URL, username, password and server key into a root-only file. Read it with:
sudo cat /root/nakama-credentials.txt
There is no default or shared credential in the image. Nakama normally ships with a default Console login of admin / password and a default client server key of defaultkey; on this image both have been rotated away and no longer work. The Console username, Console password and server key are all unique to this VM. Store them somewhere safe.

Step 6 - Confirm the version and health endpoints
nginx serves an unauthenticated /healthz endpoint for load balancer probes; Nakama itself serves /healthcheck on the client API port. Confirm the Nakama and PostgreSQL versions and that both surfaces respond:
nakama --version
psql --version
curl -sI http://127.0.0.1/healthz | head -1
curl -s -o /dev/null -w 'Console UI (:80): %{http_code}\n' http://127.0.0.1/
curl -s -o /dev/null -w 'Client API (:7350): %{http_code}\n' http://127.0.0.1:7350/healthcheck
Expected output:
3.40.0+d4d92f93f
psql (PostgreSQL) 16.14 (Ubuntu 16.14-0ubuntu0.24.04.1)
HTTP/1.1 200 OK
Console UI (:80): 200
Client API (:7350): 200

Step 7 - The local PostgreSQL backend
Everything Nakama stores - accounts, storage objects, leaderboards, matches, notifications and more - lives in the local nakama PostgreSQL database, owned by the nakama role and reachable only over loopback. The image ships with the schema migrated and no application accounts (they are created by your clients at runtime):
sudo -u postgres psql -l | grep nakama
sudo -u postgres psql -d nakama -tAc "SELECT count(*) FROM information_schema.tables WHERE table_schema='public'"
sudo -u postgres psql -d nakama -tAc "SELECT count(*) FROM users"

Step 8 - Sign in to the admin Console
Browse to http://<vm-public-ip>/. Enter the Console username and password from Step 5.

Because the Console is fronted by nginx and its API calls are same origin, signing in over the Azure public IP works out of the box. For production, put the Console behind your own hostname and a TLS-terminating reverse proxy or Azure Application Gateway.
Step 9 - The status dashboard
After signing in you land on the Dashboard, a realtime view of your server: current sessions (concurrent users), presences, active parties, authoritative matches and goroutines, alongside per-node status and live processing latency, request rate and throughput graphs. This is where you keep an eye on a running game backend.

Step 10 - Explore players and accounts
Open Players from the left navigation to browse every registered account by user ID, username, email, social provider ID or device ID. From here you can inspect a player's profile, wallet, friends, groups and storage, and ban or delete accounts. Accounts are created by your clients when they authenticate for the first time (by device, email, custom ID or a social provider), so this list grows as players join.

Step 11 - Browse the storage engine
Open Storage to browse the storage engine, where Nakama keeps arbitrary JSON objects associated with users - player progress, inventory, settings and other game data - organised by collection and key. You can search by user ID, filter by collection, and create, edit or delete objects directly from the Console.

Step 12 - Connect a game client
Your game and app clients connect to the client API on port 7350 using the per-VM server key from Step 5. Point a Nakama client SDK (Unity, Unreal, Godot, JavaScript, C#, and others) at http://<vm-public-ip>:7350 with that server key, then authenticate a device, email or social account and open a realtime socket. You can confirm the API accepts the server key straight from the VM - this authenticates a device account and returns a session token:
SERVER_KEY=$(sudo grep '^NAKAMA_SERVER_KEY=' /root/nakama-credentials.txt | cut -d= -f2-)
curl -s -u "${SERVER_KEY}:" -X POST -H 'Content-Type: application/json' \
--data '{"id":"example-device-0001"}' \
'http://127.0.0.1:7350/v2/account/authenticate/device?create=true'
A JSON body containing a token (a session JWT) confirms the client API is working. See the Nakama client documentation for the SDK for your engine.
Maintenance
- Back up your data: everything Nakama stores lives in the local
nakamaPostgreSQL database. Snapshot the OS disk, or usepg_dump nakamafor logical backups. - Configuration: the runtime configuration lives in
/etc/nakama/config.yml(ownedroot:nakama, mode 0640). Change a setting there and runsudo systemctl restart nakama. - Security updates: unattended security upgrades are enabled, so the OS keeps itself patched. Reboot when a new kernel is installed.
- TLS: for production, front the Console and client API with your own domain and a TLS-terminating reverse proxy or Azure Application Gateway.
- Rotate secrets: to force a fresh set of per-VM secrets, stop
nakama, drop thenakamadatabase and role, remove/var/lib/cloudimg/nakama-firstboot.done, and reboot; first boot regenerates everything cleanly.
Support
cloudimg provides 24/7/365 expert technical support for this image. Contact support@cloudimg.co.uk. Nakama is licensed under the Apache License 2.0. This image is provided by cloudimg; additional charges apply for build, maintenance and 24/7 support.