Custom Domain & TLS
Serve the dashboard at your own domain with automatic HTTPS, and give players a friendly address.
There are two separate things you might want a domain for: a friendly address for players to connect to, and a public HTTPS dashboard for admins. They're independent — set up either or both.
A friendly address for players
The Minecraft server is public at the host's IP on MC_HOST_PORT (usually
25565). A custom address is just DNS pointing at that IP — no server change
needed.
Add a DNS record
In your DNS provider, add an A record (and AAAA if the host has IPv6):
| Type | Name | Value |
|---|---|---|
A | mc | the host's public IPv4 |
Players then connect with mc.example.com (no port, since 25565 is the
default).
Cloudflare users: proxy must be OFF
Set the record to DNS only (gray cloud). Cloudflare's proxy is HTTP-only; Minecraft is raw TCP and gets silently dropped through an orange cloud. This is the #1 "I added the record and it still won't connect" cause.
Tell the dashboard the address
So the How to join panel shows the friendly name, set it in .env:
MC_PUBLIC_HOST=mc.example.comThen beacon restart. For a non-default port, add a _minecraft._tcp SRV
record so players can still omit the port, and set MC_HOST_PORT /
MC_PUBLIC_PORT to match. New CLI-created beacons configure SRV-friendly ports
automatically.
Verify
dig +short mc.example.com
nc -vz mc.example.com 25565A public HTTPS dashboard (Caddy)
By default the dashboard is private over Tailscale.
Custom-domain mode instead runs a bundled Caddy
reverse proxy that serves the dashboard at https://your.domain with an
automatic certificate. One A record can cover both the dashboard (:443) and
the game server (:25565).
Point the domain at the host
Add an A record (and AAAA if applicable) for the dashboard hostname at the host's public IP. Cloudflare users: DNS only (gray cloud) again — the orange-cloud proxy breaks Caddy's ACME challenge.
Open ports 80 and 443
Caddy needs inbound TCP 80 (ACME challenge + HTTP→HTTPS redirect) and 443 (the dashboard). Open both in the OS firewall and any cloud firewall:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcpSwitch to custom-domain mode
Let the CLI write the config:
beacon create --yes --mode custom \
--app-url https://friends.example.com \
--acme-email ops@example.com \
--mc-image itzg/minecraft-server:java25 --mc-version 26.1.2Or set it in .env on an existing beacon, then beacon up:
COMPOSE_PROFILES=custom-domain
BEACON_DOMAIN=friends.example.com
PUBLIC_APP_URL=https://friends.example.com
BEACON_ACME_EMAIL=ops@example.comFirst boot
Caddy obtains the certificate on first start — this takes 30–60 seconds, during
which the dashboard returns 502. That's expected. Watch it with
beacon logs caddy.
Switching ingress invalidates sessions
Changing ingress mode changes the dashboard's origin, so everyone signs in again on the new URL.
Certificates and rate limits
Caddy tries Let's Encrypt first and automatically falls through to ZeroSSL
if LE is unavailable — most often because of LE's
5-certificates-per-week-per-domain limit after repeated redeploys. The
ZeroSSL fallback needs an EAB account, which Caddy auto-provisions only if
BEACON_ACME_EMAIL is set — that's why custom-domain mode requires it. Use a
real inbox; both CAs email expiry notices there.
beacon nuke preserves Caddy's cert state by default, so iterating doesn't burn
issuances. If you do hit the limit, switching to a fresh subdomain (a new
identifier with its own counter) is the fastest unblock.