This guide covers advanced Docker configuration topics for deploying Gate in production environments.
Volume Mounts
Configuration File
The most basic volume mount is for the configuration file:
docker run -d \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
You can also mount it to a custom location:
docker run -d \
-v /etc/gate/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
Data Directory
For persistent data (plugins, extensions, logs):
docker run -d \
-v $(pwd)/config.yml:/config.yml \
-v gate-data:/data \
ghcr.io/minekube/gate:latest
Multiple Configuration Files
If you need to mount additional files:
docker run -d \
-v $(pwd)/config.yml:/config.yml \
-v $(pwd)/plugins:/plugins \
-v $(pwd)/extensions:/extensions \
ghcr.io/minekube/gate:latest
Read-Only Mounts
For security, mount configuration as read-only:
docker run -d \
-v $(pwd)/config.yml:/config.yml:ro \
ghcr.io/minekube/gate:latest
Floodgate Key (Bedrock Support)
When using Bedrock cross-play:
docker run -d \
-v $(pwd)/config.yml:/config.yml \
-v $(pwd)/floodgate.pem:/floodgate.pem \
ghcr.io/minekube/gate:latest-jre
Environment Variables
Gate supports environment variables for sensitive configuration values.
Velocity Forwarding Secret
docker run -d \
-v $(pwd)/config.yml:/config.yml \
-e GATE_VELOCITY_SECRET=your-secret-here \
ghcr.io/minekube/gate:latest
In your config.yml:
config:
forwarding:
mode: velocity
# velocitySecret is automatically loaded from GATE_VELOCITY_SECRET
BungeeGuard Secret
docker run -d \
-v $(pwd)/config.yml:/config.yml \
-e GATE_BUNGEEGUARD_SECRET=your-secret-here \
ghcr.io/minekube/gate:latest
Using Environment Files
Create a .env file:
GATE_VELOCITY_SECRET=long-random-secret-here
GATE_BUNGEEGUARD_SECRET=another-secret-here
Then use it:
docker run -d \
-v $(pwd)/config.yml:/config.yml \
--env-file .env \
ghcr.io/minekube/gate:latest
With Docker Compose:
services:
gate:
image: ghcr.io/minekube/gate:latest
env_file:
- .env
volumes:
- ./config.yml:/config.yml
Networking
Host Network Mode
Best performance, but less isolation:
docker run -d \
--network host \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
With Docker Compose:
services:
gate:
image: ghcr.io/minekube/gate:latest
network_mode: host
volumes:
- ./config.yml:/config.yml
Host networking gives the container direct access to the host’s network stack. Only use in trusted environments.
Bridge Network Mode
Better isolation with custom networks:
# Create network
docker network create minecraft-net
# Run Gate
docker run -d \
--name gate \
--network minecraft-net \
-p 25565:25565 \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
# Run backend server
docker run -d \
--name backend \
--network minecraft-net \
itzg/minecraft-server
With Docker Compose:
services:
gate:
image: ghcr.io/minekube/gate:latest
networks:
- minecraft
ports:
- "25565:25565"
backend:
image: itzg/minecraft-server
networks:
- minecraft
networks:
minecraft:
driver: bridge
Internal Networks
Prevent backend servers from accessing the internet:
services:
gate:
image: ghcr.io/minekube/gate:latest
networks:
- public
- internal
ports:
- "25565:25565"
backend:
image: itzg/minecraft-server
networks:
- internal
networks:
public:
driver: bridge
internal:
driver: bridge
internal: true # No external access
Custom Port Mappings
# Map host port 25575 to container port 25565
docker run -d \
-p 25575:25565 \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
Multiple Ports
For Gate API and query protocol:
docker run -d \
-p 25565:25565 \
-p 8080:8080 \
-p 25577:25577/udp \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
With Docker Compose:
services:
gate:
image: ghcr.io/minekube/gate:latest
ports:
- "25565:25565" # Minecraft
- "8080:8080" # API
- "25577:25577/udp" # Query
volumes:
- ./config.yml:/config.yml
IPv6 Support
Enable IPv6 in Docker:
services:
gate:
image: ghcr.io/minekube/gate:latest
ports:
- "25565:25565"
- "[::]:25565:25565" # IPv6
volumes:
- ./config.yml:/config.yml
Resource Limits
Memory Limits
docker run -d \
--memory="1g" \
--memory-swap="1g" \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
With Docker Compose:
services:
gate:
image: ghcr.io/minekube/gate:latest
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
volumes:
- ./config.yml:/config.yml
CPU Limits
docker run -d \
--cpus="2.0" \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
With Docker Compose:
services:
gate:
image: ghcr.io/minekube/gate:latest
deploy:
resources:
limits:
cpus: '2.0'
reservations:
cpus: '1.0'
Security Configuration
Running as Non-Root User
The distroless image runs as non-root by default. For the JRE variant:
docker run -d \
--user 1000:1000 \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest-jre
Read-Only Root Filesystem
docker run -d \
--read-only \
--tmpfs /tmp \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
Dropping Capabilities
docker run -d \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
Security Options with Docker Compose
services:
gate:
image: ghcr.io/minekube/gate:latest
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
read_only: true
tmpfs:
- /tmp
volumes:
- ./config.yml:/config.yml:ro
Logging Configuration
JSON Logging Driver
docker run -d \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
Syslog Driver
docker run -d \
--log-driver syslog \
--log-opt syslog-address=tcp://192.168.0.100:514 \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest
Docker Compose Logging
services:
gate:
image: ghcr.io/minekube/gate:latest
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "production"
volumes:
- ./config.yml:/config.yml
Health Checks
TCP Health Check
docker run -d \
--health-cmd="timeout 1 bash -c 'cat < /dev/null > /dev/tcp/localhost/25565'" \
--health-interval=30s \
--health-timeout=3s \
--health-retries=3 \
-v $(pwd)/config.yml:/config.yml \
ghcr.io/minekube/gate:latest-jre
Health checks require shell utilities, so use the JRE variant.
Docker Compose Health Check
services:
gate:
image: ghcr.io/minekube/gate:latest-jre
healthcheck:
test: ["CMD-SHELL", "timeout 1 bash -c 'cat < /dev/null > /dev/tcp/localhost/25565'"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10s
volumes:
- ./config.yml:/config.yml
Using Gate API for Health Checks
If you have the API enabled:
services:
gate:
image: ghcr.io/minekube/gate:latest-jre
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
volumes:
- ./config.yml:/config.yml
Bedrock Edition (Cross-Play) Setup
For Bedrock cross-play with managed Geyser:
services:
gate:
image: ghcr.io/minekube/gate:latest-jre # JRE required for Geyser
container_name: gate
restart: unless-stopped
ports:
- "25565:25565" # Java Edition
- "19132:19132/udp" # Bedrock Edition
volumes:
- ./config.yml:/config.yml
- ./floodgate.pem:/floodgate.pem
- gate-geyser-data:/data
networks:
- minecraft
volumes:
gate-geyser-data:
networks:
minecraft:
driver: bridge
In config.yml:
config:
bind: 0.0.0.0:25565
bedrock:
enabled: true
managed: true
geyserListenAddr: 0.0.0.0:25567
managed:
enabled: true
configOverrides:
bedrock:
port: 19132
motd1: "Gate + Geyser"
motd2: "Java & Bedrock Together!"
Troubleshooting
Container Won’t Start
Check logs:
Check if config file exists:
docker run --rm -v $(pwd)/config.yml:/config.yml alpine ls -la /config.yml
Permission Issues
Fix file permissions:
sudo chown -R 1000:1000 ./config.yml
Network Connectivity Issues
Test network connectivity:
docker exec gate ping backend-server
Check DNS resolution:
docker exec gate nslookup backend-server
Port Already in Use
Find what’s using the port:
sudo lsof -i :25565
# or
sudo netstat -tulpn | grep 25565
Cannot Connect to Backend Servers
Verify backend servers are running:
Check network connectivity:
docker compose exec gate ping lobby
Verify config:
docker compose exec gate cat /config.yml
High Memory Usage
Monitor resource usage:
Set memory limits:
services:
gate:
image: ghcr.io/minekube/gate:latest
deploy:
resources:
limits:
memory: 512M
Container Keeps Restarting
Check restart policy:
docker inspect gate | grep -A 5 RestartPolicy
View last logs before crash:
docker logs --tail 100 gate
Disable restart to debug:
docker update --restart=no gate
Debug Mode
Enable debug logging in config.yml:
Then restart:
docker restart gate
docker logs -f gate
Inspecting Configuration
View loaded configuration:
# For JRE variant
docker exec gate cat /config.yml
# For distroless variant (no shell)
docker cp gate:/config.yml -
Testing Connectivity
From host:
From another container:
docker run --rm --network minecraft-net alpine telnet gate 25565
For JRE Variant
Optimize Java flags:
services:
gate:
image: ghcr.io/minekube/gate:latest-jre
environment:
JAVA_OPTS: |
-Xms512M
-Xmx1G
-XX:+UseG1GC
-XX:G1HeapRegionSize=4M
-XX:+UnlockExperimentalVMOptions
-XX:+ParallelRefProcEnabled
-XX:+AlwaysPreTouch
-XX:MaxInlineLevel=15
volumes:
- ./config.yml:/config.yml
Adjust compression settings in config.yml:
config:
compression:
threshold: 256
level: 6 # -1 to 9, higher = more CPU, less bandwidth
Connection Tuning
config:
connectionTimeout: 5s
readTimeout: 30s
quota:
connections:
enabled: true
ops: 10
burst: 20
maxEntries: 10000
Next Steps
Production Guide
Best practices for production deployments
Monitoring
Monitor your Gate proxy in production