Applies to Ubuntu 18.xx-20.xx
Introduction to Hosting

In this tutorial you will be learning some of the very basics of hosting network services. You may be wanting to host a website, a game server, an email server – literally anything! Use this knowledge so you can better understand what is going on when you host a service on a server or computer and most important how to go about different issues you may come across when setting up services.

Lets go over some basic requirements for this tutorial. This time around we are going to make it a bit fun by hosting a Minecraft Server!

Requirements:

Setting up any service typically has the same process as such:

  • Setup Server/Platform
  • Install Service
  • Configure Service
  • Configure Networking
  • Configure Security
  • Test

We are going to assume that you already have your server/platform setup and ready to go for installing your service.

Install and Setup Service

First and foremost we will setup the service and make sure it runs correctly without errors.

1. Lets update our repositories and install the required packages to run our Spigot Minecraft server.

Normally for any service that you want to setup, there will always be a list of prerequisites to run the service that need to be installed. In the case of Spigot, all we need is Java 1.8.

So first we update.

sudo apt update

Now we install Java 8.

sudo apt install openjdk-8-jdk wget -y

2. Download Spigot Minecraft Server into your machine using wget.

We will be creating a directory for keeping the Minecraft server files in /opt/minecraft.

So lets create /opt/minecraft.

sudo mkdir /opt/minecraft

Then we download Spigot into our new directory where we will run the Spigot Minecraft server from.

cd /opt/minecraft; sudo wget https://cdn.getbukkit.org/spigot/spigot-1.16.4.jar

3. We will now first create a user and group for whom the Spigot server will run as.

It is important to know that you don’t and should not run everything as root if you don’t need to. If an exploit is found in a service, especially third party and you’re running the service as root, then you run the risk of the exploit gaining root access.


Here because we will be running the service as a user with limited access, even if an exploit is found to gain local user access, the exploit can’t do much outside of the files the user owns or has access to.

sudo useradd minecraft

Hint: useradd creates both the user and group.

4. Now lets give our new user ownership over /opt/minecraft.

sudo chown minecraft:minecraft -R /opt/minecraft

5. Lets run Spigot for the first time to generate and accept the EULA txt file as minecraft.

sudo -u minecraft java -jar spigot-1.16.4.jar

Notice how we ran the above command prefixing it with sudo -u minecraft. This will execute the following command as the user specified after the -u parameter.


The server will stop itself bringing you back to the linux shell which we will then accept the eula using sed or you can edit the txt file using your favorite text editor.

sudo -u minecraft sed -i 's/false/true/' eula.txt

6. Execute the Spigot server once again to create all the necessary files for the server to run.

sudo -u minecraft java -jar spigot-1.16.4.jar

After a successful launch, the console should look like this once its done loading.

[...]
[17:02:38] [Server thread/INFO]: Time elapsed: 1155 ms
[17:02:38] [Server thread/INFO]: Done (34.316s)! For help, type "help"

After you verified it launched successfully, stop the server and you will return to the linux shell.

[...]
17:02:38] [Server thread/INFO]: Time elapsed: 1155 ms
[17:02:38] [Server thread/INFO]: Done (34.316s)! For help, type "help"
>stop

7. Next we will be setting up Minecraft to launch with SystemD.

When it comes to hosting it is important to have services launch at startup opposed to manually running services after startup. To do this, we setup our service as a SystemD unit that we will enable at startup.


Luckily the Minecraft Wiki provides a template for setting up the server with SystemD which we will use.


Copy and save the template as root to /etc/systemd/system/minecraft.service then we will reload SystemD.

# Source: https://github.com/agowa338/MinecraftSystemdUnit/
# License: MIT
[Unit]
Description=Minecraft Server %i
After=network.target

[Service]
WorkingDirectory=/opt/minecraft/%i
PrivateUsers=true
# Users Database is not available for within the unit, only root and minecraft is available, everybody else is nobody
User=minecraft
Group=minecraft
ProtectSystem=full
# Read only mapping of /usr /boot and /etc
ProtectHome=true
# /home, /root and /run/user seem to be empty from within the unit. It is recommended to enable this setting for all long-running services (in particular network-facing ones).
ProtectKernelTunables=true
# /proc/sys, /sys, /proc/sysrq-trigger, /proc/latency_stats, /proc/acpi, /proc/timer_stats, /proc/fs and /proc/irq will be read-only within the unit. It is recommended to turn this on for most services.
# Implies MountFlags=slave
ProtectKernelModules=true
# Block module system calls, also /usr/lib/modules. It is recommended to turn this on for most services that do not need special file systems or extra kernel modules to work
# Implies NoNewPrivileges=yes
ProtectControlGroups=true
# It is hence recommended to turn this on for most services.
# Implies MountAPIVFS=yes

ExecStart=/bin/sh -c '/usr/bin/screen -DmS mc-%i /usr/bin/java -server -Xms512M -Xmx2048M -XX:+UseG1GC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar $(ls -v | grep -i "FTBServer.*jar\|minecraft_server.*jar" | head -n 1) nogui'

ExecReload=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "reload"\\015'

ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN. Saving map..."\\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "save-all"\\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "stop"\\015'
ExecStop=/bin/sleep 10

Restart=on-failure
RestartSec=60s

[Install]
WantedBy=multi-user.target

Important things to note.


Notice in the template it lists which user and group as well as working directory where the service will run as. As we did before, we created the user and group minecraft for this reason.

Small Changes

a. If you are using a different directory for the Minecraft Server, replace WorkingDirectory with the directory of your choice.

b. On ExecStart, replace the section that says:
"FTBServer.*jar\|minecraft_server.*jar"
with just the jar executable name. In my case, i kept the name spigot-1.16.4.jar.

So my updated minecraft.service will look like below:

# Source: https://github.com/agowa338/MinecraftSystemdUnit/
# License: MIT
[Unit]
Description=Minecraft Server %i
After=network.target

[Service]
WorkingDirectory=/opt/minecraft/%i
PrivateUsers=true
# Users Database is not available for within the unit, only root and minecraft is available, everybody else is nobody
User=minecraft
Group=minecraft
ProtectSystem=full
# Read only mapping of /usr /boot and /etc
ProtectHome=true
# /home, /root and /run/user seem to be empty from within the unit. It is recommended to enable this setting for all long-running services (in particular network-facing ones).
ProtectKernelTunables=true
# /proc/sys, /sys, /proc/sysrq-trigger, /proc/latency_stats, /proc/acpi, /proc/timer_stats, /proc/fs and /proc/irq will be read-only within the unit. It is recommended to turn this on for most services.
# Implies MountFlags=slave
ProtectKernelModules=true
# Block module system calls, also /usr/lib/modules. It is recommended to turn this on for most services that do not need special file systems or extra kernel modules to work
# Implies NoNewPrivileges=yes
ProtectControlGroups=true
# It is hence recommended to turn this on for most services.
# Implies MountAPIVFS=yes

ExecStart=/bin/sh -c '/usr/bin/screen -DmS mc-%i /usr/bin/java -server -Xms512M -Xmx2048M -XX:+UseG1GC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar $(ls -v | grep -i "spigot-1.16.4.jar" | head -n 1) nogui'

ExecReload=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "reload"\\015'

ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN. Saving map..."\\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "save-all"\\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "stop"\\015'
ExecStop=/bin/sleep 10

Restart=on-failure
RestartSec=60s

[Install]
WantedBy=multi-user.target

Once you have your changes saved, we will now reload SystemD and enable our service at startup.

sudo systemctl daemon-reload; sudo systemctl enable minecraft.service

Now we start the service and make sure it starts up with no issues.

sudo systemctl start minecraft.service

Notice how with SystemD we did not start the service using sudo -u minecraft like we did previously.


This is because before we executed the spigot jar directly from the CLI where as now our minecraft.service is setup to run as user and group minecraft for us.


Now lets verify that the server started correctly. The service will take roughly 60 seconds to startup. After about a minute has passed, run the command below.

sudo systemctl status minecraft.service

If everything went well, the status should look something like this.

● minecraft.service - Minecraft Server
  Loaded: loaded (/etc/systemd/system/minecraft.service; enabled; vendor preset: enabled)
  <strong>Active: active (running)</strong> since Thu 2020-12-17 19:45:12 UTC; 4min 11s ago
Main PID: 8525 (sh)
  Tasks: 30 (limit: 4659)
  CGroup: /system.slice/minecraft.service
      ├─8525 /bin/sh -c /usr/bin/screen -DmS mc- /usr/bin/java -server -Xms512M -Xmx2048M -XX:+UseG1GC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -ja
      ├─8542 /usr/bin/SCREEN -DmS mc- /usr/bin/java -server -Xms512M -Xmx2048M -XX:+UseG1GC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar spigot-1.
      └─8543 /usr/bin/java -server -Xms512M -Xmx2048M -XX:+UseG1GC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar spigot-1.16.4.jar nogui

Dec 17 19:45:12 mailtrain systemd[1]: Started Minecraft Server .

Notice how our service is enabled which means it will execute on startup.

8. Finally, we will create a restart script for when the Minecraft server is restarted either manually, due to a crash or plugin trigger.

Within the root directory of our Spigot Minecraft server, in my case /opt/minecraft, we will create a file called start.sh. The contents of this file will just be the SystemD command to start the minecraft.service unit.

#!/bin/bash
systemctl start minecraft.service

Then we mark it as executable.

sudo chmod +x /opt/minecraft/start.sh
Setup Networking & Security

We are going to go over some important information regarding the networking aspect of services and how they listen for connections on the server’s interfaces.


Lets go over the 3 types of IP Address configurations and their uses:

  • Localhost: 127.0.0.1
  • Static Address: 192.168.0.165
  • Any: 0.0.0.0
Localhost

Configuring your service using the localhost address will mean that only the host can connect to that service. So if we are running a MySQL service on the host ubnt1.test.com, that means only ubnt1.test.com can connect to the MySQL service. This configuration is great to limit who can connect to your service and avoid attacks on that service.


A real life example would be a standalone LAMP (Linux, Apache, MySQL, PHP/PERL/Python) server. Since the only host that needs to access the MySQL service is the LAMP server itself, there is literally no reason for MySQL to listen on any public facing interface. So in this case, configuring MySQL to listen on 127.0.0.1 is appropriate.

Static Address

Configuring your service by defining an address will mean that any client that connects to that specific address can connect to your host.


For example, if we have host ubnt1.test.com with 2 network interfaces:

  • Interface 1: 192.168.20.20
  • Interface 2: 192.168.30.30

And you configure your service to listen on 192.168.20.20. Then any client can connect to your host only through 192.168.20.20. Any attempt to connect through 192.168.30.30 will fail because the service is bound to a single address.


This is great if you have a server that is connected to multiple networks but only want one of the networks to have access to that service or you prefer to route the traffic of that service through a specific interface/address.


An important thing to note is if you have a server using DHCP (Dynamic Host Configuration Protocol) and you configure your service to listen on the IP Address it has been assigned. At some point the IP Address will change and the service will go down for clients because the bound address has changed. This is why it is important to setup static addressing on your server interfaces opposed to DHCP.

Any

Configuring your service using the any address will mean that any client can connect to your service from any address on the host.


So unlike Static Address, a client can connect to either 192.168.20.20192.168.30.30, or even 127.0.0.1 (localhost).


This type of configuration is fine if you want your service to be open to anyone with no restrictions.

1. Lets check our server.properties file to see what address the Minecraft server is setup to listen on.

By default, Spigot will listen on all addresses on the host. So our server.properties will look like this on line server-ip=:

[...]
server-ip=
[...]

As explained before, if you want the server to listen on a specific address you can configure that address on this line.

Any changes made to this file, you will have to restart the minecraft.service unit.

sudo systemctl restart minecraft.service

2. Lets move onto enabling the Ubuntu firewall UFW (Uncomplicated Firewall).

By default, Ubuntu has the firewall disabled but we will enable it and explain different scenarios for our firewall configuration.

Lets enable the firewall now.

sudo ufw enable

Note: If you are connected to your machine via SSH and enable the firewall, you will lose connection. To avoid this, first add a rule to allow SSH connections before enabling the firewall.

sudo ufw allow in 22/tcp

3. Now we will configure our firewall rules to allow specific ports for the host to listen on.

A simple configuration would be to either allow all hosts or select hosts to connect to the service. Similarly to the interface configuration explained at the start of this section but we will be controlling it through the firewall opposed to the configuration. Configuring these rules through the firewall tends to be more flexible opposed to binding the service to an interface/IP Address.

We will go over what these 2 scenarios would look like for the Minecraft Server.

First and foremost, lets find out what ports we need to configure our firewall rules for. We can find out this information in 2 ways. Either check the server.properties file or run the following command:

sudo ss -ltnp
  • -l: Show listening
  • -t: Show TCP
  • -n: Show ports instead of service names
  • -p: Show process info of socket connection

This should render the following output:

State          Recv-Q       Send-Q                   Local Address:Port                  Peer Address:Port                                       
LISTEN         0            128                      127.0.0.53%lo:53                    0.0.0.0:*            users:(("systemd-resolve",pid=1012,fd=13))         
LISTEN         0            128                      0.0.0.0:22                          0.0.0.0:*            users:(("sshd",pid=1697,fd=3))               
LISTEN         0            128                      [::]:22                             [::]:*               users:(("sshd",pid=1697,fd=4))               
LISTEN         0            128                      *:25565                             *:*                  users:(("java",pid=8543,fd=43))

As you can see, the last line is being used by Java with the PID of 8543 with port 25565 which is the Spigot server. In the event that you are running multiple java applications, we can compare this PID to what the SystemD service says.

We can check and compare PIDs by checking the status of the Minecraft server again:

sudo systemctl status minecraft.service

Which gives us the output of:

● minecraft.service - Minecraft Server
  Loaded: loaded (/etc/systemd/system/minecraft.service; enabled; vendor preset: enabled)
  Active: active (running) since Thu 2020-12-17 19:45:12 UTC; 2h 42min ago
Main PID: 8525 (sh)
  Tasks: 30 (limit: 4659)
  CGroup: /system.slice/minecraft.service
      ├─8525 /bin/sh -c /usr/bin/screen -DmS mc- /usr/bin/java -server -Xms512M -Xmx2048M -XX:+UseG1GC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -ja
      ├─8542 /usr/bin/SCREEN -DmS mc- /usr/bin/java -server -Xms512M -Xmx2048M -XX:+UseG1GC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar spigot-1.
      └─8543 /usr/bin/java -server -Xms512M -Xmx2048M -XX:+UseG1GC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar spigot-1.16.4.jar nogui

Dec 17 19:45:12 mailtrain systemd[1]: Started Minecraft Server .

And as you can see, the PID from the previous output matches one of the PIDs being used by minecraft.service. So we can now confirm port 25565 is the port we need to allow through the firewall.

Allow all

In most circumstances you would be allowing all traffic to your service especially if it is a public service with no restrictions needed.

To allow all traffic for port 25565/tcp we will run the below command. This will add a rule for both IPv4 and IPv6 connections.

sudo ufw allow in 25565/tcp

And lets verify the rule is active.

sudo ufw status

We then get this result:

Status: active

To               Action   From
--               ------   ----
22/tcp           ALLOW    Anywhere         
25565/tcp        ALLOW    Anywhere         
22/tcp (v6)      ALLOW    Anywhere (v6)       
25565/tcp (v6)   ALLOW    Anywhere (v6)
Allow by Source

Allowing traffic by source is as mentioned before a more flexible method for controlling traffic than binding your service to an address. This is great for scenarios where you may need to make a service public to allow a remote host to access data and want only that host or network to access that data. We will go over 2 types or rules that we can use to make this possible.

First we will look at allowing a single host. We will be allowing only host 10.10.10.10 to access our Minecraft Server.

sudo ufw allow from 10.10.10.10/32 to any port 25565 proto tcp

Now we will verify the rule by running sudo ufw status.

Status: active

To               Action   From
--               ------   ----
22/tcp           ALLOW    Anywhere      
25565/tcp        ALLOW    10.10.10.10
22/tcp (v6)      ALLOW    Anywhere (v6)

Now the only host that can access the server is 10.10.10.10.

Second we will look at allowing a subnet/network to access our Minecraft Server. In this rule, instead of allowing only host 10.10.10.10, we will allow the entire subnet.

sudo ufw allow from 10.10.10.0/24 to any port 25565 proto tcp

Verify the rule by running sudo ufw status.

Status: active

To               Action   From
--               ------   ----
22/tcp           ALLOW    Anywhere      
25565/tcp        ALLOW    10.10.10.0/24
22/tcp (v6)      ALLOW    Anywhere (v6)

Now the whole 10.10.10.0 network can access the server.

Test

Now comes the moment of truth where we test connectivity to our service or in this case, our Minecraft server.

1. Lets simply open our Minecraft client and add our minecraft server to the list of servers and see if it can reach it.

In my network, the server address will be 192.168.0.168.

Testing Minecraft Server
Testing Minecraft Server

Looks like the Minecraft server is running successfully!

If you happen to be an owner of a Minecraft server, there is a new platform of mine for advertising your server!
Feel free to check it out! – Minecraft List


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *