Gotify on Ubuntu 24.04 on Azure User Guide
Overview
Gotify is the popular open source, self-hosted push notification server. Send messages from any script, server or application over a simple REST API and receive them in real time in the bundled web app, the official Android client, or any websocket consumer — a privacy-respecting alternative to hosted push services, running on infrastructure you control.
The Gotify server is a single Go binary that serves both the REST API and the web app. It runs behind nginx as a reverse proxy on port 80. PostgreSQL is the datastore; the server listens on 127.0.0.1:8080 and the database on 127.0.0.1:5432 — both bind to the loopback interface only.
On the first boot of every deployed VM, a one-shot service recreates an empty database (which also yields a fresh per-instance session signing key), rotates the PostgreSQL password, and seeds a single administrator account with a per-instance password. Open registration is disabled. The login is written to /root/gotify-credentials.txt with mode 0600. Two VMs deployed from the same image never share credentials.

What is included:
- Gotify 2.9.1 server (single Go binary, bundles the web UI) at
/opt/gotify/gotify - nginx reverse proxy on
:80(with websocket upgrade support) in front of the Gotify server on loopback:8080 - PostgreSQL datastore, bound to loopback, with its datadir on a dedicated Azure data disk at
/var/lib/postgresql - A second dedicated Azure data disk at
/var/lib/gotifyfor uploaded application images and plugins — both disks are separate from the OS disk and re-provisioned with every VM - Per-VM administrator and PostgreSQL passwords generated at first boot, in a root-only file
gotify.service,postgresql.serviceandnginx.serviceas systemd units, enabled and active- A fully patched Ubuntu 24.04 LTS security baseline at capture time, with unattended security updates enabled
- 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point — Gotify is lightweight; scale up for very large message volumes. NSG inbound: allow 22/tcp from your management network and 80/tcp (plus 443/tcp once you enable HTTPS) from the networks your users and senders will reach Gotify on.
Step 1 — Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Gotify 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) and HTTP (80). Review the two dedicated data disks on the Disks tab, then Review + create → Create. First boot initialisation takes approximately one minute after the VM starts.
Step 2 — Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name gotify \
--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 gotify --port 80 --priority 1010
Step 3 — Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 — Verify the Gotify stack
Three systemd services make up the stack. Confirm all are active and that the open version endpoint answers through nginx:
systemctl is-active gotify postgresql nginx
curl -s http://127.0.0.1/version
All three lines read active and the version endpoint returns JSON containing "version":"2.9.1".
Confirm the Gotify server and PostgreSQL bind to loopback only, and that the two dedicated data disks are mounted:
ss -tln 2>/dev/null | grep -E ':(80|8080|5432) ' || sudo ss -tln | grep -E ':(80|8080|5432) '
df -h /var/lib/postgresql /var/lib/gotify | tail -2
Port 80 (nginx) listens on all interfaces; ports 8080 (Gotify) and 5432 (PostgreSQL) are bound to 127.0.0.1 only.

Step 5 — Retrieve your administrator login
The administrator login generated on the first boot of your VM is stored in a root-only file. It lists the Gotify URL, the administrator username (admin), the password, and the PostgreSQL credentials:
sudo cat /root/gotify-credentials.txt
Store the password in your password manager and treat the file as sensitive.
Step 6 — Verify authentication
The API rejects anonymous requests and accepts the generated administrator password. The first command reports 401 and the second 200:
curl -s -o /dev/null -w 'anonymous /current/user HTTP %{http_code}\n' http://127.0.0.1/current/user
PASS=$(sudo grep '^gotify.admin.pass=' /root/gotify-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'authenticated /current/user HTTP %{http_code}\n' -u admin:$PASS http://127.0.0.1/current/user

Step 7 — First sign-in to the web app
Open a web browser and navigate to http://<vm-public-ip>/. Sign in with the username admin and the password from /root/gotify-credentials.txt. The web app shows the message stream — all notifications, grouped by application, arriving in real time.

Step 8 — Create an application and push your first message
Senders authenticate with an application token, not your administrator password. Create an application (in the web app under Apps, or over the API as below), then push a message with its token:
PASS=$(sudo grep '^gotify.admin.pass=' /root/gotify-credentials.txt | cut -d= -f2-)
APP_TOKEN=$(curl -s -u admin:$PASS -X POST http://127.0.0.1/application -F name=server-alerts -F description='Demo application' | jq -r .token)
echo "application token: $APP_TOKEN"
curl -s -X POST "http://127.0.0.1/message?token=$APP_TOKEN" -F title='Backup finished' -F message='Nightly backup completed successfully' -F priority=5 | jq .
The message appears instantly in the web app and on every connected client. Any script or application that can issue an HTTP POST can now push notifications — replace 127.0.0.1 with your VM's address when sending from another host. Manage applications, clients and users in the web app:

Confirm the message was stored, reading the stream back over the API:
PASS=$(sudo grep '^gotify.admin.pass=' /root/gotify-credentials.txt | cut -d= -f2-)
curl -s -u admin:$PASS http://127.0.0.1/message | jq '.messages[0] | {title, message, priority}'

Step 9 — Receive messages in real time
The web app receives messages over a websocket the moment they arrive. For your phone, install the official Gotify Android client (F-Droid or Google Play), point it at http://<vm-public-ip>/ and sign in — it registers itself as a client and shows every push as a native Android notification. Any other consumer can subscribe to the stream with a client token:
curl -s -N -H "X-Gotify-Key: <client-token>" "ws://<vm-public-ip>/stream"
Because this is your own self-hosted VM, your notification traffic never leaves infrastructure you control.
Security baseline
The image is captured with the Ubuntu 24.04 security baseline fully applied (including phased updates) and ships with unattended security upgrades enabled, so your VM keeps patching itself after deployment:
cat /etc/apt/apt.conf.d/20auto-upgrades
systemctl is-enabled unattended-upgrades

Enabling HTTPS
For production use, serve Gotify over HTTPS so that login credentials and message traffic are encrypted in transit. Point a DNS A record at the VM's public IP address, then install a certificate with Certbot (replace the domain):
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com
After enabling HTTPS, open 443/tcp in the NSG, update the URL in your Android client and senders to https://, and restrict or close inbound port 80.
Backup and maintenance
All Gotify state lives on the two dedicated Azure data disks: the PostgreSQL datadir at /var/lib/postgresql (users, applications, clients, messages) and uploaded application images + plugins at /var/lib/gotify. Because both are separate from the OS disk, the simplest backup is an Azure disk snapshot:
az snapshot create --resource-group <your-rg> --name gotify-db-backup --source <data-disk-id>
For a logical database backup you can instead run sudo -u postgres pg_dump gotify and copy the dump to object storage on a schedule. Apply operating system security updates with sudo apt update && sudo apt upgrade; the services restart cleanly, and Gotify resumes serving immediately because all state is on the persistent data disks. Restart the server at any time with sudo systemctl restart gotify.
Support
This image is backed by 24/7 cloudimg support. Contact us by email and chat for deployment help, integrations, TLS termination and database administration. Gotify itself is open source software licensed under the MIT license.
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.