Gaming AWS

Geyser 2.12.0 on AWS User Guide

| Product: Geyser 2.12.0 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the Geyser 2.12.0 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg game server listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

Geyser is the open source bridge between Minecraft: Bedrock Edition and Minecraft: Java Edition. Bedrock players on consoles, phones, tablets and Windows normally cannot join a Java Edition server. Geyser sits in front of your Java server, accepts Bedrock players on port 19132 and translates their connection to the Java protocol, so both editions can play together on a server you run.

Geyser is a proxy, not a game server. The image contains no Minecraft server, no Mojang game assets and no accepted Minecraft EULA. You point Geyser at your own Java Edition server (on this instance or elsewhere) and your players use their own Minecraft clients. On its first start Geyser downloads Mojang's client jar itself to extract language strings and default skins, so each instance fetches its own copy; the image ships none of it.

NetherNet is already on. From Bedrock 26.60 (planned for 27 October 2026) Bedrock clients only connect with NetherNet, Mojang's new connection method. Geyser 2.12.0 still defaults to the old RakNet method; this image switches Geyser to NetherNet with its built-in signaling, so players can keep joining. A client first asks the server how to connect with a small web request on TCP 19132 (this is called signaling), then plays over an encrypted WebRTC connection on UDP 19132.

The cloudimg image adds:

  • NetherNet set up for EC2. Built-in signaling runs on TCP 19132 and gameplay on UDP 19132. On first boot the instance reads its public IPv4 address (IMDSv2) and tells players to connect to it; without that, Geyser would only offer the instance's private address.
  • A contained service. Geyser runs as the geyser system account (no shell, no password) under a sandboxed systemd unit: no capabilities, a read only operating system with only /var/lib/geyser writable, private /tmp and devices, and a system call filter. The Geyser jar is owned by root, so the service cannot change its own code.
  • A key unique to your instance. NetherNet uses a server identity key. Geyser creates it on your instance's first start (/var/lib/geyser/nethernet/identity.pem, readable only by the geyser account); no key is baked into the image.
  • Instance metadata blocked for Geyser. Geyser fetches URLs that players and servers influence (skin textures, resource packs), so the service is denied the instance metadata service (169.254.169.254) while it can still reach your Java server and Microsoft sign in. The AMI also requires IMDSv2.
  • Players authenticate. Geyser keeps online mode (auth-type: online): Bedrock players sign in with their own Microsoft accounts and Bedrock logins are validated, so nobody can join as someone else. There is no administrator login, web console or management API, so there is no password to manage.
  • Exactly the ports players need. TCP and UDP 19132 for players and TCP 22 for SSH.
  • A pinned, checked download. Geyser 2.12.0 build 1265 from GeyserMC, verified against the sha256 GeyserMC publishes.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: Geyser Standalone 2.12.0 build 1265 (/opt/geyser/Geyser-Standalone.jar), OpenJDK 21 (Ubuntu package), Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.

Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet with a route to the internet. Geyser needs outbound internet access to reach Microsoft sign in, GeyserMC and Mojang's download servers.
  • A public IPv4 address on the instance (auto assigned or an Elastic IP), so players on the internet can reach it.
  • A security group that allows TCP 19132 and UDP 19132 from your players (usually anywhere) and TCP 22 (SSH) from your own networks only. NetherNet needs both protocols on 19132.
  • A Minecraft: Java Edition server for Geyser to forward to. If it runs on another machine, that machine must accept connections on its Java port (25565 by default) from this instance.

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Geyser 2.12.0 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large (Geyser itself uses about 0.6 GB of memory; size up if you also run your Java server on this instance), your key pair and a security group as above.

With the AWS CLI (replace the values in angle brackets):

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --associate-public-ip-address \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=geyser}]'

The security group rules, from the AWS CLI:

aws ec2 authorize-security-group-ingress --group-id <your-security-group> \
  --ip-permissions 'IpProtocol=tcp,FromPort=19132,ToPort=19132,IpRanges=[{CidrIp=0.0.0.0/0}]' \
                   'IpProtocol=udp,FromPort=19132,ToPort=19132,IpRanges=[{CidrIp=0.0.0.0/0}]' \
                   'IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges=[{CidrIp=<your-mgmt-cidr>}]'

Step 2: Connect to your instance

Version SSH user
Geyser 2.12.0 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>

The login message shows the address players connect to and the commands below.

Step 3: Check the service and the connection note

Geyser and its first boot unit are active a few seconds after boot:

systemctl is-active geyser geyser-firstboot
active
active

First boot records this instance's addresses (read with IMDSv2) in a note for you. It holds connection details only, never a secret:

sudo cat /root/geyser-instance-info.txt
# Geyser - instance information (written by geyser-firstboot.service).
# Geyser has no administrator login: this note holds connection details only, never a secret.
GEYSER_PUBLIC_IP=203.0.113.10
GEYSER_PRIVATE_IP=172.31.83.103
GEYSER_BEDROCK_PORT=19132 (TCP signaling + UDP NetherNet)
GEYSER_CONFIG=/var/lib/geyser/config.yml
# Point Geyser at your Java Edition server: edit the java: section of the config, then
#   sudo systemctl restart geyser

Your addresses will differ. GEYSER_PUBLIC_IP with port 19132 is what Bedrock players enter. If the instance has no public IPv4 the note says none and Geyser offers players its private address, which only works inside your VPC or VPN.

Step 4: Prove NetherNet signaling answers

The image ships a self test that makes the same signaling request every current Bedrock client makes before it joins (GET /v1/join on TCP 19132) and checks Geyser's reply:

geyser-selftest
OK NetherNet signaling: name="Geyser" protocol=2193 version=26.52 players=0/100 onlineAuth=true

This proves the Java runtime started, the configuration parsed, NetherNet is on and signaling answers, and that online authentication is enforced. It does not need your Java server yet. The same request works from your own computer against the public address, which also proves the security group:

curl -s http://<public-ip>:19132/v1/join

It returns a short JSON record with "name":"Geyser", the protocol, the Bedrock version and "onlineAuth":true.

NetherNet is set in the bedrock section of the configuration, and first boot filled in the address players are sent to:

sudo grep -n -E '^  transport:|^      advertise-addresses:|^        - ' /var/lib/geyser/config.yml
31:  transport: nethernet
50:      advertise-addresses:
51:        - '203.0.113.10'
75:      advertise-addresses: []

Line 50 is the built-in signaling list (your public address); line 75 belongs to the external signaling service, which this image does not use.

Step 5: Point Geyser at your Java server

The shipped config.yml was written by Geyser itself on the build and keeps Geyser's defaults apart from NetherNet. Its java section points at 127.0.0.1 port 25565, which only works if you run your Java server on this same instance:

sudo grep -n -A10 '^java:' /var/lib/geyser/config.yml
84:java:
85-  # The IP address of the Java Edition server.
86-  address: 127.0.0.1
87-
88-  # The port of the Java Edition server.
89-  port: 25565
90-
91-  # What type of authentication Bedrock players will be checked against when logging into the Java server.
92-  # Can be "floodgate" (see https://wiki.geysermc.org/floodgate/), "online", or "offline".
93-  auth-type: online
94-

Edit it with sudo nano /var/lib/geyser/config.yml:

  • address and port: your Java server's address (an IP or DNS name reachable from this instance) and port. If the Java server runs on this instance, keep 127.0.0.1.
  • auth-type: keep online when your Java server runs in online mode (the normal case). Players then sign in with their Microsoft accounts. Use floodgate only if you install the Floodgate plugin on your Java server: copy that server's key.pem to /var/lib/geyser/key.pem (owner geyser, mode 0640) and treat it as a secret. Avoid offline: anyone could then join under any name.

Then restart Geyser and wait for signaling:

sudo systemctl restart geyser
for i in $(seq 1 30); do geyser-selftest >/dev/null 2>&1 && break; sleep 2; done; geyser-selftest
OK NetherNet signaling: name="Geyser" protocol=2193 version=26.52 players=0/100 onlineAuth=true

When the Java server is reachable, the server list entry shows your Java server's MOTD and player count (passthrough-motd). To check reachability from this instance, run nc -zv YOUR_JAVA_HOST 25565 (replace the host and port).

Step 6: Connect from a Bedrock client

In Minecraft (Bedrock Edition) open Play, then Servers, then Add Server. Enter a name, the instance's public address as Server Address and 19132 as Port, then save and join. Consoles that cannot add servers directly need a DNS or "server list" workaround; see the Geyser documentation.

The trust prompt. Built-in signaling uses plain HTTP, Geyser's default. The first time a player joins by IP address, Minecraft shows a "trust on first use" prompt; after they accept it, it does not appear again for this server. The gameplay connection itself is encrypted (WebRTC with DTLS). To remove the prompt, serve signaling over HTTPS with a certificate for a domain name (Step 8).

Bedrock client versions. Each Geyser release accepts the Bedrock versions it was built for. Geyser 2.12.0 build 1265 accepts Bedrock 26.52 (protocol 2193), as geyser-selftest shows. Bedrock clients update automatically, and when a newer Bedrock release is out the Geyser log says so with a line starting There's a new Geyser update available to support Bedrock version:

sudo journalctl -u geyser --no-pager -o cat | sed -E 's/\x1b\[[0-9;]*m//g' | grep -E 'Loading Geyser version|Built-in signaling started|new Geyser update|NetherNet support' | tail -3
[00:28:59 INFO] Built-in signaling started on http://0.0.0.0:19132
[00:29:16 INFO] Loading Geyser version 2.12.0-b1265 (git-master-02dbfac)
[00:29:23 INFO] Built-in signaling started on http://0.0.0.0:19132

If your players run a newer Bedrock version than this build accepts, upgrade Geyser as in Step 10.

Step 7: Security checks

Only SSH (TCP 22) and Geyser on 19132 listen on the network. TCP 19132 is NetherNet signaling; Geyser opens UDP 19132 for each player's WebRTC connection as they join. The DHCP client on port 68 is the instance's own network setup:

sudo ss -H -tulnp | grep -v -E '127\.0\.0\.5[34]|\[::1\]|127\.0\.0\.1:323' | awk '{print $1, $5, $7}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'
udp 172.31.83.103%ens5:68 users:(("systemd-network"))
tcp 0.0.0.0:22 users:(("sshd"),("systemd"))
tcp [::]:22 users:(("sshd"),("systemd"))
tcp *:19132 users:(("java"))

Geyser runs as the unprivileged geyser account in a sandboxed unit, and the unit denies it the instance metadata addresses:

systemctl show geyser -p User -p NoNewPrivileges -p ProtectSystem -p PrivateTmp -p IPAddressDeny
IPAddressDeny=169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32
User=geyser
PrivateTmp=yes
ProtectSystem=strict
NoNewPrivileges=yes
sudo systemd-analyze security geyser.service --no-pager | tail -1
→ Overall exposure level for geyser.service: 1.5 OK 🙂

The deny list holds only the metadata addresses, so Geyser still reaches your Java server, Microsoft sign in and GeyserMC. The rule lives in /etc/systemd/system/geyser.service.d/50-cloudimg-imds-deny.conf; keep it.

The NetherNet identity key was created on this instance and only the geyser account can read it:

sudo ls -l /var/lib/geyser/nethernet/
total 4
-rw------- 1 geyser geyser 288 Oct 20 00:27 identity.pem

Signaling takes the player's address from the connection. It ignores X-Forwarded-For unless you list a reverse proxy in advanced.bedrock.signaling-trusted-proxies (empty in this image).

Step 8: HTTPS for signaling (optional)

To remove the trust prompt, give the server a DNS name (for example a Route 53 record pointing at an Elastic IP), get a certificate for it from a public certificate authority, and point built-in signaling at it in /var/lib/geyser/config.yml:

  • bedrock.signaling.builtin.https.certificate: the path to the certificate chain (PEM), for example /var/lib/geyser/tls/fullchain.pem.
  • bedrock.signaling.builtin.https.private-key: the path to its private key. Keep the files owned by geyser with mode 0600.
  • bedrock.signaling.builtin.advertise-addresses: you can leave the IP address here. Players then add the server by its DNS name.

Restart Geyser. Signaling then serves HTTPS on TCP 19132 and refuses plain HTTP, so geyser-selftest (which speaks HTTP) reports a failure. Check with curl -s https://<your-domain>:19132/v1/join instead. GeyserMC's HTTPS guide covers the options in detail, including a reverse proxy in front of the signaling port.

Step 9: Configuration you may want to change

All settings live in /var/lib/geyser/config.yml, each documented by a comment above it. Restart Geyser after a change (sudo systemctl restart geyser).

Setting Image default Meaning
bedrock.port 19132 Signaling (TCP) and NetherNet gameplay (UDP). Change the security group with it.
bedrock.transport nethernet How players connect. both also accepts the old RakNet method, but then needs a separate webrtc-port (another UDP port).
bedrock.signaling.builtin.advertise-addresses this instance's public IPv4 The address players are sent to. First boot sets it; see Step 11.
java.address, java.port 127.0.0.1, 25565 Your Java Edition server (Step 5).
java.auth-type online Microsoft account sign in. See Step 5 before changing it.
motd.primary-motd, motd.passthrough-motd Geyser, true The server list text; passthrough shows your Java server's own MOTD.
log-player-ip-addresses true Player addresses in Geyser's log. Set false if you do not want them recorded.
enable-metrics true Anonymous usage statistics to bStats, Geyser's default. Set false to switch them off. Each instance gets its own random metrics-uuid at first boot.
advanced.bedrock.use-haproxy-protocol false Keep false unless Geyser sits behind a proxy that sends the PROXY protocol, or players could fake their address.

Geyser's own logs are in the systemd journal (sudo journalctl -u geyser) and in /var/lib/geyser/logs/.

Step 10: Upgrade Geyser

Geyser is a single jar; your config.yml stays as it is. Pick the release and build from GeyserMC's download page and replace <version> and <build> below. The commands check the jar against the sha256 GeyserMC publishes before installing it:

V=<version>; B=<build>
API="https://download.geysermc.org/v2/projects/geyser/versions/${V}/builds/${B}"
SUM="$(curl -fsSL "${API}" | python3 -c 'import json,sys; print(json.load(sys.stdin)["downloads"]["standalone"]["sha256"])')"
curl -fsSL -o /tmp/Geyser-Standalone.jar "${API}/downloads/standalone"
echo "${SUM}  /tmp/Geyser-Standalone.jar" | sha256sum -c - \
  && sudo install -o root -g root -m 0644 /tmp/Geyser-Standalone.jar /opt/geyser/Geyser-Standalone.jar \
  && sudo systemctl restart geyser
rm -f /tmp/Geyser-Standalone.jar

Then check the new version with the journalctl command in Step 6 and run geyser-selftest.

Step 11: Server components

Component Version Location
Geyser Standalone 2.12.0 build 1265 /opt/geyser/Geyser-Standalone.jar (root owned)
OpenJDK 21 (Ubuntu package, security updates via unattended upgrades) /usr/lib/jvm
Configuration and state /var/lib/geyser/ (config.yml, permissions.yml, nethernet/, packs, extensions, logs, cache)
JVM options -Xms256m -Xmx1024m /etc/default/geyser
Self test /usr/local/sbin/geyser-selftest
Advertised address helper /usr/local/sbin/geyser-set-address
First boot geyser-firstboot.service, note in /root/geyser-instance-info.txt
Licence texts /usr/share/doc/geyser/

If the instance's public address changes (for example after a stop and start without an Elastic IP), run first boot again; it updates the advertised address and the note. Then restart Geyser:

sudo rm -f /var/lib/cloudimg/geyser-firstboot.done
sudo systemctl restart geyser-firstboot
sudo grep GEYSER_PUBLIC_IP /root/geyser-instance-info.txt
sudo systemctl restart geyser

To advertise a different address yourself (for example an Elastic IP you attach later), run sudo geyser-set-address <address> and then sudo systemctl restart geyser.

Step 12: Security recommendations

  • Allow TCP 22 only from your own networks; only TCP and UDP 19132 need to be open to players.
  • Keep auth-type: online (or Floodgate with its key kept secret). Offline mode lets anyone impersonate any player.
  • Keep /var/lib/geyser/nethernet/identity.pem private. If you copy it to another server, both share one identity.
  • Use HTTPS for signaling when you have a domain name (Step 8).
  • Protect your Java server too: if it runs elsewhere, allow its Java port only from this instance.
  • Upgrade Geyser when Bedrock updates (Step 10); unattended upgrades keep Ubuntu and OpenJDK patched.

Troubleshooting

  • Bedrock players cannot find the server. Check the security group allows TCP and UDP 19132, then run curl -s http://<public-ip>:19132/v1/join from your own computer. If that answers but players cannot join, check the advertised address (Step 4) matches the public address.
  • Players see "Outdated server" or "Outdated client". Their Bedrock version does not match this Geyser build; see Step 6 and Step 10.
  • Players reach the server list but cannot join a world. Geyser cannot reach your Java server: check java.address and java.port (Step 5), the Java server's own firewall, and that auth-type matches the Java server's mode. sudo journalctl -u geyser -n 50 shows the reason.
  • The service does not start. systemctl status geyser --no-pager and sudo journalctl -u geyser -n 50. A YAML mistake in config.yml is the usual cause.

Support and licensing

cloudimg provides 24/7 technical support for this image by email and live chat at support@cloudimg.co.uk. Include the output of geyser-selftest and the last lines of sudo journalctl -u geyser with a request.

Geyser is free software under the MIT License. The jar also bundles the MinecraftAuth library (LGPL-3.0, unmodified), Apache-2.0 and MIT licensed libraries including Bouncy Castle, and a native WebRTC library for NetherNet (libdatachannel-java, libdatachannel and libjuice under MPL-2.0, usrsctp under BSD-3-Clause; NOTICE.native-webrtc lists where to get their source). Every licence and notice text ships on the image:

ls /usr/share/doc/geyser/ && head -3 /usr/share/doc/geyser/LICENSE
LICENSE
LICENSE.mappings-MIT
LICENSE.native-webrtc-MPL-2.0
LICENSE.native-webrtc-usrsctp-BSD-3-Clause
LICENSE.third-party-Apache-2.0
LICENSE.third-party-BouncyCastle-MIT
LICENSE.third-party-MIT
LICENSE.third-party-MIT-2
LICENSE_MinecraftAuth
NOTICE.native-webrtc
NOTICE.third-party
README.cloudimg
The MIT License

Copyright (c) 2019-2026 GeyserMC. http://geysermc.org

Minecraft is a trademark of Mojang Synergies AB. Geyser is a community project of GeyserMC. cloudimg is not affiliated with or endorsed by Mojang, Microsoft or GeyserMC.