Server Setup

These instructions are written under the assumption that you will use either DigitalOcean and Vultr for hosting, since they are the cheaper options for hosting a vps.

Create a New SSH Key

Either download and install putty, or download putty.exe or puttygen.exe standalone (if you opt for the latter then make sure that putty.exe isn't older than puttygen.exe). You can download putty here.

Open puttygen.

Generate a new key with the default setting of 2048-bit RSA.

Enter a passphrase then click on "Save Private Key".

You can access your public key at any time by opening the private key in puttygen (double click on the ppk file if you installed putty, or drag and drop onto puttygen.exe if using the puttygen.exe standalone).

Create a New DigitalOcean Droplet or Vultr Instance

Go to Create > Droplets in DigitalOcean or Deploy > Deploy New Server in Vultr.

Select the Shared CPU option ("Basic" in DigitalOcean, "Cloud Compute" in Vultr).

For the distro I am using Rocky Linux. Go for the highest version available.

I could be wrong but I’m pretty sure the majority of CS fans are from the US, so a US datacentre means those people get faster lookup. To that end the datacentre I chose was New York given that it is the most populated city in the US.

For the plan choose the 1GB ram + 1 AMD/Intel CPU + 25GB NVMe SSD. This option is only $6 or $7 per month as of writing.

It is cheaper to have backups disabled (Vultr has the option ticked by default), since you can just rebuild the server if anything goes badly wrong, but that's up to you.

Make sure IPv6 is enabled. This can be found under "Advanced Options" in DigitalOcean (this section is normally collapsed, so it is easy to miss) and under "Additional Features" in Vultr.

Choose the ssh key authentication option.

Click on "Add SSH Key" or "New SSH Key".

Copy and paste your ssh public key into this box and give the key a name.

Click on "Add SSH Key".

Enter your domain name as the hostname.

Point Domain to DigitalOcean/Vultr

The DigitalOcean nameservers are:
ns1.digitalocean.com
ns2.digitalocean.com
ns3.digitalocean.com

The Vultr nameservers are:
ns1.vultr.com
ns2.vultr.com

Keep in mind that if you cannot change the nameservers (for instance if you are using a subdomain and want to have the main domain pointing elsewhere) then you will need to configure dns records on the host that the nameservers are currently pointed to so they point to the ip address of the new server (for a subdomain just create a new A record pointing to said ip address).

Set Up DNS Records

Skip this section if you didn't repoint the nameservers.

Go to Create > Domains/DNS, Networking > Domains, or Network > DNS.

For Vultr click "Add Domain", enter the domain name, select your server, and click "Add".

For DigitalOcean enter your domain name and click"Add Domain", create an A record for your domain (a TTL of 3600 is ideal) and point them to the droplet IP address (click in the box where you enter the IP address and you should be given prefill options).

Include an AAAA record for the domain name pointing to the IPv6 address for the server/droplet.

Include a CNAME record for a www subdomain so we can do a www to no-www redirect later (unless you are using a subdomain).

Log in with SSH

Open putty.

In "Session" enter your server’s ip address and port number 22, and ensure that SSH is the connection type.

In Connection > SSH > Auth > Credentials select your private ssh key you saved earlier.

In "Session" enter a name into "Saved Sessions" and press "Save".

In future you can skip all of the above by selecting the session you saved and clicking "Load".

Now press "Open".

Agree to store the key fingerprint (if it asks).

We need to log in with username "root" and the passphrase you set when creating your ssh key.

To copy text in the putty terminal window first select some text and left-click on the selection. To paste text you need to right-click.

Enable SFTP and Change SSH Port Number

Update all already installed packages:

dnf update

Install nano because vim is not user friendly:

dnf install nano -y

From here on out any dummy information you need to substitute out will be marked in red.

Add our new sftp user (replace all instances of "soapuser" with your chosen username, please actually choose something different from what I wrote here so that people don't magically know your username just from reading this document):

groupadd soapuser
adduser soapuser --home /var/www --shell /sbin/nologin --gid soapuser
passwd soapuser

Install, start up, and configure the firewall to permit some basic services and set a new SSH port number (replace all instances of "1234" with a different port number in the 1024-65535 range):

dnf install firewalld -y
systemctl start firewalld
firewall-cmd --permanent --add-service=dns
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --remove-service=cockpit
firewall-cmd --permanent --add-port=1234/tcp
firewall-cmd --reload

Edit the SSH config:

nano /etc/ssh/sshd_config

Uncomment the "Port" setting and change it to our new port number:

Port 1234

Change the "Subsystem" setting to:

Subsystem sftp internal-sftp

Finally add the following to the end of the config file:

Match Group soapuser
ForceCommand internal-sftp
PasswordAuthentication yes
ChrootDirectory /var/www
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no

Press CTRL-X to exit and press Y to save changes.

Notify SELinux of the new port number:

semanage port -a -t ssh_port_t -p tcp 1234

Restart the SSH daemon to apply changes:

systemctl restart sshd

Close and reopen putty.

Click on the session you created earlier and press "Load".

Change the port number to your new ssh port number and press "Save".

Press "Open".

Agree to store the key fingerprint again (if it asks).

If anything goes wrong then you can use DigitalOcean’s recovery console.

Finally you should block SSH connections from port 22:

firewall-cmd --permanent --remove-service=ssh
firewall-cmd --reload

Setup NGINX

We will create some basic directories and assign them to the new user and group:

mkdir -p /var/www/soaprun/html
chown -R soapuser:soapuser /var/www/soaprun
chcon -R -t httpd_sys_rw_content_t /var/www/soaprun/html
chmod -R 755 /var/www

Now install and start up nginx:

dnf install nginx -y
systemctl start nginx

Set the owner and group for /var/www to root (so it can be accessed via SFTP):

chown root:root /var/www

Connect via SFTP

Download the Filezilla FTP Client here.

Install and open Filezilla on your computer.

Go to File > Site Manager.

Click on "New Site".

Give it a name.

Set the protocol to SFTP, the host to your droplet’s IP address, the port to your new SSH port number, the user to the sftp username you set, and the password you entered for that user account.

Click "Connect".

Upload Some Files

Create a new file on your computer called 000-soaprun.conf with the following contents (replace "example.org" with the actual domain for the server):

server {
        listen 80;
        listen [::]:80;
        server_name www.example.org;
        return 301 https://example.org$request_uri;
}
#server {
#        listen 443 ssl http2;
#        listen [::]:443 ssl http2;
#        server_name www.example.org;
#        return 301 https://example.org$request_uri;
#}
server {
        listen 80;
        listen [::]:80;
        server_name example.org;
        return 301 https://example.org$request_uri;
}
#server {
#        listen 443 ssl http2;
#        listen [::]:443 ssl http2;
#        server_name example.org;
#        root /var/www/soaprun/html/;
#        index index.html index.htm;
#        try_files $uri $uri/ =404;
#        autoindex off;
#        server_tokens off;
#}

Upload 000-soaprun.conf to /soaprun in Filezilla.

Return to the putty terminal window and change the permissions for the files you uploaded:

chmod -R 755 /var/www/soaprun/000-soaprun.conf
chown -R root:root /var/www/soaprun/000-soaprun.conf

Now move said files:

mv /var/www/soaprun/000-soaprun.conf /etc/nginx/conf.d

Restart NGINX:

systemctl restart nginx

Add Swap

You do not need to do this on Vultr, since they allocate swap for you when creating the server.

fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

Set Up Lets Encrypt

Install certbot:

dnf install epel-release -y
dnf install certbot python3-certbot-nginx -y

We need to request SSL certificates.

If you set up a dns record for a www subdomain then use this command:

certbot --nginx --no-redirect -d example.org -d www.example.org

...otherwise use this command instead:

certbot --nginx --no-redirect -d example.org

If the certificate request fails then the DNS changes from earlier haven’t propagated to Lets Encrypt’s ISP. Wait a while then try again.

We now need to add certificate renewal to cron.

Edit the global crontab file:

nano /etc/crontab

Add this line to the bottom of the file:

0 0,12 * * * root python3 -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q

Press CTRL-X to exit and press Y to save changes.

Final NGINX Configuration

Edit 000-soaprun.conf:

nano /etc/nginx/conf.d/000-soaprun.conf

In this file are 4 server blocks, and 2 are commented out. As in the lines start with a hash. So you need to go through and remove the hash from the start of those lines.

For the two server blocks that start with "listen 80;" you need to remove this line (you can remove lines by using CTRL-K):

listen 443 ssl; # managed by Certbot

Now you need to move the "managed by Certbot" lines from the "listen 80;" server blocks to the "listen 443 ssl http2;" server blocks, just below the line starting with server_name.

Remember that in putty you can copy text by selecting it and then left-clicking on the selection, and you can paste using right-click.

To put this into context 000-soaprun.conf should look something like this at the start:

server {
        listen 80;
        listen [::]:80;
        server_name www.example.org;
        return 301 https://example.org$request_uri;

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
#server {
#        listen 443 ssl http2;
#        listen [::]:443 ssl http2;
#        server_name www.example.org;
#        return 301 https://example.org$request_uri;
#}
server {
        listen 80;
        listen [::]:80;
        server_name example.org;
        return 301 https://example.org$request_uri;

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
#server {
#        listen 443 ssl http2;
#        listen [::]:443 ssl http2;
#        server_name example.org;
#        root /var/www/soaprun/html/;
#        index index.html index.htm;
#        try_files $uri $uri/ =404;
#        autoindex off;
#        server_tokens off;
#}

...and something like this at the end:

server {
        listen 80;
        listen [::]:80;
        server_name www.example.org;
        return 301 https://example.org$request_uri;
}
server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name www.example.org;
    ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
        return 301 https://example.org$request_uri;
}
server {
        listen 80;
        listen [::]:80;
        server_name example.org;
        return 301 https://example.org$request_uri;
}
server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name example.org;
    ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
        root /var/www/soaprun/html/;
        index index.html index.htm;
        try_files $uri $uri/ =404;
        autoindex off;
        server_tokens off;
}

Press CTRL-X to exit and press Y to save changes.

Restart NGINX (Again):

systemctl restart nginx

Install Rust

Install some dependencies:

dnf install cmake gcc make curl clang -y

Install Rust itself:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Add Rust to PATH:

source "$HOME/.cargo/env"

Build Soapdispenser

cd ~
dnf install git -y
git clone https://github.com/CaveStoryModdingCommunity/soapdispenser.git
cd ~/soapdispenser
cargo build --release

Configure Soapdispenser

Edit the config file:

nano ~/soapdispenser/config.json

Find this line:

"address": "127.0.0.1:1002"

You need to replace the ip address with your server ip and the port you wish to use for soaprun communications (replace all instances of "6789" in these instructions with a different port number in the 1024-32767 range, and all instances of "123.123.123.123" with your server's ip address).

Change room_directory, entity_path, and attributes_path so they are absolute paths by adding "/root/soapdispenser/" to the beginning (don't use the tilde shorthand in here).

So something like this:

{
        "room_verification_bounds": "InBounds",
        "room_verification_mode": "TileTypes",
    "room_directory": "/root/soapdispenser/recreations/2010_11_13",
        "entity_path": "/root/soapdispenser/recreations/2010_11_13/entities.json",
        "attributes_path": "/root/soapdispenser/recreations/map.attributes",
        "max_player_movement_nodes_per_packet": 4,
        "max_player_distance_per_movement_node": 20,
        "max_player_distance_per_packet": 20,
        "max_players": 64,
        "address": "123.123.123.123:6789"
}

Add the port to the firewall:

firewall-cmd --permanent --add-port=6789/tcp
firewall-cmd --reload

You can create additional configurations (and by extension, different maps) on the same server, but they much be configured to different ports.

Start Soapdispenser

~/soapdispenser/target/release/soapdispenser -c /root/soapdispenser/config.json &

The ampersand at the end will start Soapdispenser as a background process, but if you want it to be limited to your current session then omit it as follows:

~/soapdispenser/target/release/soapdispenser -c /root/soapdispenser/config.json

Create and Upload Some More Files

Create a new file called server.html and give it the following contents (replace all instances of "<tab>" with a tab character and make sure this file has only 4 lines):

<html><body>
Pixel<br>
November 13, 2010<tab>open<tab>123.123.123.123<tab>6789<tab>Soaprun<tab>64<tab>.<tab><br>
</body></html>

Optionally create a file called index.html and make a landing page for your domain with instructions on how to connect.

Log in using sftp via Filezilla again.

Upload index.html and server.html to /soaprun/html in Filezilla.

Stop Soapdispenser

If you ever need to kill a soapdispenser process then run the following command to find the pid of said process:

ps aux | grep soapdispenser

The output should have the user, followed by the pid, and at the end you will see the command (including all arguments).

Now kill said process (replace "654321" with the pid you located with ps aux):

kill -9 654321