A tool for turning a singleplayer Minecraft world into a real standalone dedicated
server, running independently of the game client, with a persistent join address
(via a relay - see relay/) that stays the same across restarts. Inspired
by e4mc, whose tunneled address is tied to the game
client's own session and resets whenever you close it.
The server keeps running after you close Minecraft. With autostart enabled, it also comes back automatically after a reboot (as long as your PC is on).
MCPersist-windows.zip from Releases and extract it.MCPersist.exe inside the extracted folder. Click Set Up New World -
instances from Prism/MultiMC/PolyMC/ATLauncher and the official launcher are
detected automatically and offered as a pick-list; pick one, or point it at your
instance folder yourself if yours isn't found. Then either select one of your existing
singleplayer worlds to promote, generate a brand-new one from scratch, or switch
to a server you've already set up before (instant, no re-download), and follow the
wizard - the right Java version downloads automatically if you don't already have
it, no separate install needed.Set up more than one world over time? Every server you've made stays around - open Set Up New World again and pick Switch to a Previous Server to jump between them instantly, without re-downloading anything.
No Python install needed for this path - everything's bundled into the folder.
A note on antivirus/SmartScreen warnings: MCPersist isn't code-signed (that costs money and this is a free hobby project), so some antivirus engines and Windows SmartScreen may flag or warn about the binary the first time - this is extremely common for small, unsigned open-source tools and not evidence of anything malicious. The source is fully here in this repo if you'd rather verify or build it yourself; see Building from source.
MCPersist checks GitHub for a newer release once when it starts up. If one's out, a
banner with an Update Now button shows up on the status screen - click it and it
downloads, installs, and restarts itself, no manual re-download needed. This only
applies to the packaged .exe; running from source, use git pull instead (run.bat check-update will tell you if there's anything new either way).
Setup auto-detects the world's owner from the save file and whitelists just them - the server starts closed by default, not open.
Leave the whitelist on. Once the tunnel is up, your server is reachable at a public address. Port-scanning bots and random players routinely find and probe open Minecraft servers on the internet - this isn't a hypothetical risk. With online-mode on but no whitelist, literally any real Minecraft account can join and grief the world. Turning the whitelist off, even briefly, means anyone who happens to scan your address in that window gets in.
The main status screen always shows whether the whitelist is currently ON or OFF (with a warning if it's off) and who's currently on it, so it's not something you have to remember to check or dig through a log for.
To add or remove a friend, run either through RCON/the server console, or in-game by an op:
whitelist add <their exact Minecraft username>
whitelist remove <username>
whitelist list
Case-sensitive, needs their real account name. To make someone an op too:
op <username>, same way. All of these take effect immediately, no restart needed -
or from the CLI, run.bat whitelist-add <username> does the same as the first one
(works whether the server's running or not).
If the owner couldn't be auto-detected during setup (an ambiguous or already-shared
world - setup says so explicitly when this happens), the whitelist is left off and
flagged with a warning - turn it on yourself as soon as possible: set
white-list=true in server.properties, add players to whitelist.json (server
stopped) or via whitelist add/whitelist on over RCON (server running).
RAM and view/simulation distance are auto-sized from your PC's specs by default (a background-persistent server shares the machine with whatever else you're doing, so this favors running smoothly alongside other things over maxing out the hardware) - visible and editable in the Memory and Performance sections of the status screen, each with an Auto toggle. Turn it off to set a value yourself; either way, changes take effect on the next Start/Restart, not retroactively on an already-running server (the status screen tells you which, once you hit Save).
Starting the server connects to the relay baked into config.json's defaults with
no setup required - it registers automatically and gets back a random address
(e.g. quiet-badger.mcpersist.com). That address is ephemeral: it can change on the
next start.
For a fixed, memorable address that never changes - the actual point of this
project for anyone who cares about persistence - get a subdomain + token from
whoever runs the relay you're using, then run configure-relay (CLI) or use the
Configure Relay option (only relevant if you're managing a reserved address; most
people never need it). That reserves the subdomain permanently - every future start
uses it instead of a random one.
The relay (the piece that gives out addresses like *.mcpersist.com) is just as
open source as the client - see relay/README.md for deploying
your own on a VPS you control. Point any MCPersist client at it with
configure-relay; nothing about the client is tied to the default one.
mods/ folder as a starting point. Client-only
mods (rendering, HUD, etc.) can crash a dedicated server - if startup fails, check
servers/<world>/logs/server.out.log and remove the offending mod(s) from
servers/<world>/mods/.java_path in config.json is still the default,
setup/start download a matching portable Temurin JRE into bin/ themselves (like
Prism/MultiMC do) rather than requiring a system-wide install. Set java_path
explicitly if you'd rather point at your own Java install instead.mods/
folder - e4mc is built against different Minecraft mappings server-side and crashes
the whole server the moment a player joins if left in. You don't need it anyway;
MCPersist replaces what it does.relay/README.md.servers/<world>/world if that matters to you.mcpersist/
cli.py the `run.bat ...` command-line interface
tray_app.py the GUI's entry point (main window)
gui_pages.py the GUI's screens (status, setup wizard)
actions.py start/stop/status logic - shared by the CLI and GUI
setup_flow.py setup/configure-relay logic - shared by the CLI and GUI
world.py reads world saves: version/loader/owner detection
server_vanilla.py downloads a matching vanilla server jar
server_fabric.py downloads a matching Fabric server jar + mods
java_manager.py auto-downloads a matching portable Java (Temurin) if needed
mojang.py UUID -> username lookups (for whitelist/op)
tunnel_relay.py launches the tunnel client as a detached process
tunnel_relay_run.py the tunnel client itself - talks to the relay
process_manager.py detached-process/PID-file management
rcon.py minimal RCON client (graceful server stop, admin commands)
config.py config.json load/save, RAM/view-distance auto-sizing
autostart.py start-on-login (Task Scheduler or Startup-folder fallback)
version.py the app's own version, compared against GitHub releases
update_checker.py checks for/applies updates to the packaged .exe
relay/ runs on a VPS you control - see relay/README.md
relay_server.py the relay: routes connections by subdomain, pipes bytes
mc_handshake.py parses just enough of the Minecraft protocol to read the
hostname a connecting client typed
users.py / auto_assignments.py reserved and auto-assigned subdomain registries
admin_cli.py operator CLI for issuing subdomain+token pairs
setup copies the chosen world, downloads a matching server, and writes
server.properties/eula.txt/whitelist.start launches the server and the tunnel client as detached background
processes (not tied to the terminal/GUI that started them), so closing either
doesn't stop them.stop sends stop to the server over RCON for a clean shutdown, then stops the
tunnel.autostart install registers a Windows Scheduled Task that runs start at login -
or, if Task Scheduler's "on logon" trigger is blocked (some locked-down/managed
Windows images restrict it for standard users), falls back to a Startup-folder
entry instead, which needs no special privileges.For contributors, or anyone who'd rather not run a downloaded binary:
git clone <this repo>
cd MCPersist
pip install -r requirements.txt
python -m mcpersist setup
python -m mcpersist start # or: python main_gui.py, for the GUI
To build the binary yourself:
pip install pyinstaller
pyinstaller --name MCPersist --onedir --windowed --noupx main_gui.py
(--onedir, not --onefile - a self-extracting single exe is exactly the pattern
that gets flagged as a false positive by some antivirus engines; see the note above.
The build lands in dist/MCPersist/ - zip that folder up if you want to distribute
it, same as the release builds do.)
Troubleshooting a locked-down/managed Windows machine: if python.org's installer
fails with 0x80070003 from Windows Installer, or pip install fails building a
package from source with no compiler available, your machine may be blocking
MSI-based installs and/or lack a C toolchain (common on corporate/managed images).
Workarounds: use Python's embeddable
package (a portable zip, no installer)
instead of the normal installer, and prefer packages that ship prebuilt wheels for
your Python version over ones that need to compile from source.
A Windows/Java quirk worth knowing: on a machine with a long username, Java's
networking can fail to start at all with Unable to establish loopback connection /
Invalid argument: connect. Root cause: Java opens an internal AF_UNIX socket
under %TEMP%, and that path is capped at ~108 bytes - a long
C:\Users\<name>\AppData\Local\Temp\... can push it over the limit. MCPersist works
around this by launching the server with TEMP/TMP pointed at a short path instead
(see SHORT_TMP_DIR in mcpersist/process_manager.py) - if you ever see that error
in server.out.log, this is the first thing to check.
MIT - see LICENSE.
46 commits
Python
99.7%
A tool for turning a singleplayer Minecraft world into a real standalone dedicated
server, running independently of the game client, with a persistent join address
(via a relay - see relay/) that stays the same across restarts. Inspired
by e4mc, whose tunneled address is tied to the game
client's own session and resets whenever you close it.
The server keeps running after you close Minecraft. With autostart enabled, it also comes back automatically after a reboot (as long as your PC is on).
MCPersist-windows.zip from Releases and extract it.MCPersist.exe inside the extracted folder. Click Set Up New World -
instances from Prism/MultiMC/PolyMC/ATLauncher and the official launcher are
detected automatically and offered as a pick-list; pick one, or point it at your
instance folder yourself if yours isn't found. Then either select one of your existing
singleplayer worlds to promote, generate a brand-new one from scratch, or switch
to a server you've already set up before (instant, no re-download), and follow the
wizard - the right Java version downloads automatically if you don't already have
it, no separate install needed.Set up more than one world over time? Every server you've made stays around - open Set Up New World again and pick Switch to a Previous Server to jump between them instantly, without re-downloading anything.
No Python install needed for this path - everything's bundled into the folder.
A note on antivirus/SmartScreen warnings: MCPersist isn't code-signed (that costs money and this is a free hobby project), so some antivirus engines and Windows SmartScreen may flag or warn about the binary the first time - this is extremely common for small, unsigned open-source tools and not evidence of anything malicious. The source is fully here in this repo if you'd rather verify or build it yourself; see Building from source.
MCPersist checks GitHub for a newer release once when it starts up. If one's out, a
banner with an Update Now button shows up on the status screen - click it and it
downloads, installs, and restarts itself, no manual re-download needed. This only
applies to the packaged .exe; running from source, use git pull instead (run.bat check-update will tell you if there's anything new either way).
Setup auto-detects the world's owner from the save file and whitelists just them - the server starts closed by default, not open.
Leave the whitelist on. Once the tunnel is up, your server is reachable at a public address. Port-scanning bots and random players routinely find and probe open Minecraft servers on the internet - this isn't a hypothetical risk. With online-mode on but no whitelist, literally any real Minecraft account can join and grief the world. Turning the whitelist off, even briefly, means anyone who happens to scan your address in that window gets in.
The main status screen always shows whether the whitelist is currently ON or OFF (with a warning if it's off) and who's currently on it, so it's not something you have to remember to check or dig through a log for.
To add or remove a friend, run either through RCON/the server console, or in-game by an op:
whitelist add <their exact Minecraft username>
whitelist remove <username>
whitelist list
Case-sensitive, needs their real account name. To make someone an op too:
op <username>, same way. All of these take effect immediately, no restart needed -
or from the CLI, run.bat whitelist-add <username> does the same as the first one
(works whether the server's running or not).
If the owner couldn't be auto-detected during setup (an ambiguous or already-shared
world - setup says so explicitly when this happens), the whitelist is left off and
flagged with a warning - turn it on yourself as soon as possible: set
white-list=true in server.properties, add players to whitelist.json (server
stopped) or via whitelist add/whitelist on over RCON (server running).
RAM and view/simulation distance are auto-sized from your PC's specs by default (a background-persistent server shares the machine with whatever else you're doing, so this favors running smoothly alongside other things over maxing out the hardware) - visible and editable in the Memory and Performance sections of the status screen, each with an Auto toggle. Turn it off to set a value yourself; either way, changes take effect on the next Start/Restart, not retroactively on an already-running server (the status screen tells you which, once you hit Save).
Starting the server connects to the relay baked into config.json's defaults with
no setup required - it registers automatically and gets back a random address
(e.g. quiet-badger.mcpersist.com). That address is ephemeral: it can change on the
next start.
For a fixed, memorable address that never changes - the actual point of this
project for anyone who cares about persistence - get a subdomain + token from
whoever runs the relay you're using, then run configure-relay (CLI) or use the
Configure Relay option (only relevant if you're managing a reserved address; most
people never need it). That reserves the subdomain permanently - every future start
uses it instead of a random one.
The relay (the piece that gives out addresses like *.mcpersist.com) is just as
open source as the client - see relay/README.md for deploying
your own on a VPS you control. Point any MCPersist client at it with
configure-relay; nothing about the client is tied to the default one.
mods/ folder as a starting point. Client-only
mods (rendering, HUD, etc.) can crash a dedicated server - if startup fails, check
servers/<world>/logs/server.out.log and remove the offending mod(s) from
servers/<world>/mods/.java_path in config.json is still the default,
setup/start download a matching portable Temurin JRE into bin/ themselves (like
Prism/MultiMC do) rather than requiring a system-wide install. Set java_path
explicitly if you'd rather point at your own Java install instead.mods/
folder - e4mc is built against different Minecraft mappings server-side and crashes
the whole server the moment a player joins if left in. You don't need it anyway;
MCPersist replaces what it does.relay/README.md.servers/<world>/world if that matters to you.mcpersist/
cli.py the `run.bat ...` command-line interface
tray_app.py the GUI's entry point (main window)
gui_pages.py the GUI's screens (status, setup wizard)
actions.py start/stop/status logic - shared by the CLI and GUI
setup_flow.py setup/configure-relay logic - shared by the CLI and GUI
world.py reads world saves: version/loader/owner detection
server_vanilla.py downloads a matching vanilla server jar
server_fabric.py downloads a matching Fabric server jar + mods
java_manager.py auto-downloads a matching portable Java (Temurin) if needed
mojang.py UUID -> username lookups (for whitelist/op)
tunnel_relay.py launches the tunnel client as a detached process
tunnel_relay_run.py the tunnel client itself - talks to the relay
process_manager.py detached-process/PID-file management
rcon.py minimal RCON client (graceful server stop, admin commands)
config.py config.json load/save, RAM/view-distance auto-sizing
autostart.py start-on-login (Task Scheduler or Startup-folder fallback)
version.py the app's own version, compared against GitHub releases
update_checker.py checks for/applies updates to the packaged .exe
relay/ runs on a VPS you control - see relay/README.md
relay_server.py the relay: routes connections by subdomain, pipes bytes
mc_handshake.py parses just enough of the Minecraft protocol to read the
hostname a connecting client typed
users.py / auto_assignments.py reserved and auto-assigned subdomain registries
admin_cli.py operator CLI for issuing subdomain+token pairs
setup copies the chosen world, downloads a matching server, and writes
server.properties/eula.txt/whitelist.start launches the server and the tunnel client as detached background
processes (not tied to the terminal/GUI that started them), so closing either
doesn't stop them.stop sends stop to the server over RCON for a clean shutdown, then stops the
tunnel.autostart install registers a Windows Scheduled Task that runs start at login -
or, if Task Scheduler's "on logon" trigger is blocked (some locked-down/managed
Windows images restrict it for standard users), falls back to a Startup-folder
entry instead, which needs no special privileges.For contributors, or anyone who'd rather not run a downloaded binary:
git clone <this repo>
cd MCPersist
pip install -r requirements.txt
python -m mcpersist setup
python -m mcpersist start # or: python main_gui.py, for the GUI
To build the binary yourself:
pip install pyinstaller
pyinstaller --name MCPersist --onedir --windowed --noupx main_gui.py
(--onedir, not --onefile - a self-extracting single exe is exactly the pattern
that gets flagged as a false positive by some antivirus engines; see the note above.
The build lands in dist/MCPersist/ - zip that folder up if you want to distribute
it, same as the release builds do.)
Troubleshooting a locked-down/managed Windows machine: if python.org's installer
fails with 0x80070003 from Windows Installer, or pip install fails building a
package from source with no compiler available, your machine may be blocking
MSI-based installs and/or lack a C toolchain (common on corporate/managed images).
Workarounds: use Python's embeddable
package (a portable zip, no installer)
instead of the normal installer, and prefer packages that ship prebuilt wheels for
your Python version over ones that need to compile from source.
A Windows/Java quirk worth knowing: on a machine with a long username, Java's
networking can fail to start at all with Unable to establish loopback connection /
Invalid argument: connect. Root cause: Java opens an internal AF_UNIX socket
under %TEMP%, and that path is capped at ~108 bytes - a long
C:\Users\<name>\AppData\Local\Temp\... can push it over the limit. MCPersist works
around this by launching the server with TEMP/TMP pointed at a short path instead
(see SHORT_TMP_DIR in mcpersist/process_manager.py) - if you ever see that error
in server.out.log, this is the first thing to check.
MIT - see LICENSE.
46 commits
Python
99.7%