Hosting Minecraft on DigitalOcean

Courtesy Minecraft Facebook page

I’m a nerd. I admit it. I love tech. I love computers. I love games. And I love to code. So, it was obvious that my kids would absorb a little of that. Of course, games have come a long way since my day. But we love them all the same — old or new.

Then came along this strange little game of blocks called Minecraft. My boys gravitated toward it pretty quickly. And now we have 3+ accounts, and I’m sure billions of blocks have been mined and built by them. It amazes me what they can do with the game. In all honesty, I have no interest in playing it (or building in it), but I support their love for it nonetheless. So much so that I’m trying to get one of my old expired domains back just to recover one of our accounts.

Our boys have friends (Crazy, right?). And they like Minecraft too. So they’ve asked for a server to be stood up, so they can all enjoy the “world” together — without others coming around and “ruining” it. I had a very simplistic server stood up a while back for our boys, but they barely used it. However, knowing they’ve been playing Minecraft quite a bit lately, I decided to give in and create a new server for them. But I had a requirement this time — I wanted to automate the management of the server as much as I could. I also wanted to limit the amount of money I’d be forking over for this server.

This meant creating a system where the boys or I could turn the server on and off and destroy/create the virtual server on demand.

As I’ve written about in the past, I’ve been around the block when it comes to web hosting. My current host is DigitalOcean (or use my referral link). I’ve been extremely pleased with them. And with the requirement to limit the budget on this endeavor, I wanted to rely on the fact that DigitalOcean charges per hour of use of a virtual server instance (or Droplet, as they call them). That meant that I wouldn’t have to pay a flat monthly fee for a Droplet if they only use it for 10 days out of the month. And luck has it, DigitalOcean has an API I can rely on too. That meant I could shutdown, destroy, and recreate Droplets remotely. Excellent!

As part of the of automation, I also wanted to be able to update a domain DNS to point to the IP address of the new server instance too (sometimes when you recreate your Droplet, you get a new IP). That’s where my registrar, NameSilo (or use my referral link), comes into play. They have an API too!

So let’s dive in… this will be lengthy, so grab a coffee or soda… or beer!

Create a Droplet

Before we can start automating the system, we need to create a configuration with which we’ll be happy. So, let’s go to DigitalOcean and create a Droplet.

The biggest concern I had with DigitalOcean is the server specs. They are pretty up-front about their RAM specs, but CPU is another story. They keep the CPU allotment vague. Since the server probably won’t start off very popular, I figured a 1GB Droplet would suffice. Choose a starting point that makes sense to you. If we see the memory use getting high, we can always change this.

At the time of this writing, a 1GB Droplet runs $0.015 per hour. Want to go to 2GB? That will be $0.03 per hour. Knowing my kids won’t have this server running the entire month, that’s not a grand investment. If they do happen to max it out, it would be $10 for a month of 1GB or $20 for a month of 2GB. But that would only be if I was asleep for a month, and the boys left the server running. Note, that there are even higher spec Droplets and even a 512MB Droplet if you think you can live with that.

So, we create our DigitalOcean account, then we create a Droplet.

  • 1GB Droplet
  • Ubuntu 12.04 x64
  • No IO virtualization, private networking, or backups
  • And I chose one of the NYC data centers

In only a matter of minutes after clicking Create Droplet, the Droplet gets created and an email arrives in my mailbox. The email includes the IP address, username, and password to access our Droplet.

Now I won’t pretend to be a master system administrator, but here’s how I configured the server and got Minecraft server installed — Tekkit Classic in this case.

Configure Server

Since I’m stuck on Windows, I use PuTTY as my SSH client. Load it up, enter your credentials, and access the Droplet you just created. Use your SSH client of choice to do the same.

Once you have a connection, let’s change the default root password. Run:

passwd

Enter the default password and then your new password.

Now let’s create a new account, so we aren’t just relying on our root account. We’ll call it myadmin (change it if you like). Run:

adduser myadmin

Give it a password and any other info you desire.

Now we need to give this account admin rights. Run:

visudo

Look for your root account, and add this under it (if you picked a different name, change it here too):

myadmin ALL=(ALL:ALL) ALL

Save and close the file.

Now we will create our firewall rules. Run:

sudo iptables -F
sudo nano /etc/iptables.firewall.rules

In this file, add:

*filter
# Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT -d 127.0.0.0/8 -j REJECT
# Accept all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow all outbound traffic - you can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT
# Allow HTTP and HTTPS connections from anywhere (the normal ports for websites and SSL).
-A INPUT -p tcp --dport 80 -j ACCEPT
# Allow SSH connections
#
# The -dport number should be the same port number you set in sshd_config
#
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT
# Allow ping
-A INPUT -p icmp -j ACCEPT
# Log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
# Drop all other inbound - default deny unless explicitly allowed policy
-A INPUT -j DROP
-A FORWARD -j DROP
COMMIT

Save and close the file and then put it to work. Run:

sudo iptables-restore < /etc/iptables.firewall.rules

You can see how things look with this command:

sudo iptables -L

Now let's make the changes stick. Run:

sudo nano /etc/network/if-pre-up.d/firewall

Add this:

#!/bin/sh
/sbin/iptables-restore < /etc/iptables.firewall.rules

Save and close the file, then run:

sudo chmod +x /etc/network/if-pre-up.d/firewall

You don't have to, but I usually install Fail2Ban as well. Keeps the nasties away. Run:

sudo apt-get install fail2ban

Now let's update the Ubuntu goodies. Run:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade

I like to go ahead and give the system a reboot. This also let's me swap to the account we created, instead of using root. Run:

sudo reboot

Tired yet? I hope not. The good news is that our standard configuration of the server is done.

Install Java

Now we turn to the Minecraft specific stuff. First, we need to get Java installed.

Run:

sudo apt-get install python-software-properties
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer

If you find the need to uninstall it in the future, you can run:

sudo apt-get remove oracle-java7-installer
sudo add-apt-repository --remove ppa:webupd8team/java

Let's be sure Java is responding. Run:

java -version

It should be reporting as 1.7.x.

Install Tekkit Server (Minecraft)

Now that we have the server setup and Java installed, we can install the Minecraft sever. In this case, we are installing Tekkit Classic 3.1.2.

Run:

sudo mkdir /usr/local/tekkit-server

If we decide to delete Tekkit at any point, we'll be able to just delete the /usr/local/tekkit-server folder.

Let's create a user to run Tekkit for us. We'll call it tekkit-server (Note that the account is referenced in a few commands below and in the Startup Scripts section, so if you change it here, you'll have to change it in other places.). Run:

sudo adduser --system --no-create-home --home /usr/local/tekkit-server tekkit-server

If you ever need to delete the account, you can run:

sudo userdel tekkit-server

Now take over the folder with our new account. Run:

sudo chown -R tekkit-server /usr/local/tekkit-server

Run:

cd /usr/local/tekkit-server
sudo wget http://mirror.technicpack.net/files/Tekkit_Server_3.1.2.zip
sudo apt-get install unzip
sudo unzip Tekkit_Server_3.1.2.zip
sudo rm Tekkit_Server_3.1.2.zip

Let's install Screen for the virtualization of sessions.

sudo apt-get install screen

Almost there.

Let’s test

To test Screen and Tekkit Server, we can do the following - but you don't have to if you'd rather test the full configuration later on. Run:

screen -S minecraft

In the new session, run (you may want to play with the -Xmx and -Xms settings depending on your Droplet specs):

java -Xmx768M -Xms512M -jar /usr/local/tekkit-server/Tekkit.jar nogui

Once you are happy, kill it with Ctrl+C or whatever key combo works for you, and then run:

exit

You should be back in the original session - outside of Screen.

Create Startup Scripts

I want Tekkit to launch immediately upon boot up - especially when I move on to destroying and recreating our Droplets.

Run:

sudo nano /etc/init/tekkit-server.conf

Add the following (you may want to play with the -Xmx and -Xms settings depending on your Droplet specs):

# description "start and stop the minecraft-server"
chdir /usr/local/tekkit-server
exec su -s /bin/sh -c 'exec "$0" "$@"' tekkit-server -- /usr/bin/screen -DmS tekkit-server java -Xmx768M -Xms512M -jar /usr/local/tekkit-server/Tekkit.jar nogui > /dev/null
start on runlevel [2345]
stop on runlevel [^2345]

Save and close the file.

I like to clean up the permissions on our files. Run:

sudo chown tekkit-server:nogroup /usr/local/tekkit-server
sudo chmod g+s /usr/local/tekkit-server
sudo chown -R tekkit-server:nogroup /usr/local/tekkit-server/*
sudo chmod 2755 /usr/local/tekkit-server

Now let's try to start and stop it. Run:

sudo start tekkit-server
sudo stop tekkit-server

Hopefully those worked. If not, I hate to say it, but you may need to start over to see what you missed along the way. The good news is that DigitalOcean is only charging by the hour, so you can destroy your Droplet and start with a brand new one.

If it did work, great. Let's move on.

Tekkit Configuration

We are making great progress. Let's configure the Tekkit Server specific to our installation.

cd /usr/local/tekkit-server
sudo nano /usr/local/tekkit-server/server.properties

The configuration of server.properties is entirely up to you. I've included some default data. (Make note of what you choose as the server-port - in this case 24432.)

#My Minecraft Server properties
allow-nether=true
level-name=world
enable-query=false
allow-flight=false
server-port=24432
level-type=DEFAULT
enable-rcon=false
level-seed=Artomix #http://seedhunter.blogspot.com/2012/03/jungle-island.html
server-ip=
max-build-height=256
spawn-npcs=true
white-list=false
spawn-animals=true
online-mode=true
pvp=true
difficulty=3
gamemode=0
max-players=6
spawn-monsters=true
generate-structures=true
view-distance=10
motd=Welcome! Have fun!

Save and close the file.

Want to have server operators (admins)? If so, run:

sudo nano /usr/local/tekkit-server/ops.txt

Add Minecraft usernames - one per line. Then save and close the file.

Almost done!

Let's add Tekkit to the firewall rules. Remember that you should've made a note of the server-port earlier. We need it in the next few parts. I'll be using my sample port - 24432. Change it below if you changed it in the properties file.

Run:

sudo ufw allow 24432/tcp
sudo nano /etc/iptables.firewall.rules

Add this to the file:

-A INPUT -p tcp --dport 24432 -j ACCEPT

Refresh the firewall.

sudo service ufw restart
sudo iptables-restore < /etc/iptables.firewall.rules

Now reboot:

sudo reboot

Yeah!

Test It

When the server comes back up after the reboot, you should be able to test your Tekkit Server. Load Technic Launcher, choose Tekkit Classic, and try to connect to your server's IP address and the port you chose earlier.

Hope it works for you like it did for me.

If you just wanted a Tekkit Server (Minecraft) on a DigitalOcean Droplet, then you are done. However, as I stated before, I wanted more automation. I didn't want to shutdown a Droplet and then have to start all over.

Snapshots

I love the fact that DigitalOcean allows customers to create Snapshots of their Droplets. A Snapshot is exactly as it sounds - a copy of your server's configuration, ready to be deployed as a new Droplet (or to overwrite an existing Droplet). This makes our work incredibly easy.

Many folks could just rely on the DigitalOcean control panel to manage their Tekkit/Minecraft Server. When done playing, shut down your server, take a Snapshot, then destroy the server. When ready to play again, create a Droplet with your Snapshot and start playing. You don't even need to SSH into the server. It will auto-start Tekkit Server with all the settings you had before. It should even have your world as you left it.

All of that would have been fine for me, but I wanted my boys to be able to manage the server - all while not letting them screw up my web hosting server. So that meant I couldn't give them access to my DigitalOcean account. Plus, I wanted to make it easier for them.

Scripts

I was hoping there were already some amazing management scripts for DigitalOcean, but that didn't appear to be the case. The API is feature reach, but I guess folks keep their efforts hush hush.

I did run across some decent starts - one that looked simplistic enough for my needs was here. Of course, I needed more. So here is what I came up with.

Go grab an v1 API key from DigitalOcean:

Link: DigitalOcean v1 API

Now go grab my digitalocean-tekkit-manager repository from GitHub - noting the changes necessary for each file below.

Link: GitHub - digitalocean-tekkit-manager

Or you can save each file individually.

Go to the following link and save the code as index.php. This is the logon page. You could have your own logon system if you like. I recommend changing the $secretpasswordA password.

Link: GitHub - digitalocean-tekkit-manager - index.php

Go to the following link and save the code as index_minecraft.php in the same location as index.php. This is the menu page.

Link: GitHub - digitalocean-tekkit-manager - index_minecraft.php

Go to the following link and save the code as index_minecraft_stats.php in the same location as the others. This is just a stats page.

Link: GitHub - digitalocean-tekkit-manager - index_minecraft_stats.php

Go to the following link and save the code as bounce.php in the same location as the others. This page keeps us informed about the API events.

Link: GitHub - digitalocean-tekkit-manager - bounce.php

Go to the following link and save the code as common.php in the same location as the others. This page houses our variables and functions. Be sure to update the variables at the top of the code. These include your API ID and Key, your preferred Droplet name, size, and location, and your Minecraft port you decided on earlier.

Link: GitHub - digitalocean-tekkit-manager - common.php

That's it. Save those files and upload to your web host.

Access the logon page, log in, and then follow the instructions.

Wrap Up

Keep in mind that this is a work in progress. It is rough. The code is rough. I cranked it out quickly, so I didn't have to hover over the boys to make sure I wasn't paying for unused services. It works for us. And maybe I'll make more changes. Maybe not.

Maybe you have some ideas on how to improve it. I'm cool with that. Share!

And if you do decide to give this a shot on DigitalOcean, please use my referral link!

Be sure to keep your server up-to-date. Every once in a while, create the Droplet from your Snapshot, log into it via SSH, and run the update commands. Then shutdown the Droplet, take a new Snapshot, and destroy the Droplet. This will ensure you keep things patched.

Aside: I also have our system update NameSilo (my domain registrar) to reference each new Droplet's IP address. That saves us from having to add a new server in Minecraft every time DigitalOcean issues a new IP. I'll add that piece on here later. I'm tired.

Update July 16, 2014: Domain Management

This is entirely optional. As I mentioned before, I have an option that allows me to update the IP address of a domain I have through NameSilo. I just have a textbox on my menu page. I copy and paste the IP address from the list, and then click the Submit button. This auto-updates my subdomain's A record. This allows me to store the subdomain in my Minecraft client's server list instead of an IP address that may get changed. To add this feature to your scripts, do the following.

Go grab an API key from NameSilo:

Link: NameSilo API

Open index_minecraft.php, and before the closing body tag, add:

<p>May want to update a domain DNS with the new IP:
<ol>
<li>Update the DNS entry for <?=$namesilo_subdomain?>.<?=$namesilo_domain?> -
<?php
$domainid = getDomainID();
if ($domainid=="0") {
echo "domain ID not found";
}else{
echo "<form action=\"https://www.namesilo.com/api/dnsUpdateRecord\" method=\"get\" target=\"_blank\"><input type=\"hidden\" name=\"version\" value=\"1\" /><input type=\"hidden\" name=\"type\" value=\"xml\" /><input type=\"hidden\" name=\"key\" value=\"".$namesilo_apikey."\" /><input type=\"hidden\" name=\"domain\" value=\"".$namesilo_domain."\" /><input type=\"hidden\" name=\"rrhost\" value=\"".$namesilo_subdomain."\" /><input type=\"hidden\" name=\"rrttl\" value=\"7200\" /><input type=\"hidden\" name=\"rrid\" value=\"".$domainid."\" />Enter New IP: <input type=\"text\" name=\"rrvalue\" /> <input type=\"submit\" value=\"Submit\" /></form>";
}
?></li>
</ol>
</p>

Now, open common.php, and before the getDroplets function, add (update your API key, domain, and subdomain):

$namesilo_apikey = "***GET YOUR OWN***";
$namesilo_domain = "test.com"; //like test.com
$namesilo_subdomain = "minecraft"; //like minecraft, which would make minecraft.test.com
function getDomainID() {
global $namesilo_apikey, $namesilo_domain, $namesilo_subdomain;
$getDomainID = 0;
$thexml = file_get_contents("https://www.namesilo.com/api/dnsListRecords?version=1&type=xml&key=".$namesilo_apikey."&domain=".$namesilo_domain);
$data = simplexml_load_string($thexml);
if (isset($data->reply->code)) {
$eventstatus = $data->reply->code;
if ($eventstatus=="300") {
foreach($data->reply->resource_record as $mydata) {
$subdomainid=$mydata->record_id;
$subdomainhost=$mydata->host;
if ($subdomainhost==$namesilo_subdomain.".".$namesilo_domain) {
$getDomainID = $subdomainid;
}
}
}
}
return $getDomainID;
}

That should do it.

As I said before, this is optional. If you prefer, just copy the IP address from the list, and use it - and send it to your friends.

Enjoy!

Update: July 18, 2014: Essentials Plugin

Kids wanted more commands and features, so they requested that I add Bukkit Essentials to the server. Here's how.

First, I went to this page to find the latest link for Essentials 2.9.2. Look for the Download link and copy the URL.

Link: Bukkit Essentials 2.9.2 Download Page

Then I ran the following (Update the link for 2.9.2 if necessary):

sudo stop tekkit-server
cd /usr/local/tekkit-server
cd plugins
sudo wget http://dev.bukkit.org/media/files/599/892/Essentials.zip
sudo unzip Essentials.zip
sudo chmod +x Essentials*.jar
sudo chown -R tekkit-server:nogroup Essentials*.jar
sudo rm -rf Essentials.zip
sudo start tekkit-server

All set. Check out the Bukkit Essentials page for details on commands and other info.

COMMENTS

Since I’ve changed blog platforms a few times, some old comments can be found here.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.