Skip to content

Instantly share code, notes, and snippets.

@crischutu07
Last active June 20, 2025 00:34
Show Gist options
  • Save crischutu07/9c4e9ae237e62472e215edd6dd9afe0b to your computer and use it in GitHub Desktop.
Save crischutu07/9c4e9ae237e62472e215edd6dd9afe0b to your computer and use it in GitHub Desktop.
Minecraft server installer for Linux (requires fzf and jq and probably curl and tac)
#!/usr/bin/env bash
servers=(PurpurMC PaperMC Velocity Waterfall "PocketMine-MP")
DEFAULT_SERVER="${servers[0]}"
# Dependency programs
DEPS=(curl fzf tac jq)
for i in "${DEPS[@]}"; do
if ! command -v "$i" > /dev/null 2>&1; then
echo "Command '$i' is not found."
exit 1
fi
done
echo -e "Select the server you wanted to install"
for ((i=0; i<${#servers[@]}; i++)); do
if [ "${DEFAULT_SERVER}" = "${servers[i]}" ]; then
echo "$((i+1)). ${servers[i]} (Default)"
else
echo "$((i+1)). ${servers[i]}"
fi
done
read -rp '> ' selectserver
# make case-insensitive.
case "${selectserver,,}" in
1|purpur|purpurmc) selectedServer="${servers[0]}";;
2|paper|papermc) selectedServer="${servers[1]}";;
3|velocity) selectedServer="${servers[2]}";;
4|waterfall) selectedServer="${servers[3]}";;
5|pmmp|pocketmine-mp|pocketmine|pocketminemp) selectedServer="${servers[4]}";;
'') selectedServer="${DEFAULT_SERVER}";;
*) echo "Invalid selection."; exit 1;;
esac
function getPaper() {
case "$1" in
velocity)
endpoint="https://api.papermc.io/v2/projects/velocity"
brand="Velocity"
id="velocity";;
waterfall)
endpoint="https://api.papermc.io/v2/projects/waterfall"
brand="Waterfall"
id="waterfall"
echo "WARNING: Waterfall is depecreated, consider using Velocity over Waterfall, proceed with caution!";;
*) endpoint="https://api.papermc.io/v2/projects/paper"; brand="PaperMC"; id="paper";;
esac
stty -echo
echo "[$brand] Fetching available versions..."
tmpversion=$(curl -s "$endpoint" | jq -r '.versions[]')
stty -echo
version=$(fzf --tac --prompt="[$brand] Version: " --exact <<< "$tmpversion")
unset tmpvesion
stty -echo
if [ -z "$version" ]; then
echo " ╰─ Please select the version"
stty echo
exit 1
fi
echo " ╰─ Version: $version"
echo "[$brand] Fetching available builds..."
tmpbuild=$(curl -s "$endpoint/versions/${version}" | jq -r '.builds[]')
stty echo
build=$(fzf --tac --prompt="[$brand $version] Build: " --exact <<< "$tmpbuild")
unset tmpbuild
stty -echo
if [ -z "$build" ]; then
echo " ╰─ Please select the build for $version"
stty echo
exit 1
fi
echo " ╰─ Build: $build"
stty -echo
result=$(curl -s "$endpoint/versions/${version}/builds/${build}")
channel="$(jq -r '.channel' <<< "${result}")"
date="$(jq -r '.time' <<< "${result}")"
if [ "$channel" = 'experimental' ]; then
echo "WARNING: This build may contains bug and not compatible with some plugins, proceed with caution!"
fi
echo "${brand} ${version} (build #${build})"
echo " ├─ Released in: $(date -d "${date}" '+%A %B %d, %Y (%r)')"
echo " ╰─ Channel: $channel"
stty echo
read -rp "> Proceed install this build? [Y/N] (default: Y): " yn
echo
case "${yn:0:1}" in
[Yy])
echo "[$brand] Running: curl -o \"${id}-${version}-${build}.jar\" \"${endpoint}/versions/${version}/builds/${build}/downloads/${id}-${version}-${build}.jar\""
curl -o "${id}-${version}-${build}.jar" "${endpoint}/versions/${version}/builds/${build}/downloads/${id}-${version}-${build}.jar"
;;
[Nn]) exit 2;;
'')
echo "[$brand] Running: curl -o \"${id}-${version}-${build}.jar\" \"${endpoint}/versions/${version}/builds/${build}/downloads/${id}-${version}-${build}.jar\""
curl -o "${id}-${version}-${build}.jar" "${endpoint}/versions/${version}/builds/${build}/downloads/${id}-${version}-${build}.jar"
;;
*) exit 2;;
esac
}
getPurpur () {
brand="PurpurMC"
id="purpur"
endpoint="https://api.purpurmc.org/v2/${id}"
stty -echo
echo "[$brand] Fetching minecraft versions.."
tmpversion=$(curl -s "$endpoint" | jq -r '.versions[]')
stty echo
version=$(fzf --tac --prompt="[$brand] Version: " --exact <<< "$tmpversion")
unset tmpvesion
stty -echo
if [ -z "$version" ]; then
echo "Please select the version"
stty echo
exit 1
fi
echo " ╰─ Version: $version"
echo "[$brand] Fetching available builds..."
tmpbuild=$(curl -s "$endpoint/${version}" | jq -r '.builds.all[]' | sort -n)
stty echo
build=$(fzf --tac --prompt="[$brand $version] Build: " --exact <<< "$tmpbuild")
unset tmpbuild
stty -echo
if [ -z "$build" ]; then
echo " ╰─ Please select the build for $version"
stty echo
exit 1
fi
echo " ╰─ Build: $build"
stty -echo
result=$(curl -s "$endpoint/${version}/${build}")
channel=$(jq -r '.result' <<< "${result}")
# Unix timestamp (in milliseconds)
date=$(jq -r '.timestamp' <<< "${result}")
echo "$brand $version (Build #${build})"
echo " ╰─ Build date: $(date -d "@$(("${date}"/1000))" '+%A %B %d, %Y (%r)')"
echo " ╰─ Channel: ${channel}"
stty echo
read -rp "> Proceed install this build? [Y/N] (default: Y): " yn
echo
case "${yn:0:1}" in
[Nn]) exit 2;;
[Yy])
echo "[$brand] Running: curl -o \"${id}-${version}-${build}.jar\" \"${endpoint}/${version}/${build}/download\""
curl -o "${id}-${version}-${build}.jar" "${endpoint}/${version}/${build}/download"
;;
'')
echo "[$brand] Running: curl -o \"${id}-${version}-${build}.jar\" \"${endpoint}/${version}/${build}/download\""
curl -o "${id}-${version}-${build}.jar" "${endpoint}/${version}/${build}/download"
;;
*) exit 2;;
esac
}
getPMMP (){
url="https://get.pmmp.io"
brand="PocketMine-MP"
# id="pmmp"
echo "NOTICE: $brand is a server software for Bedrock Edition"
read -rp "Press [Enter] to proceed the action." yn
case "${yn:0:1}" in
'') echo;;
*) exit 2;;
esac
echo "[${brand}] Running ${url}"
curl -sL "${url}" | bash -s -
}
case "$selectedServer" in
"${servers[0]}") getPurpur;;
"${servers[1]}") getPaper;;
"${servers[2]}") getPaper velocity;;
"${servers[3]}") getPaper waterfall;;
"${servers[4]}") getPMMP;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment