Setting up a Minecraft server from scratch.
Features:
- OS: Debian stable
- Server: Paper
- SSH: OpenSSH
- Firewall: UFW
- Java: OpenJDK JRE
- Auto update OS
- Auto update server
- Auto local snapshot
- Encrypted drive with USB unlock
- Remote lookup of dynamic IP
- Logs
First step is creating a bootable USB to do a fresh install of Debian.
- Visit https://www.debian.org/download
- Download the latest "netinst" of the "stable" release.
- Verify download using the SHA checksum.
- Determine the name of the USB drive, something of the kind
/dev/diskX
- Copy the image, replacing
X
:
sudo dd if=debian-X-X-netinst.iso of=/dev/diskX bs=1024k status=progress
Boot of the USB and follow instructions. Do:
- Not create a root user.
- Use LVM with encrypted drive.
- Not install a desktop environment.
- Install SSH server.
On server, get the fingerprint of the public key and the IP address:
ssh-keygen -E md5 -lf /etc/ssh/ssh_host_rsa_key.pub
ssh-keygen -E md5 -lf /etc/ssh/ssh_host_ecdsa_key.pub
ssh-keygen -E md5 -lf /etc/ssh/ssh_host_ed25519_key.pub
hostname -I
On client, update your ssh config according to ssh/config
,
replacing X
with hostname and IP address:
nano ~/.ssh/config
Copy SSH key, replacing X
with hostname:
ssh-copy-id X
SSH into server using private key, replacing X
with hostname:
ssh X
From here on, all commands are to be run on the server over SSH.
Update the SSH config according to sshd_config
, replacing
X
:
sudo nano /etc/ssh/sshd_config
Restart SSH service:
sudo systemctl restart sshd
systemctl status sshd
Set up UFW firewall, with ssh and Minecraft server ports (25565 for Java Edition, 19132:19133 for Bedrock):
sudo apt update && sudo apt upgrade
sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow proto tcp from 192.168.0.0/16 to any port 25565
sudo ufw allow proto tcp from 192.168.0.0/16 to any port 19132:19133
sudo ufw allow proto udp from 192.168.0.0/16 to any port 19132:19133
sudo ufw enable
sudo ufw status
Additionally, if you want to make the server accessible outside of your network:
sudo ufw allow 25565/tcp
sudo ufw allow 19132:19133/tcp
sudo ufw allow 19132:19133/udp
Have you server boot without requiring you to enter disk encryption passphrase.
Insert USB stick. Find USB and encrypted drive:
lsblk
Create a random passphrase, write it to USB, and add it to LUKS, replacing X
according to the above listing:
head -c 256 /dev/urandom > passphrase
sudo dd if=passphrase of=/dev/sdX bs=1
sudo cryptsetup luksAddKey /dev/sdaX passphrase
rm passphrase
Find the id
of the USB drive:
ls -l /dev/disk/by-id
In crypttab
, replace none
with the ID and append
,keyscript=/usr/local/bin/passphrase-from-usb
.
sudo nano /etc/crypttab
Create the script file according to
passphrase-from-usb
and make it executable:
sudo nano /usr/local/bin/passphrase-from-usb
sudo chmod 755 /usr/local/bin/passphrase-from-usb
Update initramfs:
sudo update-initramfs -u
Restart the system to confirm change:
sudo shutdown -r now
Keep your software up to date, automatically.
Set up Unattended Upgrades:
sudo apt install unattended-upgrades
Update the config according to
50unattended-upgrades
:
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Create auto-upgrade according to 20auto-upgrades
:
sudo nano /etc/apt/apt.conf.d/20auto-upgrades
Download Paper and plugins, automatically.
Add minecraft
user:
sudo groupadd --system minecraft
sudo useradd --system --gid minecraft --shell /usr/sbin/nologin --home-dir /opt/minecraft minecraft
Create home folder in /opt
:
sudo mkdir -p /opt/minecraft/server/plugins
sudo chown -R minecraft:minecraft /opt/minecraft
ls -la /opt/minecraft
Create log file in /var/log
:
sudo touch /var/log/minecraft.log
sudo chown minecraft:minecraft /var/log/minecraft.log
ls -la /var/log
Create download script according to download-paper
:
sudo nano /usr/local/bin/download-paper
Make script executable and execute:
sudo chmod +x /usr/local/bin/download-paper
sudo -u minecraft /usr/local/bin/download-paper
tail /var/log/minecraft.log
Set up the Paper server, as a service.
Install screen and openJDK:
sudo apt install screen openjdk-17-jre
Create service according to minecraft.service
:
sudo nano /etc/systemd/system/minecraft.service
Start the service:
sudo systemctl start minecraft
systemctl status minecraft
Once the service has stopped, accept the EULA (eula=true
):
sudo -u minecraft nano /opt/minecraft/server/eula.txt
Update server settings according to
server.properties
, replacing X
:
sudo -u minecraft nano /opt/minecraft/server/server.properties
Optionally, if server.properties was not created, you can debug by running:
cd /opt/minecraft/server
sudo -u minecraft /usr/bin/java -jar paper.jar --nogui
Make sure to exit (Ctrl+C) before continuing.
Load plugins and update Geyser settings according to
config.yaml
, replacing X
:
sudo systemctl start minecraft
sudo -u minecraft nano /opt/minecraft/server/plugins/Geyser-Spigot/config.yml
Enable and run the service:
sudo systemctl enable minecraft
sudo systemctl restart minecraft
systemctl status minecraft
To view the server log:
tail /opt/minecraft/server/logs/latest.log
To run commands (Ctrl+a d
to exit):
sudo -u minecraft screen -R minecraft
Make sure to keep a shapshot of the server folder in case the server gets corrupted or someone destroys your precious creation.
Create snapshot folder in /opt
:
sudo mkdir -p /opt/snapshot
Create hourly update script according to
snapshot-hourly
:
sudo nano /usr/local/bin/snapshot-hourly
Create daily update script according to snapshot-daily
:
sudo nano /usr/local/bin/snapshot-daily
Make scripts executable:
sudo chmod +x /usr/local/bin/snapshot-hourly
sudo chmod +x /usr/local/bin/snapshot-daily
Update crontab
according to crontab
:
sudo crontab -e
Test run hourly snapshot:
sudo /usr/local/bin/snapshot-hourly
tail /var/log/minecraft.log
Keep your software up to date, automatically.
Create update script according to update-server
:
sudo nano /usr/local/bin/update-server
Make script executable:
sudo chmod +x /usr/local/bin/update-server
Update crontab
according to crontab
:
sudo crontab -e
Test run:
sudo /usr/local/bin/update-server
tail /var/log/minecraft.log
systemctl status minecraft
If you prefer not to expose the Paper server to the network, use SSH tunneling.
Locally, set up a tunnel:
ssh -NL 25565:localhost:25565 192.168.X.X
You can now connect to the server using the address localhost
.
To allow others to connect, create a new system user:
sudo groupadd --system mctunnel
sudo useradd --system --gid mctunnel --shell /usr/sbin/nologin mctunnel
To allow public key logins, append the public key to authorized keys:
sudo mkdir /etc/ssh/authorized-keys
sudo touch /etc/ssh/authorized-keys/mctunnel
sudo chown mctunnel:mctunnel /etc/ssh/authorized-keys/mctunnel
sudo nano /etc/ssh/authorized-keys/mctunnel
Client-side, an SSH key can be generated and installed:
ssh-keygen -t ed25519
cat ~/.ssh/id_ed25519.pub
Update the SSH config according to
sshd_config-tunnel
, replacing X
:
sudo nano /etc/ssh/sshd_config
sudo systemctl restart ssh
Others can now set up a tunnel:
ssh -NL 25565:localhost:25565 mctunnel@192.168.X.X
Optionally, to allow password logins, set a password and update the SSH config
according to sshd_config-passwd
:
sudo passwd mctunnel
sudo nano /etc/ssh/sshd_config
If you use your minecraft server only intermittently, it might be best to keep minecraft ports closed by default. The following will auto-close the port at night.
Create close port script according to close-port
:
sudo nano /usr/local/bin/close-port
Make script executable:
sudo chmod +x /usr/local/bin/close-port
Update crontab
according to crontab
:
sudo crontab -e
Test script:
sudo /usr/local/bin/close-port
tail /var/log/minecraft.log
sudo ufw status
Open Minecraft port again:
sudo ufw allow 25565/tcp
sudo ufw allow 19132:19133/tcp
sudo ufw allow 19132:19133/udp
If you are running your server from home you might have a dynamic IP address and get locked out.
Create track ip script according to track-ip
, replacing X
with a unique url-safe base64 key between 11 and 22 characters:
sudo nano /usr/local/bin/track-ip
Make script executable:
sudo chmod +x /usr/local/bin/track-ip
Update crontab
according to crontab-minecraft
:
sudo -u minecraft crontab -e
Test script:
sudo -u minecraft /usr/local/bin/track-ip
tail /var/log/minecraft.log
Now, you can https://ip.leovandriel.com/X,
replacing X
.
In case of a calamity, or to test the snapshot.
NB: the following will overwrite your existing minecraft server folder. Make sure you have a backup before continuing.
First stop the server:
sudo systemctl stop minecraft
Extract the tarball, replacing X
:
sudo tar -C / -xvf /opt/snapshot/X.tar
sudo tar -C / -xzvf /opt/snapshot/X.tar.gz
Restart the server:
sudo systemctl start minecraft
systemctl status minecraft
Alternatively, if you have an older backup, and you only want to restore certain
files, e.g. the world map, you can first extract to /tmp
:
sudo tar -C /tmp -xvf /opt/snapshot/X.tar
sudo tar -C /tmp -xzvf /opt/snapshot/X.tar.gz
sudo mv /tmp/opt/minecraft/server/X /opt/minecraft/server
sudo rm -rf /tmp/opt/minecraft
Don't want to run the slow and bulky Minecraft Launcher?
On your client, install portablemc
and launch directly into server, replacing X
:
pip install --user portablemc
portablemc start --username X --server 192.168.X.X
Or if you prefer to keep it completely contained with one folder:
mkdir ~/minecraft
cd ~/minecraft
python3 -m venv venv
source ./venv/bin/activate
pip install --upgrade pip
pip install portablemc
deactivate
touch launch
chmod +x launch
nano launch
And paste the following, replacing X
:
#!/bin/bash
set -e
source ./venv/bin/activate
portablemc --main-dir ./main --work-dir ./work start --username X --server 192.168.X.X
And launch right into the server with ./launch
.
MIT