PaperScript is a dependency-free updater for Paper servers that uses the current PaperMC Fill v3 downloads service.
It is designed for the layout where your server root stays readable, while PaperScript keeps its own files in a visible paperscript/ directory:
/anydirectory/
/anydirectory/server.properties
/anydirectory/Paper-1.21.11-130.jar
/anydirectory/paperscript.sh
/anydirectory/paperscript/
/anydirectory/paperscript/paperscript.py
/anydirectory/paperscript/config.example.json
/anydirectory/paperscript/config.json
/anydirectory/paperscript/state.json
/anydirectory/paperscript/downloads/
/anydirectory/paperscript/backups/
/anydirectory/paperscript/logs.log
/anydirectory/paperscript/todo.log
This makes it easy to git pull, wipe PaperScript runtime files, or move between macOS and Ubuntu without flooding the server root with updater clutter.
Python is the best fit here for this project:
- It works well on modern macOS and Ubuntu without needing
jq, npm packages, or extra shell tooling. - JSON, version sorting, checksums, prompts, logging, and future expansion are much easier to keep readable.
- The runtime stays small: one Python script plus one tiny shell launcher.
- It is much easier to maintain than a large Bash script once features like status views, integrity checks, cleanup, and per-server config exist.
Bash still has a place here, which is why the launcher remains a simple paperscript.sh.
- Uses the PaperMC Fill v3 API.
- Sends a custom User-Agent by default:
mrfloris-PaperScript/2.0 (https://github.com/mrfdev/PaperScript) - Finds the latest stable Paper version and latest stable build automatically.
- Can inspect and install the latest experimental release overall.
- Only auto-updates when the stable build is newer for the same version.
- Prompts before cross-version upgrades.
- Prompts before downgrades.
- Supports forced re-download of the same build with
--force. - Verifies downloads against the API-provided SHA-256.
- Stores the installed SHA-256 in
state.jsonfor laterverifychecks. - Backs up the current jar before replacing it.
- Keeps only the newest 10 backups by default.
- Can trim backups to a chosen count with
cleanup --backups --keep N. - Detects likely running servers using
server-port, process checks, and tmux-aware graceful stop attempts. - Uses tmux by preference for graceful stop and falls back to
SIGTERM. - Supports
--dry-run,--quiet,--no-color, and per-server config defaults. - Supports color themes and a compact or full status view.
- Keeps updater runtime files isolated inside
paperscript/.
- Python
3.9+ python3available on your pathtmuxif you want graceful stop support
No third-party Python packages are required.
Clone the repo into the server directory or a test directory:
git clone https://github.com/mrfdev/PaperScript.git
cd PaperScript
chmod +x paperscript.sh paperscript/paperscript.pyIf you want to initialize or repair the runtime files manually:
./paperscript.sh initThat creates or repairs the local runtime pieces in paperscript/ and asks for confirmation before it changes anything.
Show the current state:
./paperscript.sh statusInstall the latest stable Paper release when appropriate:
./paperscript.sh updateForce a re-download of the current latest stable build:
./paperscript.sh --force updateInspect the latest experimental release:
./paperscript.sh experimentalDownload that experimental build:
./paperscript.sh experimental --downloadChecks the server directory, detects the latest stable Paper release, and installs it when appropriate.
Behavior:
- If no current
Paper-<version>-<build>.jarexists, it offers the latest stable build. - If your current version matches the newest stable version, it only downloads when the build number is newer.
- If your current version and build already match the newest stable release,
--force updatere-downloads it. - If the newest stable version is a newer Minecraft version, PaperScript asks before upgrading.
- If
server.propertiesexists and a likely matching Java process is running, PaperScript asks how to proceed. - If
--dry-runis used, it reports what it would do without changing files or stopping anything.
Examples:
./paperscript.sh
./paperscript.sh update
./paperscript.sh --force update
./paperscript.sh update --dry-run
./paperscript.sh --yes --quiet update
./paperscript.sh --no-color update
./paperscript.sh --server-dir /srv/mc/live updateShows the current PaperScript and Paper server state, the newest stable release, and the newest experimental release overall.
The normal full view can include:
- PaperScript release
- server directory and runtime directory
- server label
- tmux session name and whether it currently exists
- graceful stop command
- server properties detection
- configured server port
- running server detection
- current jar, version, build, and SHA-256
- stored expected SHA-256 from the last PaperScript install
- newest stable release
- update status
- newest channels for the current stable version
- newest experimental release overall
- backup retention settings
- backup file count and cleanup suggestions when useful
Status views:
./paperscript.sh statusFull status view./paperscript.sh status --compactShorter overview./paperscript.sh status --fullForce full mode even if config defaults to compact
Examples:
./paperscript.sh status
./paperscript.sh status --compact
./paperscript.sh --server-dir /srv/mc/live statusShows the latest stable Paper release overall and can install it directly.
This is useful when you want a clear stable overview without running a full update flow first.
Examples:
./paperscript.sh stable
./paperscript.sh stable --download
./paperscript.sh --force stable --download
./paperscript.sh stable --download --yes --forceShows the latest experimental Paper release overall and can install it directly.
This is different from the ALPHA line shown under the latest stable version in status.
For example:
Latest channels for stable version 1.21.11means the channels that exist for1.21.11Latest experimental release overallmay instead be something newer like26.1.2 build #7
Examples:
./paperscript.sh experimental
./paperscript.sh experimental --download
./paperscript.sh --yes experimental --download
./paperscript.sh experimental --download --yesHashes the current installed jar and compares it against:
- the SHA-256 recorded in
state.jsonduring the last PaperScript install - the expected SHA-256 from the live Paper API for that exact version and build
Examples:
./paperscript.sh verify
./paperscript.sh --server-dir /srv/mc/live verifyLists every Paper version the API currently exposes.
Examples:
./paperscript.sh list-versions
./paperscript.sh list-versions --channelsWith --channels, PaperScript also shows the newest build it can find per channel for each version.
This is useful for questions like:
- which versions exist at all
- whether
26.2.xonly exists as alpha or beta - whether
26.1.2is the newest stable or experimental family - whether older versions such as
1.20.4or1.19.2still have builds available
Shows the newest available build per channel for one specific version, then offers to download one interactively.
If the selected build is already installed, PaperScript can offer a direct Download it anyway? confirmation so you can re-download the same jar without leaving the inspect flow.
Examples:
./paperscript.sh inspect 1.20.4
./paperscript.sh inspect 1.19.2
./paperscript.sh inspect 26.1.2Interactive version picker. It lists all available versions, lets you choose one by number, shows the newest builds for that version, and can then download it.
If the build you choose is already installed, explore can offer the same Download it anyway? flow as inspect.
Examples:
./paperscript.sh exploreDownloads a chosen version or exact build on demand.
Examples:
./paperscript.sh download --version 26.1.2
./paperscript.sh download --version 1.20.4
./paperscript.sh download --version 1.20.4 --build 123
./paperscript.sh download --version 26.2.1 --channel BETA
./paperscript.sh --force download --version 26.1.2
./paperscript.sh --force download --version 1.21.11 --build 130
./paperscript.sh download --version 1.21.11 --build 130 --force --yesNotes:
--versiondownloads the newest build for that version on the selected channel.--builddownloads that exact build number for the version.- The default channel comes from
config.jsonand defaults toSTABLE. - Version upgrades still prompt unless you add
--yes. --forcelets you re-download and reinstall the same build even if it is already present.- Use
./paperscript.sh --force updateto re-download the current latest stable build. - Use
./paperscript.sh --force download --version <version> --build <build>to re-download one exact build.
Removes selected local runtime files and caches from paperscript/.
Default behavior:
./paperscript.sh cleanupCleans the safe/default targets:downloads/and Python__pycache__/
Targets:
--downloadsDelete staged downloads and temp files indownloads/--backupsClean backup jars--backups --keep NKeep the newestNbackups and remove older ones--allClean downloads, backups,__pycache__, logs, and JSON state/config together--pycacheDelete Python__pycache__/folders--logsClearlogs.log--jsonor--configDeleteconfig.jsonandstate.jsonso the next run starts fresh
Confirmation behavior:
- cleanup explains what will be removed
- cleanup asks for
y/Nconfirmation by default --yesskips the prompt--dry-runshows what would be deleted without removing anything
Examples:
./paperscript.sh cleanup
./paperscript.sh cleanup --all
./paperscript.sh cleanup --downloads
./paperscript.sh cleanup --backups
./paperscript.sh cleanup --backups --keep 10
./paperscript.sh cleanup --pycache
./paperscript.sh cleanup --logs
./paperscript.sh cleanup --json
./paperscript.sh cleanup --yes --downloads --pycache
./paperscript.sh cleanup --dry-run --jsonCreates or repairs local runtime files inside paperscript/.
It can create:
config.jsonstate.jsonlogs.logtodo.logdownloads/backups/
It always asks for confirmation unless you use --yes.
Examples:
./paperscript.sh init
./paperscript.sh --yes init
./paperscript.sh init --dry-run--server-dir PATHUse a specific server directory instead of the current directory.--contact VALUEOptional legacy contact value used to build aPaperScript/<version> (<contact>)User-Agent override.--user-agent VALUEFull custom User-Agent header. If omitted, PaperScript uses the built-in default.--tmux-session NAMEtmux session to use for graceful stop. Defaults to config,PAPERSCRIPT_TMUX_SESSION, ormcserver.--timeout SECONDSHTTP timeout in seconds. Default comes fromconfig.jsonand is30unless changed.--yesAccept prompts automatically where it is safe to do so.--forceReinstall even if the same build is already present. Most useful withupdate,stable --download,experimental --download, ordownload.--dry-runShow what would happen without downloading, moving jars, pruning backups, or stopping servers.--quietSuppress normal console output. Logs still go topaperscript/logs.log.--no-colorDisable ANSI colors in terminal output.
PaperScript also accepts these global flags after the command, so both styles work:
./paperscript.sh --yes --force stable --download
./paperscript.sh stable --download --yes --forceFor cron or scheduled tasks, the safest pattern is usually:
./paperscript.sh --yes --quiet updateThat keeps the run non-interactive, quiet on stdout, and still logged to paperscript/logs.log.
PaperScript uses this behavior:
- If you pass
--server-dir, that path is used. - If you run from a normal directory, the current working directory is treated as the server directory.
- If you run the Python file from inside a directory actually named
PaperScript, the parent directory is treated as the server directory.
That makes this work naturally:
cd /server
./paperscript.sh updateand also:
cd /server/paperscript
python3 paperscript.py updateIf server.properties exists, PaperScript assumes the directory may be a live server directory and checks for a likely matching Java process.
It first uses the server-port value from server.properties and looks for a Java process listening on that exact TCP port. That makes it safer on a machine that runs several Minecraft servers at once.
If port-based detection does not find anything, it falls back to:
- jar-name matching
- command-line matching
- working-directory matching
When it finds one, it offers:
- graceful stop
- force stop
- upgrade anyway
- exit
Graceful stop behavior:
- first tries
tmux send-keys -t <session> stop Enter - then waits for exit
- if that fails, falls back to
SIGTERM
Force stop uses SIGKILL.
Examples:
./paperscript.sh --tmux-session production update
PAPERSCRIPT_TMUX_SESSION=test-server ./paperscript.sh updatePaperScript stores its runtime files inside the visible paperscript/ directory:
paperscript/config.example.jsonTracked config template for the repopaperscript/config.jsonLocal per-server config, intentionally ignored by gitpaperscript/state.jsonLast installed jar information, intentionally ignored by gitpaperscript/logs.logActivity logpaperscript/downloads/Temporary and staged downloadspaperscript/backups/Previous jars moved out of the server rootpaperscript/todo.logDeferred future ideas for the project
These runtime files are isolated on purpose so the server root stays clean and different servers can keep different local settings without git noise.
PaperScript creates paperscript/config.json automatically if it does not exist yet.
The repo includes a tracked template at paperscript/config.example.json.
Current default config:
{
"server_name": null,
"tmux_session": "mcserver",
"default_channel": "STABLE",
"check_latest_channel_only": "STABLE",
"allow_cross_version_auto_upgrade": false,
"allow_same_version_build_upgrade": true,
"keep_backups": 10,
"cleanup_backups_after_install": true,
"running_server_action": "ask",
"graceful_stop_command": "stop",
"http_timeout_seconds": 30,
"status_show_all_channels": true,
"download_filename_pattern": "Paper-{version}-{build}.jar",
"log_file": "logs.log",
"backup_dir": "backups",
"downloads_dir": "downloads",
"confirm_before_force_download": true,
"confirm_before_downgrade": true,
"auto_detect_server_by_port": true,
"fallback_process_detection": true,
"quiet": false,
"no_color": false,
"color_theme": "default",
"default_status_view": "full",
"command_hint_mode": "auto",
"release_link_mode": "auto"
}Useful per-server settings:
server_nameFriendly label for status outputtmux_sessionSession to use for graceful stopkeep_backupsHow many backup jars to keep after installrunning_server_actionDefault behavior when a running server is detecteddefault_channelDefault download channel fordownload --versionquietMake unattended runs silent by defaultno_colorDisable ANSI colors by defaultcolor_themeTheme name. Current options:default,soft,high-contrastdefault_status_viewfullorcompactcommand_hint_modeauto,always, orneverrelease_link_modeauto,always, ornever
If you already have a jar installed but want the same file again anyway, use one of these:
./paperscript.sh --force update
./paperscript.sh --force stable --download
./paperscript.sh --force experimental --download
./paperscript.sh --force download --version 1.21.11 --build 130
./paperscript.sh stable --download --yes --forceInside inspect and explore, PaperScript can also offer:
Download it anyway? [y/N]
when the selected build is already installed.
Check a live server without changing anything:
./paperscript.sh status
./paperscript.sh verify
./paperscript.sh update --dry-runUpdate a dev server in the current directory:
./paperscript.sh updateSee whether a newer version family exists before touching production:
./paperscript.sh list-versions --channels
./paperscript.sh stable
./paperscript.sh experimentalInspect an older branch:
./paperscript.sh inspect 1.20.4Download an exact historical build:
./paperscript.sh download --version 1.19.2 --build 88Target a separate server directory:
./paperscript.sh --server-dir /Users/you/minecraft/test-server updatePaperScript keeps a live local todo file at paperscript/todo.log for deferred ideas that are not implemented yet.
Current queued ideas include:
- optional update scheduling or smarter unattended workflows
- extra selective cleanup and repair helpers
- richer tmux and server control helpers such as start, stop, and restart
- additional smoke-test or planner-style validation modes
PaperScript is built around the current PaperMC downloads service and its User-Agent expectations:
- Docs: https://docs.papermc.io/misc/downloads-service/
- Swagger UI: https://fill.papermc.io/swagger-ui/index.html#/
- Downloads page: https://papermc.io/downloads/paper
MIT. See LICENSE.