Category Archives: Linux

Setting up a free Minecraft Server on Oracle Cloud

Update 2 months later

Somewhat unsurprisingly, given Oracle reputation, they disabled my supposedly always free resources two months later. Turns out, they disable the resources created while you were on trial. However, you can still make a clone of your boot volume, then terminate your previous instance, then recreate your instance from the cloned volume. It works so far.

In this tutorial, we’ll set up a free Minecraft server using a free tier Oracle Cloud.

Setting up an Oracle Free Tier

Signup for Oracle free account. Since this is Oracle, you probably want to check on the billing from time to time to make sure they didn’t start your changing for what they promised to be free.

Create a new compute instance. For max compatibility, we’ll use Ubuntu 18.04. You can try your luck with a newer version.

For the shape, select Ampere with 4 OCPU and 6GB Ram. This should still qualify for the free tier and should still be plenty for a Minecraft server.

Add your public SSH keys in the “Add SSH keys” section.

Create the instance.

After it’s created, go to the instance details, find “Primary VNIC” section, and open the subnet link (or create a new one).

Open Default Security List (or create a new one if one doesn’t exist yet)

Add Ingress Rules to open TCP/UDP ports 19132 for Bedrock and 25565 for Java edition (or both). Use CIDR for Source Type, for Source CIDR, 19132 for Destination port. Repeat for TCP. Repeat for 25565 if planning to use Java edition.

SSH to your server

Upgrade all packages:

sudo apt-get update
sudo apt-get upgrade

Let’s reset the firewall rules and open the ssh and Minecraft ports:

sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -F
sudo iptables-save
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 19132/udp
sudo ufw allow 19132/tcp
sudo ufw allow 25565/udp
sudo ufw allow 25565/tcp
sudo ufw enable
sudo ufw status

Optionally install zsh and vim:

sudo apt install zsh
sudo apt install vim


SSH to your server: ssh ubuntu@ip_address

We’ll use this script to setup the server:

curl | bash

Use the following commands to start/restart the service (you specified the service name when you ran the installation script):

sudo systemctl stop minecraft_service
sudo systemctl start minecraft_service
sudo systemctl restart minecraft_service

screen -R
# To disconnect (do not do ctrl-c or it may kill the minecraft service):

Java Edition

This section is only for Java edition. Don’t use it if you need the Bedrock version.

We’ll use this script to install the Java edition Paper server:

SSH to your server and run curl | bash. All default settings should be fine.

If you want Bedrock users to use your server, we can install Geyser plugin:

We’ll download the latest Geyser-Spigot server from

On the server run:

cd minecraft/plugins/
curl -O

If you also want Bedrock users to be able to login with their Microsoft account without requiring a separate Java account, we can also install a floodgate plugin:

curl -O

Restart the Minecraft server with sudo systemctl restart minecraft.service

DNS Records with Cloudflare

Add an A record for your server IP. For example, if you own and want to connect to your server using, then add an A record for mct pointing to your server IP.

Add 2 srv records for each port (19132 and 25565):

Use mct for Name, _minecraft for service, 0 for both Priority and Weight, UDP for protocol, for the target. mct is just the subdomain that you can change to whatever you want. Repeat for TCP and then for each port (19132 and 25565)

Checking/Cleaning Disk Space on Linux

Check the disk space (may need to install ncdu first):

sudo ncdu /

Clean up unused stuff:

sudo apt-get clean
sudo apt-get autoclean
sudo apt-get autoremove

clean: clean clears out the local repository of retrieved package files. It removes everything but the lock file from /var/cache/apt/archives/ and /var/cache/apt/archives/partial/. When APT is used as a dselect(1) method, clean is run automatically. Those who do not use dselect will likely want to run apt-get clean from time to time to free up disk space.

autoclean: Like clean, autoclean clears out the local repository of retrieved package files. The difference is that it only removes package files that can no longer be downloaded, and are largely useless. This allows a cache to be maintained over a long period without it growing out of control. The configuration option APT::Clean-Installed will prevent installed packages from being erased if it is set to off.

autoremove: is used to remove packages that were automatically installed to satisfy dependencies for some package and that are no more needed.

See a related question on askubuntu:

NGINX Subdomains

In the example below we serve index.html from /var/www/html/your_site directory when accessing “”; and we send all requests to local application server running locally on port 4000 when accessing

File: /etc/nginx/sites-enabled/default

server {
        listen 80;
        listen [::]:80;


        location / {
                root /var/www/html/your_site;
                try_files $uri /index.html;

server {
  listen 80;
  listen [::]:80;


  location / {
     proxy_redirect off;

Deploying React to Linux Server with Git Push

Selected VPS: Linode, 1GB Ram, 20 GB SSD, 1 TB transfer
OS: Ubuntu 17.04
Web Server: Ngnix
If you’d like to try Linode, I would greatly appreciate using this referral link – Linode: SSD Cloud Hosting & Linux Servers

Start with regular updates

apt-get update && apt-get upgrade

Set up fail2ban and Firewall

I’m installing fail2ban 0.10 since it supports ipv6. At the time of this post, it is not available as a regular package.

tar -xvzf 0.10.0.tar.gz
python3 install

#To enable fail2ban as an automatic service, copy the script for your distro from the files directory to /etc/init.d.

cp files/debian-initd /etc/init.d/fail2ban
update-rc.d fail2ban defaults
service fail2ban start

#Add local jail
awk '{ printf "# "; print; }' /etc/fail2ban/jail.conf | sudo tee /etc/fail2ban/jail.local
vim /etc/fail2ban/jail.local

uncomment sshd section and add
enabled = true

sudo apt-get install sendmail iptables-persistent
sudo service fail2ban start

Firewall ( allow established connections, traffic generated by the server itself, traffic destined for our SSH and web server ports. We will drop all other traffic):

sudo service fail2ban stop
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
sudo iptables -A INPUT -j DROP

# easy way to rate-limit ssh with ufw:
# technically, we could do all of the iptables stuff with ufw
ufw enable
ufw limit ssh

If using IPv6:

ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT # (replace with your undisclosed port)
ip6tables -A INPUT -p icmpv6 -j ACCEPT
ip6tables -A INPUT -j REJECT
ip6tables -A FORWARD -j REJECT

View iptables rules:

sudo iptables -S

Save iptables rules:

sudo dpkg-reconfigure iptables-persistent
sudo service fail2ban start


vim /etc/ssh/sshd_config

#Add or uncomment (if using Ubuntu < 17.04)
protocol 2

#Add allowed ciphers
Ciphers aes128-ctr,aes192-ctr,aes256-ctr
KexAlgorithms ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256
MACs hmac-sha2-256,hmac-sha2-512

Restart and test ssh config:

service sshd restart
#returns nothing if everything configured properly
sshd -t


sudo apt-get install software-properties-common
sudo add-apt-repository ppa:nginx/stable
sudo apt-get install nginx
service nginx status

Update /etc/nginx/sites-enabled/default

root /var/www/html/your_site;

location / {
# Some comments...
try_files $uri /index.html;   # ADD THIS

sudo service nginx restart

Installing React Dependencies

# install yarn
curl -sS | sudo apt-key add -
echo "deb stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn
#install node (apt-get repo has an older version of Node)
curl -sL | sudo -E bash -
sudo apt-get install -y nodejs
sudo apt-get install -y build-essential

GIT Push Deploy

Let’s set up git on the server

apt-get install git-core
mkdir repos && cd repos
mkdir your_site.git
cd your_site.git
git init --bare

Set up a post-push hook
cd /repos/your_app.git/hooks
touch post-receive

#!/bin/bash -l


yarn install
yarn build
rm -rf $PUBLIC_WWW/your_app_bup
mv $PUBLIC_WWW/your_app $PUBLIC_WWW/your_app_bup
cp -a build/. $PUBLIC_WWW/your_app

Run on post-receiv:

chmod +x post-receive

On your local machine:

git remote add linode root@remote_server_address:repos/your_app.git
git push linode master