What this network does
Velocity becomes the only public Minecraft entry point. It authenticates Java players and sends them to one or more backend servers. In this first setup, the network contains:
- one
itzg/mc-proxycontainer running Velocity - one
itzg/minecraft-servercontainer running Paper - one shared Docker network
- only TCP port 25565 published by the proxy
- persistent folders for proxy and server state
If you only need one server and no proxy plugins, stay with the simpler Java server configurator. A proxy adds another security boundary that must be configured deliberately.
Step 1: Generate the proxy Compose baseline
Open the Minecraft Proxy Configurator, select VELOCITY, and keep the public mapping at 25565:25577. Download the generated Compose file.
For the complete network, extend it with a Paper backend:
services:
proxy:
image: itzg/mc-proxy:latest
restart: unless-stopped
ports:
- "25565:25577"
environment:
TYPE: VELOCITY
MEMORY: 512m
volumes:
- ./proxy:/server
networks:
- minecraft
stdin_open: true
tty: true
lobby:
image: itzg/minecraft-server:java25
restart: unless-stopped
environment:
EULA: "TRUE"
TYPE: PAPER
VERSION: "26.1.2"
ONLINE_MODE: "FALSE"
volumes:
- ./lobby:/data
networks:
- minecraft
networks:
minecraft: {}
The backend has no ports entry. Docker Compose makes it reachable as lobby:25565 from the proxy because both services share the minecraft network.
Pin a Minecraft release you have tested instead of copying the example version indefinitely. Check the Java version guide when the selected Paper release changes its runtime requirement.
Step 2: Start once to create configuration files
Create the persistent folders, validate the resolved Compose model, and start both services:
mkdir -p proxy lobby
docker compose config
docker compose up -d
docker compose logs -f proxy lobby
Wait until Paper reports that it is ready and Velocity has created proxy/velocity.toml. Then stop the stack before changing forwarding:
docker compose down
Do not leave the backend in offline mode while its port is public. The next step completes identity forwarding before the network is opened to players.
Step 3: Register the backend in Velocity
Edit proxy/velocity.toml. Keep the proxy listener aligned with the container port and point the backend at the Compose service name:
bind = "0.0.0.0:25577"
online-mode = true
player-info-forwarding-mode = "modern"
forwarding-secret-file = "forwarding.secret"
[servers]
lobby = "lobby:25565"
try = ["lobby"]
localhost would mean the proxy container itself, not the Paper container. Docker service discovery keeps lobby stable even when the backend container receives a new IP address.
Velocity creates proxy/forwarding.secret. The same value must be configured on Paper. Follow the dedicated Velocity modern forwarding guide before starting the public network.
Step 4: Start and validate every layer
Bring the stack back up:
docker compose up -d
docker compose ps
docker compose logs --tail=100 proxy lobby
Confirm these conditions:
- Both services remain
Upand the proxy becomes healthy. - Velocity logs no forwarding or backend connection error.
docker compose port proxy 25577shows the public mapping.docker compose port lobby 25565returns no published host port.- A Java client can join the host on port 25565 and reaches
lobby.
Finally, run server lobby in the Velocity console or use the in-game /server lobby command with appropriate permissions. The backend console should show the forwarded player identity, not an unauthenticated direct login.
Add a second backend later
Add another service, for example survival, to the same network and register it in velocity.toml:
[servers]
lobby = "lobby:25565"
survival = "survival:25565"
try = ["lobby"]
Do not reuse a world directory across backend services. Give every server its own persistent data path and repeat the same forwarding and isolation controls.
Troubleshooting
| Symptom | Likely cause | Next check |
|---|---|---|
Velocity starts, but lobby is unavailable | Wrong service name, port, or Docker network | Follow the backend connection runbook |
| Paper says to connect through Velocity | Modern forwarding differs between proxy and backend | Compare mode, enabled flag, and secret |
| Players can bypass the proxy | Backend port was published or allowed by a firewall | Remove the backend port mapping and close the rule |
| Proxy is unhealthy but accepts connections | Healthcheck port differs from the Velocity listener | Align SERVER_PORT, bind, and the container port |
| Existing world is missing | A different /data path was mounted | Stop and verify the bind mount before copying data |
Next steps
- Complete Velocity modern forwarding for Paper before inviting players.
- If the proxy cannot see a backend, diagnose the Docker connection path.
- Add Bedrock access with Geyser and Floodgate on Velocity.
- Protect each server independently with automatic backups.