Gaming Azure

Geyser 2.11.1 on Ubuntu 24.04 on Azure User Guide

| Product: Geyser 2.11.1 on Ubuntu 24.04 on Azure

Overview

This guide covers the deployment and use of Geyser 2.11.1 on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images.

Geyser is the standard open source bridge between Minecraft: Bedrock Edition and Minecraft: Java Edition. Bedrock players on console, mobile and Windows normally cannot join a Java Edition server at all; Geyser sits in front of your Java server and translates the Bedrock protocol on the fly, so both editions can play together on infrastructure you control.

Geyser is a gateway, not a game server. This image does not include or require a bundled Minecraft server, and it ships no Mojang owned game content or assets of any kind. You bring your own Minecraft: Java Edition server, running on this VM or elsewhere, and your own Minecraft clients; Geyser only bridges the connection between them. Nothing about a working Geyser installation implies a Java server is already running anywhere — that is a separate step you control.

What you get

Capability What it means in practice
A working Bedrock listener from boot Geyser starts automatically and binds the standard Bedrock port over UDP the moment the VM is up — no manual startup step.
Real protocol proof, not a port check The image ships a self test that speaks the actual RakNet discovery protocol every Bedrock client uses, and proves a genuine reply, not merely that a process is running.
The address problem solved First boot resolves the VM's real public IP and leaves it in a connection note — the value your Bedrock clients need is right there, no guessing.
Point and edit configuration One clearly commented config.yml file. Point the java: section at your own Java server and restart.
A contained service The server runs as a dedicated no shell account under a locked down systemd sandbox. There is no admin login, no web console and no credential of any kind.

Licence

Geyser is free software licensed under the MIT License — verified from the LICENSE file bundled inside the exact jar this image ships, not from a badge.

Geyser's jar is a shaded build and bundles a small number of third party dependency licences alongside its own. All are permissive, and one is copyleft in a way that is fully compatible with redistribution:

  • /opt/geyser/licenses/LICENSE-geyser-MIT.txt — Geyser itself, MIT.
  • /opt/geyser/licenses/LICENSE-MinecraftAuth-LGPL-3.0.txt — the bundled MinecraftAuth library (handles Java/Xbox Live account authentication), GNU LGPL 3.0. Shipped unmodified, exactly as the licence permits.
  • /opt/geyser/licenses/LICENSE-thirdparty-Apache-2.0.txt and LICENSE-thirdparty-slf4j-MIT.txt — aggregated notices for further permissively licensed dependencies (Apache 2.0 and MIT/BSD style).

The same four files are also kept at /usr/share/doc/cloudimg/geyser/ for easy reference. No AGPL, SSPL or other network copyleft component exists anywhere in the shipped jar.

Minecraft is a trademark of Mojang Synergies AB. Geyser is an independent, community maintained project and is not affiliated with, endorsed by, or sponsored by Mojang or Microsoft.


Before you start

Item Value
Recommended VM size Standard_B2s (2 vCPU / 4 GiB) — Geyser itself used around 590 MB resident with default heap settings while idling with the listener bound
Bedrock listener port 19132, UDP — Minecraft: Bedrock Edition uses UDP exclusively for gameplay; this port must allow UDP traffic
SSH 22, restricted to your own address
Admin credential None exists. Geyser has no admin login, web console or credential of any kind — see Security posture
Java server Not included. You provide your own Minecraft: Java Edition server, on this VM or elsewhere, and point Geyser at it

Network security group

Bedrock Edition speaks to Geyser entirely over UDP. Opening only TCP is the single most common reason a freshly deployed Geyser "looks fine on the VM" but no Bedrock client can find it:

az network nsg rule create --resource-group <your-rg> --nsg-name <your-nsg> \
  --name geyser-bedrock-udp --priority 1010 \
  --access Allow --protocol Udp --direction Inbound \
  --source-address-prefixes Internet --destination-port-ranges 19132

Run that from your workstation with your own resource names. Do not open anything else on this VM — SSH on 22 (restricted to your own address) and the Bedrock listener are the only two things this image exposes. If your Java Edition server runs on a different machine, that machine needs its own Java port (25565 by default) reachable from this VM — that is a separate NSG on that other machine, not this one.


First boot

On first boot the VM resolves its own public IP address and writes it into a connection note for you. Geyser itself has nothing to bootstrap or protect — there is no admin credential to rotate — so the Bedrock listener starts on its own at every boot, independent of this step.

Give the VM a minute after it reports Running, then check both units:

systemctl is-active geyser-firstboot.service geyser.service

Both should report active. Then read this VM's connection note:

sudo cat /root/geyser-instance-info.txt

Expected output (your address will differ):

# Geyser — Instance Info (written by geyser-firstboot.service on first boot)
# Geyser has no admin login of any kind — this file is informational only,
# it never contains a secret or credential.
GEYSER_PUBLIC_IP=20.106.160.134
GEYSER_BEDROCK_PORT=19132
GEYSER_MOTD=cloudimg Geyser

# Point Geyser at your own Minecraft: Java Edition server by editing the
# "java:" section of /opt/geyser/config.yml, then: sudo systemctl restart geyser
# Bedrock clients connect to: udp://20.106.160.134:19132

GEYSER_PUBLIC_IP and GEYSER_BEDROCK_PORT are exactly what your Bedrock clients need. The same summary is shown on every SSH login.

Terminal showing geyser-firstboot.service and geyser.service both active, the systemd status for the running Geyser process started as the dedicated geyser user, and the per VM connection note listing the resolved public IP, the Bedrock port 19132 and the reminder to edit the java section of config.yml


Point Geyser at your Java server

Geyser ships with an honest placeholder: java.address is 127.0.0.1 and java.port is 25565, Geyser's own upstream default. There is no fake or invented backend — until you edit this, Geyser is listening correctly but has nothing to bridge to.

sudo nano /opt/geyser/config.yml

Find the java: section near the top and set it to your real server:

java:
  address: 127.0.0.1   # <- change to your Java server's address
  port: 25565           # <- change to your Java server's port
  auth-type: online      # "online" (Microsoft account), "offline", or "floodgate"
  forward-hostname: false
  • If your Java Edition server runs on this same VM, install it separately and keep address: 127.0.0.1, just correct the port: if it differs from 25565.
  • If it runs elsewhere, set address to that server's reachable IP or hostname.
  • Set auth-type to match how your Java server is configured: online if it runs in online mode (the default, requires a Microsoft account), offline if your Java server runs in offline mode, or floodgate if you have the Floodgate plugin installed on the Java server itself.

Apply the change:

sudo systemctl restart geyser

Verifying your deployment

The image carries its own protocol level check. It does not settle for "a port is open" — it speaks the real RakNet discovery protocol every Bedrock client and every third party server list tool uses:

sudo /usr/local/sbin/geyser-selftest

Expected output:

OK Bedrock RakNet unconnected-pong: edition=MCPE motd="Geyser" protocol=2168 mcversion=26.40 players=0/100

That line proves the JVM started cleanly, config.yml parsed without error, and the Bedrock RakNet listener is genuinely bound and answering with a well formed reply — independent of whether your Java backend is reachable yet. A Bedrock client performs exactly this exchange (an Unconnected Ping, answered with an Unconnected Pong carrying the MOTD) the moment it lists your server, before it ever attempts to join.

Terminal showing the geyser selftest reporting OK with a genuine Bedrock RakNet unconnected pong, the edition tag MCPE, the configured MOTD, the negotiated protocol number and the Minecraft version this Geyser build supports

If the self test fails, see Troubleshooting.


Managing the service

systemctl status geyser.service --no-pager

The server logs to the systemd journal:

sudo journalctl -u geyser.service --no-pager | tail -20

A healthy start looks like this:

[INFO] Loading extensions...
[INFO] Loaded 0 extension(s)
[INFO] Loading Geyser version 2.11.1-b1216 (git-master-1e448d6)
[INFO] Registered 199 custom block overrides.
[INFO] Registered 7 custom blocks.
[INFO] Started Geyser on UDP port 19132
[INFO] Done (4.449s)! Run /geyser help for help!

Restart at any time — Geyser holds no persistent game state of its own, only in-flight connections, which reconnect automatically from the client side:

sudo systemctl restart geyser.service

The listener surface is deliberately minimal — the Bedrock port, and SSH:

ss -uln | grep ':19132 '
ss -tln | grep -E ':(22) '

Terminal showing the running Geyser journal with the version loading, block and item overrides registering, the Bedrock listener starting on UDP port 19132 and reporting Done, followed by the listener audit showing only UDP 19132 and TCP 22 exposed


Configuration reference

Geyser's own first run generated the full config.yml this image ships, with every option documented inline:

sudo cat /opt/geyser/config.yml

The settings you are most likely to touch:

Setting This image Meaning
bedrock.address / bedrock.port 0.0.0.0 / 19132 The Bedrock listener. Leave as is unless you need to restrict which interface accepts connections.
java.address / java.port 127.0.0.1 / 25565 (placeholder) Your Java Edition server. You must edit this — see Point Geyser at your Java server.
java.auth-type online Matches Geyser's own upstream default. Change to offline or floodgate to match your Java server.
motd.primary-motd / motd.passthrough-motd Geyser / true The MOTD shown to Bedrock clients. Passthrough relays your Java server's real MOTD once it is reachable.
gameplay.enable-integrated-pack true Serves the bundled resource pack Bedrock clients need for some Geyser only features.
enable-metrics true Anonymous bStats usage reporting, Geyser's own default. Set to false to disable.

Every option is documented with a comment directly above it in the file itself — there is no separate reference to keep in sync.


Upgrading Geyser

Geyser ships as a single jar with no bundled data to migrate. config.yml is preserved across an upgrade — Geyser only adds newly introduced keys, it never removes your edits.

curl -fsSL -o /tmp/Geyser-Standalone.jar \
  https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/standalone
sudo systemctl stop geyser.service
sudo install -o geyser -g geyser -m 0644 /tmp/Geyser-Standalone.jar /opt/geyser/Geyser-Standalone.jar
sudo systemctl start geyser.service

Then confirm the new version in the journal and re-run the self test:

sudo journalctl -u geyser.service --no-pager | grep 'Loading Geyser version' | tail -1
sudo /usr/local/sbin/geyser-selftest

Security posture

Geyser has no admin login, no web console and no user database of any kind — its entire purpose is to listen on the network and forward per its configuration. This image does not invent a credential where none exists; instead, secure by default means containment and honest configuration:

  • A dedicated account. The server runs as the geyser system user with no shell and no home login.
  • A locked down sandbox. The systemd unit applies NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp and a read write allowance for /opt/geyser only.
  • A minimal surface. UDP 19132 and TCP 22 — nothing else listens, and the build fails if anything else ever does.
  • No per instance secret to leak. First boot writes only an informational connection note; there is no credential file, no default password and nothing to rotate.
cat /opt/geyser/licenses/LICENSE-geyser-MIT.txt

Terminal showing the shipped licence files for Geyser MIT, the bundled MinecraftAuth LGPL 3.0 library and the third party notices, confirming no AGPL or network copyleft component exists, alongside the geyser system user and the config.yml java section still showing the honest unedited placeholder

Recommendations:

  • Restrict the SSH rule in your NSG to your own address; only the Bedrock UDP rule needs Internet as a source.
  • Give players the address from the connection note, nothing else — there is nothing else to give.
  • If your Java server lives on a different machine, secure that machine's own Java port separately; this VM's NSG only governs Geyser's own listener.

Server components

Component Version Install path
Geyser Standalone 2.11.1 (build 1216) /opt/geyser/Geyser-Standalone.jar
OpenJDK runtime 21 (Ubuntu package, auto updated) /usr/lib/jvm
Configuration /opt/geyser/config.yml
Self test /usr/local/sbin/geyser-selftest
Licences MIT (Geyser) + LGPL 3.0 (MinecraftAuth) + Apache 2.0/MIT (third party) /opt/geyser/licenses/, /usr/share/doc/cloudimg/geyser/

Filesystem layout

Mount point Size Description
/ 30 GB Root filesystem
/boot/efi 100 MB UEFI boot partition (Gen2 Hyper V)
/mnt varies Azure temporary resource disk

Key directories:

Path Purpose
/opt/geyser Working directory: the jar, config.yml, cached bundled assets and licences
/var/lib/cloudimg First boot sentinel
/root/geyser-instance-info.txt The per VM connection note (informational, not a secret)

Troubleshooting

Bedrock clients cannot find the server. Almost always the NSG: Bedrock Edition needs UDP 19132 open, not TCP. Re-check the rule, then run the self test on the VM — if it reports OK, the server side is proven and the problem is network reachability from the client's side.

The self test fails. Read what it printed — the failure reason is in the message (FAIL-no-response, FAIL-unexpected-packet-id, etc.). FAIL-no-response with the service reporting active usually means a local firewall change blocked UDP; check the journal:

sudo journalctl -u geyser.service --no-pager | tail -30

Bedrock clients connect but cannot actually join a world. This means the Bedrock side is working — the RakNet listener is proven live by the self test. The remaining step is entirely the Java side: confirm java.address / java.port in config.yml point at a real, running Java Edition server, and that server is reachable from this VM (nc -zv <java-address> <java-port> from this VM's shell is a quick check). Also confirm auth-type matches how that Java server is configured.

The service is not running.

systemctl status geyser.service --no-pager
sudo journalctl -u geyser.service --no-pager | tail -30

The connection note shows the wrong address. First boot resolves the address once; if the VM's public IP changes later (for example after deallocating and restarting without a static IP), re-run first boot manually:

sudo rm -f /var/lib/cloudimg/geyser-firstboot.done
sudo systemctl start geyser-firstboot.service
sudo cat /root/geyser-instance-info.txt

Support

cloudimg images come with 24/7 support. Include the output of sudo /usr/local/sbin/geyser-selftest and the last lines of sudo journalctl -u geyser.service with any request.

Geyser itself is community software — for protocol questions and feature requests, the upstream project and its Discord community are the right place.