File size: 4,864 Bytes
06a3be4
 
 
 
 
 
 
 
 
 
e0b0081
06a3be4
2f4bd8e
 
 
 
06a3be4
 
 
4ef5cfe
 
 
 
 
06a3be4
 
 
 
 
4ef5cfe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
06a3be4
1816c94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
06a3be4
 
 
 
 
 
4ef5cfe
 
 
06a3be4
4ef5cfe
06a3be4
 
 
 
4ef5cfe
 
 
 
 
 
06a3be4
4ef5cfe
06a3be4
 
 
2f4bd8e
 
 
 
06a3be4
 
2f4bd8e
 
 
 
 
4ef5cfe
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
---
title: Minecraft Server
emoji: 🧱
colorFrom: green
colorTo: blue
sdk: docker
app_port: 7860
pinned: false
---

# Minecraft Server (Java Edition 1.21.11)

[Paper](https://papermc.io) server (1.21.11, build 132) bundled with the
[playit.gg](https://playit.gg) agent so it can be reached from a normal
Minecraft client, plus a small web control panel that runs in the same
container.

## How the networking works

A Minecraft Java client speaks raw TCP and the Space only routes HTTPS to
`app_port` (7860), so the two cannot meet directly. The playit agent fixes this
without any inbound connectivity: it dials **out** to playit's relays and they
proxy the public address back down that same connection. The Space only ever
makes outbound requests.

```
Minecraft client ──TCP──> playit relay <──outbound──> playitd ──> java server :25565
```

Port 7860 hosts the **control panel** (live console, commands, stop/restart),
which also keeps the Space reporting as running.

## Control panel

Open the Space URL in a browser (keep it private if you want - accessing the
panel is separate from joining the game):

- Live server console with auto-scroll
- Send commands (`say hi`, `list`, `whitelist ...`, `/stop`) via the input or
  quick buttons
- **Stop** (graceful, saves the world) and **Restart**
- Status badges: server state, RAM/uptime, playit tunnel state
- Reading logs/status is open; commands and stop/restart require a password
  when one is configured

## Panel / API over HTTP

From a browser the panel page (`/`) already uses the API below. The public
`.hf.space` gateway only reliably forwards **GET** requests (POST bodies get
rejected or stripped of their JSON quotes), so the panel talks to the API with
GET + query parameters:

```sh
# status / logs
curl https://USER-SPACE.hf.space/api/status
curl "https://USER-SPACE.hf.space/api/log?after=-10"

# run a server command
curl --get --data-urlencode "cmd=list" https://USER-SPACE.hf.space/api/command
curl --get --data-urlencode "cmd=say hello" https://USER-SPACE.hf.space/api/command

# stop (graceful) / restart
curl --get --data-urlencode "action=stop" https://USER-SPACE.hf.space/api/action
curl --get --data-urlencode "action=restart" https://USER-SPACE.hf.space/api/action
```

If a `CONTROL_PASSWORD` is set, add the header `X-Token: <token>` where the
token is `sha256("panel-control:" + CONTROL_PASSWORD)`, and log in first via
`POST /api/login` for a panel session. JSON/form POST endpoints also exist
(`/api/command`, `/api/action`, `/api/login`) for callers that can reach the
container directly (e.g. from inside the Space).

## Setup

1. Create a Space with the **Docker** SDK and push this repo.
2. Generate a playit **secret key** (link in the playit dashboard, "new agent").
3. Add it in the Space settings under **Variables and secrets** as a **Secret**
   named `PLAYIT_SECRET`. Do not commit it.
4. (Recommended) Add a second Secret named `CONTROL_PASSWORD` to lock the
   panel's command/stop/restart actions. Leave it unset only while testing.
5. In the playit dashboard, create a tunnel of type **Minecraft Java** targeting
   `localhost:25565`, then claim it with this Space's agent.
6. Copy the assigned address and port into the Minecraft client's
   *Direct Connect* / *Add Server*.

## Configuration

| Variable          | Default | Notes                                        |
| ----------------- | ------- | -------------------------------------------- |
| `PLAYIT_SECRET`   | unset   | Required for the tunnel; server still boots without it |
| `CONTROL_PASSWORD`| unset   | Gives the panel Open Console / Stop / Restart a password. Leave unset = unlocked (testing only) |
| `MC_MEM`          | `4G`    | Both `-Xmx` and `-Xms`                        |
| `STATUS_PORT`     | `7860`  | Control panel; must match `app_port`           |

Server tuning lives in `server.properties` aboard the container.

## Caveats worth knowing

- **World persistence depends on your storage.** Fresh Spaces use ephemeral
  storage and are reset on restart; this space mounts a Storage Bucket at `/data`
  so the world/`server.properties` survive rebuilds and playit/client count resets
  only with a rebuild.
- **Offline mode is on** (`online-mode=false`), so any username can join and
  nothing is verified with Mojang. Turn it on if you want real authentication.
- **Server jar is Paper 1.21.11 (build 132, Java 21 bytecode).** The Paper
  bundler re-downloads the Mojang 1.21.11 server jar into `versions/` on first
  boot. It runs on the pinned `eclipse-temurin:25-jre-jammy` (Java 25) base image
  since newer JVMs run older class files. Swap `server.jar` and reuse `MC_JAR` if
  you change versions.
- The server auto-restarts on crash (3s backoff) and restarts if the container
  is recreated, so a failed boot loops in the logs - read the newest trace.