514 lines
13 KiB
Markdown
514 lines
13 KiB
Markdown
# DirtSimpleP2P
|
|
|
|
DirtSimpleP2P is a Minecraft networking plugin that lets a public BungeeCord or Waterfall proxy reach backend Paper/Spigot servers that are behind NAT.
|
|
|
|
It is designed for server owners who want to host a backend Minecraft server at home or on a private network without opening the backend Minecraft port on their router.
|
|
|
|
The backend server connects outbound to the public proxy. Bungee/Waterfall then connects to a local port on the proxy machine, and DirtSimpleP2P carries the Minecraft TCP connection through the tunnel.
|
|
|
|
## Features
|
|
|
|
- One jar for both the proxy and backend server
|
|
- No home router port forwarding for backend Minecraft servers
|
|
- NAT-safe outbound tunnel from backend to proxy
|
|
- Multiple simultaneous Minecraft player connections
|
|
- Multiplexed framed TCP protocol
|
|
- Secret-token authentication
|
|
- Automatic token generation
|
|
- Optional TLS encryption
|
|
- Self-signed TLS certificate generation
|
|
- TLS certificate pinning on backend servers
|
|
- Fast reconnect with heartbeat checks
|
|
- Multiple public proxies can connect to one backend
|
|
- One proxy can expose multiple named backend servers
|
|
- `/dsp2p status` and `/dsp2p doctor` commands
|
|
- Temporary browser setup wizard with console-generated login key
|
|
- Simple `config.properties` setup
|
|
|
|
## Requirements
|
|
|
|
- Java 21
|
|
- Maven 3.8+
|
|
- BungeeCord or Waterfall for the public proxy side
|
|
- Paper or Spigot for the backend server side
|
|
|
|
## How It Works
|
|
|
|
Normal Minecraft proxy setup expects Bungee/Waterfall to connect directly to a backend server.
|
|
|
|
That does not work well when the backend server is at home behind NAT, unless you forward ports on the home router.
|
|
|
|
DirtSimpleP2P avoids that:
|
|
|
|
1. The proxy server runs DirtSimpleP2P in `frontend` mode.
|
|
2. The backend server runs DirtSimpleP2P in `backend` mode.
|
|
3. The backend opens an outbound tunnel to the public proxy.
|
|
4. The proxy exposes a local port such as `127.0.0.1:25566`.
|
|
5. Bungee/Waterfall sends players to that local port.
|
|
6. DirtSimpleP2P carries the TCP traffic through the tunnel to the backend server.
|
|
|
|
The public proxy needs an open tunnel port. The home/backend router does not need a Minecraft port forward.
|
|
|
|
## Build
|
|
|
|
From the project folder:
|
|
|
|
```bash
|
|
mvn clean package
|
|
```
|
|
|
|
The plugin jar is created at:
|
|
|
|
```bash
|
|
plugin/target/DirtSimpleP2P-0.1.0-SNAPSHOT.jar
|
|
```
|
|
|
|
Use this same jar on both the proxy and backend server.
|
|
|
|
## Basic Setup
|
|
|
|
You need:
|
|
|
|
- A public BungeeCord/Waterfall proxy, usually on a VPS
|
|
- A backend Paper/Spigot server, which can be at home or on a private network
|
|
|
|
### 1. Install On The Proxy
|
|
|
|
Put the jar in your BungeeCord/Waterfall `plugins` folder:
|
|
|
|
```text
|
|
DirtSimpleP2P-0.1.0-SNAPSHOT.jar
|
|
```
|
|
|
|
Start the proxy once, then stop it.
|
|
|
|
DirtSimpleP2P creates:
|
|
|
|
```text
|
|
plugins/DirtSimpleP2P/config.properties
|
|
```
|
|
|
|
### 2. Configure The Proxy
|
|
|
|
Use this on the BungeeCord/Waterfall side:
|
|
|
|
```properties
|
|
role=frontend
|
|
node.name=bungee-frontend
|
|
|
|
tunnel.listenHost=0.0.0.0
|
|
tunnel.listenPort=24445
|
|
tunnel.authToken=GENERATED_AUTOMATICALLY
|
|
|
|
tunnel.connectTimeoutMillis=5000
|
|
tunnel.heartbeatIntervalMillis=2000
|
|
tunnel.heartbeatTimeoutMillis=8000
|
|
tunnel.heartbeatMissesBeforeDisconnect=4
|
|
tunnel.reconnectInitialMillis=250
|
|
tunnel.reconnectMaxMillis=10000
|
|
|
|
tunnel.tls.enabled=false
|
|
tunnel.tls.allowInsecure=true
|
|
tunnel.tls.autoGenerate=true
|
|
tunnel.tls.keyStore=certs/frontend.p12
|
|
tunnel.tls.keyStorePassword=
|
|
tunnel.tls.requireClientAuth=false
|
|
|
|
webwizard.bindHost=127.0.0.1
|
|
webwizard.port=8765
|
|
|
|
routes=minecraft
|
|
route.minecraft.frontendBindHost=127.0.0.1
|
|
route.minecraft.frontendBindPort=25566
|
|
route.minecraft.backendNode=paper-backend
|
|
```
|
|
|
|
Notes:
|
|
|
|
- `tunnel.listenPort` is the public tunnel port that the backend connects to.
|
|
- `tunnel.authToken` is generated automatically on first start.
|
|
- Copy the generated token to the backend config.
|
|
- `route.minecraft.frontendBindPort` is the local port Bungee/Waterfall should use for this backend.
|
|
- `route.minecraft.backendNode` must match the backend server's `node.name`.
|
|
|
|
### 3. Point Bungee/Waterfall At The Local Tunnel
|
|
|
|
In your BungeeCord/Waterfall server config, set the backend address to:
|
|
|
|
```text
|
|
127.0.0.1:25566
|
|
```
|
|
|
|
Do not put your home server IP in the Bungee/Waterfall config. Bungee connects locally, and DirtSimpleP2P carries the traffic through the tunnel.
|
|
|
|
### 4. Install On The Backend
|
|
|
|
Put the same jar in your Paper/Spigot `plugins` folder:
|
|
|
|
```text
|
|
DirtSimpleP2P-0.1.0-SNAPSHOT.jar
|
|
```
|
|
|
|
Start the backend server once, then stop it.
|
|
|
|
DirtSimpleP2P creates:
|
|
|
|
```text
|
|
plugins/DirtSimpleP2P/config.properties
|
|
```
|
|
|
|
### 5. Configure The Backend
|
|
|
|
Use this on the Paper/Spigot side:
|
|
|
|
```properties
|
|
role=backend
|
|
node.name=paper-backend
|
|
|
|
frontends=proxy1
|
|
frontend.proxy1.connectHost=YOUR_PROXY_IP_OR_DOMAIN
|
|
frontend.proxy1.connectPort=24445
|
|
frontend.proxy1.tls.pinnedCertificateSha256=
|
|
|
|
tunnel.authToken=PASTE_THE_PROXY_TOKEN_HERE
|
|
|
|
tunnel.connectTimeoutMillis=5000
|
|
tunnel.heartbeatIntervalMillis=2000
|
|
tunnel.heartbeatTimeoutMillis=8000
|
|
tunnel.heartbeatMissesBeforeDisconnect=4
|
|
tunnel.reconnectInitialMillis=250
|
|
tunnel.reconnectMaxMillis=10000
|
|
|
|
tunnel.tls.enabled=false
|
|
tunnel.tls.allowInsecure=true
|
|
tunnel.tls.trustOnFirstUse=true
|
|
|
|
webwizard.bindHost=127.0.0.1
|
|
webwizard.port=8765
|
|
|
|
routes=minecraft
|
|
route.minecraft.backendTargetHost=127.0.0.1
|
|
route.minecraft.backendTargetPort=25565
|
|
```
|
|
|
|
Change:
|
|
|
|
- `frontend.proxy1.connectHost` to your public proxy IP or domain
|
|
- `frontend.proxy1.connectPort` to the proxy `tunnel.listenPort`
|
|
- `tunnel.authToken` to the token from the proxy config
|
|
- `route.minecraft.backendTargetPort` if your Paper/Spigot server is not listening on `25565`
|
|
|
|
### 6. Start Everything
|
|
|
|
Start the public proxy first.
|
|
|
|
Then start the backend Paper/Spigot server.
|
|
|
|
If the tunnel connects, the proxy log should show that a backend authenticated. Players connect to your normal public proxy address.
|
|
|
|
## TLS
|
|
|
|
TLS is optional, but recommended for real deployments.
|
|
|
|
On the proxy:
|
|
|
|
```properties
|
|
tunnel.tls.enabled=true
|
|
tunnel.tls.allowInsecure=false
|
|
tunnel.tls.autoGenerate=true
|
|
```
|
|
|
|
When TLS is enabled, the proxy can generate:
|
|
|
|
```text
|
|
plugins/DirtSimpleP2P/certs/frontend.p12
|
|
```
|
|
|
|
On the backend:
|
|
|
|
```properties
|
|
tunnel.tls.enabled=true
|
|
tunnel.tls.allowInsecure=false
|
|
tunnel.tls.trustOnFirstUse=true
|
|
```
|
|
|
|
On the first successful TLS connection, the backend saves the proxy certificate fingerprint:
|
|
|
|
```properties
|
|
frontend.proxy1.tls.pinnedCertificateSha256=
|
|
```
|
|
|
|
After that, the backend only trusts that same certificate.
|
|
|
|
For stricter security, copy the certificate fingerprint from the proxy log and paste it into the backend config before the first connection.
|
|
|
|
## Multi-Server Setups
|
|
|
|
### Two Public Proxies, One Backend
|
|
|
|
Use this when two public BungeeCord/Waterfall proxies should both reach the same backend server.
|
|
|
|
Backend config:
|
|
|
|
```properties
|
|
role=backend
|
|
node.name=survival-backend
|
|
|
|
frontends=proxy1,proxy2
|
|
frontend.proxy1.connectHost=proxy1.example.com
|
|
frontend.proxy1.connectPort=24445
|
|
frontend.proxy1.tls.pinnedCertificateSha256=
|
|
frontend.proxy2.connectHost=proxy2.example.com
|
|
frontend.proxy2.connectPort=24445
|
|
frontend.proxy2.tls.pinnedCertificateSha256=
|
|
|
|
routes=minecraft
|
|
route.minecraft.backendTargetHost=127.0.0.1
|
|
route.minecraft.backendTargetPort=25565
|
|
```
|
|
|
|
Each proxy config:
|
|
|
|
```properties
|
|
role=frontend
|
|
node.name=proxy1
|
|
|
|
routes=minecraft
|
|
route.minecraft.frontendBindHost=127.0.0.1
|
|
route.minecraft.frontendBindPort=25566
|
|
route.minecraft.backendNode=survival-backend
|
|
```
|
|
|
|
Each proxy listens for tunnel connections. The backend connects outbound to both proxies.
|
|
|
|
### One Proxy, Multiple Backends
|
|
|
|
Use this when one proxy should expose more than one backend server.
|
|
|
|
Proxy config:
|
|
|
|
```properties
|
|
role=frontend
|
|
node.name=main-proxy
|
|
|
|
routes=survival,lobby
|
|
route.survival.frontendBindHost=127.0.0.1
|
|
route.survival.frontendBindPort=25566
|
|
route.survival.backendNode=survival-backend
|
|
route.lobby.frontendBindHost=127.0.0.1
|
|
route.lobby.frontendBindPort=25567
|
|
route.lobby.backendNode=lobby-backend
|
|
```
|
|
|
|
Bungee/Waterfall server entries:
|
|
|
|
```text
|
|
survival -> 127.0.0.1:25566
|
|
lobby -> 127.0.0.1:25567
|
|
```
|
|
|
|
Survival backend config:
|
|
|
|
```properties
|
|
role=backend
|
|
node.name=survival-backend
|
|
|
|
frontends=main
|
|
frontend.main.connectHost=YOUR_PROXY_IP
|
|
frontend.main.connectPort=24445
|
|
|
|
routes=survival
|
|
route.survival.backendTargetHost=127.0.0.1
|
|
route.survival.backendTargetPort=25565
|
|
```
|
|
|
|
Lobby backend config:
|
|
|
|
```properties
|
|
role=backend
|
|
node.name=lobby-backend
|
|
|
|
frontends=main
|
|
frontend.main.connectHost=YOUR_PROXY_IP
|
|
frontend.main.connectPort=24445
|
|
|
|
routes=lobby
|
|
route.lobby.backendTargetHost=127.0.0.1
|
|
route.lobby.backendTargetPort=25565
|
|
```
|
|
|
|
All nodes in the same private tunnel group must use the same `tunnel.authToken`.
|
|
|
|
## Commands
|
|
|
|
Run from the server console or in game:
|
|
|
|
```text
|
|
/dsp2p status
|
|
```
|
|
|
|
Shows role, node name, whether the tunnel is connected, connected tunnel count, active streams, TLS state, and the latest event.
|
|
|
|
```text
|
|
/dsp2p doctor
|
|
```
|
|
|
|
Checks the config and prints setup/security hints.
|
|
|
|
```text
|
|
/dsp2p webwizard
|
|
```
|
|
|
|
Toggles a temporary browser setup wizard.
|
|
|
|
When the wizard starts, the server console prints:
|
|
|
|
```text
|
|
Please sign in with this key: <temporary-key>
|
|
```
|
|
|
|
Open the printed URL in a browser and sign in with the temporary key.
|
|
|
|
The wizard provides guided sections for:
|
|
|
|
- server mode and node name
|
|
- proxy listener settings
|
|
- backend proxy connections
|
|
- Minecraft routes
|
|
- tunnel token and TLS
|
|
- heartbeat and reconnect settings
|
|
- advanced raw config keys
|
|
|
|
The web UI includes:
|
|
|
|
- `Save Config`
|
|
- `Save + Reload DirtSimpleP2P`
|
|
- `Reload Current Config`
|
|
- `Generate New Token`
|
|
|
|
Reloading from the wizard restarts the DirtSimpleP2P tunnel agent with the latest config. It does not run a full Minecraft server reload.
|
|
|
|
Run `/dsp2p webwizard` again to stop the wizard when setup is complete.
|
|
|
|
By default, the wizard binds to:
|
|
|
|
```properties
|
|
webwizard.bindHost=127.0.0.1
|
|
webwizard.port=8765
|
|
```
|
|
|
|
Keep it on `127.0.0.1` unless you understand the risk of exposing a config editor over the network.
|
|
|
|
Permission:
|
|
|
|
```text
|
|
dirtsimplep2p.command
|
|
```
|
|
|
|
On Paper/Spigot, the permission defaults to server operators. On BungeeCord/Waterfall, give this permission to staff who should see tunnel diagnostics.
|
|
|
|
## Firewall Notes
|
|
|
|
On the public proxy/VPS, allow the tunnel port:
|
|
|
|
```text
|
|
24445/tcp
|
|
```
|
|
|
|
On the home router, you do not need to forward the backend Minecraft port:
|
|
|
|
```text
|
|
25565/tcp
|
|
```
|
|
|
|
The backend server must be allowed to make outbound TCP connections to the proxy.
|
|
|
|
## Reconnect Behavior
|
|
|
|
DirtSimpleP2P is tuned to detect real drops quickly while still tolerating short latency spikes.
|
|
|
|
Default behavior:
|
|
|
|
- Heartbeat every `2` seconds
|
|
- Status warning if heartbeats are delayed
|
|
- Disconnect after about `8` seconds without tunnel traffic
|
|
- First reconnect retry after about `250ms`
|
|
- Exponential backoff up to `10` seconds while the proxy is unreachable
|
|
|
|
Useful config values:
|
|
|
|
```properties
|
|
tunnel.heartbeatIntervalMillis=2000
|
|
tunnel.heartbeatTimeoutMillis=8000
|
|
tunnel.heartbeatMissesBeforeDisconnect=4
|
|
tunnel.reconnectInitialMillis=250
|
|
tunnel.reconnectMaxMillis=10000
|
|
```
|
|
|
|
If your network has frequent latency spikes, increase:
|
|
|
|
```properties
|
|
tunnel.heartbeatMissesBeforeDisconnect=5
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Token Problems
|
|
|
|
The token must match on both sides.
|
|
|
|
If the plugin generated a token on the proxy, copy that generated value into the backend config.
|
|
|
|
### Backend Says Connection Refused
|
|
|
|
Check that:
|
|
|
|
- The proxy server is running
|
|
- DirtSimpleP2P started on the proxy
|
|
- `frontend.proxy1.connectHost` points to the proxy IP or domain
|
|
- `frontend.proxy1.connectPort` matches the proxy `tunnel.listenPort`
|
|
- The proxy firewall allows the tunnel port
|
|
|
|
### Bungee Cannot Reach The Backend
|
|
|
|
Make sure the Bungee/Waterfall backend server entry points to the local tunnel port:
|
|
|
|
```text
|
|
127.0.0.1:25566
|
|
```
|
|
|
|
Also check that the backend Paper/Spigot server is running and the tunnel is connected.
|
|
|
|
### Players Disconnect Or Freeze
|
|
|
|
Check both server logs for:
|
|
|
|
- reconnect messages
|
|
- heartbeat timeout messages
|
|
- stream reset messages
|
|
- backend target connection failed
|
|
|
|
## Security Notes
|
|
|
|
Keep `tunnel.authToken` private. Anyone with the token can attempt to authenticate to the tunnel.
|
|
|
|
For local testing, insecure mode is available:
|
|
|
|
```properties
|
|
tunnel.tls.enabled=false
|
|
tunnel.tls.allowInsecure=true
|
|
```
|
|
|
|
For real deployments, enable TLS:
|
|
|
|
```properties
|
|
tunnel.tls.enabled=true
|
|
tunnel.tls.allowInsecure=false
|
|
```
|
|
|
|
Trust-on-first-use is convenient, but the first TLS connection is the sensitive moment. For the strictest setup, manually copy the proxy certificate fingerprint into the backend config before the first connection.
|
|
|
|
The Web Wizard is intended as a temporary setup tool. It uses a random key printed to the server console and should be stopped when configuration is complete.
|
|
|
|
The reload button reloads DirtSimpleP2P itself. It intentionally does not run Paper/Bukkit `/reload`, because full server reloads are risky on production Minecraft servers.
|