Setup Full IOTA Node on Centos 7

IOTA is all the craze now. Even though there is lots of noise going on the project itself is very interesting. For developing purposes you most likely want to setup your own IOTA node. Here are the setup instructions for Centos 7.

I assume you have already installed a Centos 7 image on your VPS. I used Linode 4GB which costs $20 per month. I have been their client for the last nine years. The link above is an affiliate link. If you buy something it makes me a happy puppy.

Heads up! This is not meant for people with zero technical backround. These instructions follow some best practices which makes the install bit more complicated but result in a reasonably secure install.
Wrong OS? Iota Parners has excellent Ubuntu installation instructions.

Software Update and Basic Firewall

Login as root to the freshly created VPS. First task is to apply the latest software updates and setup basic firewall. You should not keep freshly installed server in the open internet. Even after few minutes you can already see automated scripts trying to break in.

$ ssh [email protected]
# yum update

When sofware update finishes enable the firewall.

# systemctl start firewalld
# systemctl enable firewalld

Centos 7 already has predefined secure zone called dmz which enables only ssh access. Set the dmz as the default zone on et eth0 network interface.

# firewall-cmd --set-default-zone=dmz
# firewall-cmd --zone=dmz --add-interface=eth0
# firewall-cmd --zone=dmz --list-all

Output from the last command should be like following.

dmz (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

Create a Second User Account

It is generally a bad practice do any operations as root. Instead you should create and use a separate user account. This user account should be given access to sudo by adding the user to the wheel group. Remember to use strong password.

# useradd --comment "Foo Bar" --home /home/foobar --shell /usr/bin/bash foobar
# usermod --append --groups wheel foobar
# passwd foobar

After creating your own user logout and relogin with the new user.

# logout
$ ssh [email protected]

Create IRI User

Now we are in the main part. First create user for iri. This is not normal user and should not have access to shell. Note that since we are no longer logged in as root commands should be prefixed with sudo.

$ sudo useradd --comment "IRI" --home /opt/iri  --shell /sbin/nologin iri

You can check the new user info with finger.

$ sudo yum install finger
$ finger iri
finger iri
Login: iri                              Name: IRI
Directory: /opt/iri                     Shell: /sbin/nologin
Never logged in.
No mail.
No Plan.

Install Java

Current IRI implementation is written in Java. To save some resources you can ignore all X11 crud and install the headless version.

$ sudo yum install java-1.8.0-openjdk-headless
$ java -version
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)

Install IRI

To install IRI you have two options. You can clone, compile and package the code from Git yourself. Or you can simply use the precompiled release. Latter makes more sense unless you have a technical curiocity to do the compilation yourself.

Download the latest version and move it into /opt/iri folder. We also make a symlink to a shorter name of iri.jar. By using a symlink there is no need to change startup scripts when new version of IRI is released.

$ sudo yum install wget
$ wget https://github.com/iotaledger/iri/releases/download/v1.4.1.4/iri-1.4.1.4.jar
$ sudo mv iri-1.4.1.4.jar /opt/iri
$ sudo ln -s /opt/iri/iri-1.4.1.4.jar /opt/iri/iri.jar

With everything installed create a config file for IRI. You could use systemd environment variables but in this case I find it easier to keep everything in one folder.

$ sudo nano -w /opt/iri/iri.ini

Copy paste the following into the editor. Full paths are used for IXI_DIR and DB_PATH to make sure IRI does not get confused even if current working directory is something else than /opt/iri. Press ctlr-x to save and exit.

[IRI]
PORT = 14265
UDP_RECEIVER_PORT = 14600
TCP_RECEIVER_PORT = 15600
NEIGHBORS =
IXI_DIR = /opt/iri/ixi
DB_PATH = /opt/iri/mainnetdb
HEADLESS = true

Next make sure all files and folders have correct permissions.

$ sudo chown -R iri:iri /opt/iri
$ sudo chmod 700 /opt/iri

Now is a good time to to temporarily start IRI to make sure everything is ok.

sudo -u iri java -jar /opt/iri/iri.jar --config /opt/iri/iri.ini

This will start IRI on the foreground. Use another shell window to try access the API.

$ curl http://localhost:14265 \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'X-IOTA-API-Version: 1' \
  --data '{"command": "getNodeInfo"}' \
  --include

You should see something like following.

HTTP/1.1 200 OK
Connection: keep-alive
Access-Control-Allow-Origin: *
Keep-Alive: timeout=500, max=100
Content-Type: application/json
Content-Length: 569
Date: Fri, 15 Dec 2017 13:22:46 GMT

{"appName":"IRI","appVersion":"1.4.1.2","jreAvailableProcessors":2,"jreFreeMemory":121209760,"jreVersion":"1.8.0_151","jreMaxMemory":921174016,"jreTotalMemory":859832320,"latestMilestone":"WYDPKQDICXMTYSCRLHAPGLDWQF9UUYCTNPIZGHMHPDNLRFNWWRVXQZJEHEPYXBFPDZBGNNYQQWPSA9999","latestMilestoneIndex":303782,"latestSolidSubtangleMilestone":"WYDPKQDICXMTYSCRLHAPGLDWQF9UUYCTNPIZGHMHPDNLRFNWWRVXQZJEHEPYXBFPDZBGNNYQQWPSA9999","latestSolidSubtangleMilestoneIndex":303782,"neighbors":4,"packetsQueueSize":0,"time":1513344166373,"tips":5010,"transactionsToRequest":2,"duration":0}

Before continuing press ctrl-c to exit IRI in the first window.

Automatic Startup

You most likely want IRI to start automagically on reboot. Centos 7 uses SystemD for this. Create a startup file for IRI.

$ sudo nano -w /usr/lib/systemd/system/iri.service

Copy paste the following into the editor. Press ctrl-x to save and exit.

[Unit]
Description=IRI Full Node
After=network.target

[Service]
Type=simple
WorkingDirectory=/opt/iri
ExecStart=/usr/bin/java -jar /opt/iri/iri.jar --config /opt/iri/iri.ini
Restart=on-failure
RestartSec=10s
TimeoutStopSec=30s
User=iri

[Install]
WantedBy=multi-user.target

After creating the startup file SystemD needs to be reloaded. Then we can enable and start IRI.

$ sudo systemctl daemon-reload
$ sudo systemctl enable iri.service
$ sudo systemctl start iri.service

Make sure IRI is active and running.

$ sudo systemctl status iri
● iri.service - IRI Full Node
   Loaded: loaded (/usr/lib/systemd/system/iri.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2017-12-14 15:02:28 UTC; 16s ago
 Main PID: 16390 (java)
   CGroup: /system.slice/iri.service
           └─16390 /usr/bin/java -jar /opt/iri/iri.jar --config /opt/iri/iri....

Dec 14 15:02:34 li869-90.members.linode.com java[16390]: 12/14 15:02:34.542 [...
Dec 14 15:02:34 li869-90.members.linode.com java[16390]: 12/14 15:02:34.545 [...
Dec 14 15:02:34 li869-90.members.linode.com java[16390]: 12/14 15:02:34.549 [...
Dec 14 15:02:34 li869-90.members.linode.com java[16390]: 12/14 15:02:34.551 [...
Dec 14 15:02:34 li869-90.members.linode.com java[16390]: 12/14 15:02:34.551 [...
Dec 14 15:02:34 li869-90.members.linode.com java[16390]: 12/14 15:02:34.552 [...
Dec 14 15:02:34 li869-90.members.linode.com java[16390]: 12/14 15:02:34.555 [...
Dec 14 15:02:34 li869-90.members.linode.com java[16390]: 12/14 15:02:34.561 [...
Dec 14 15:02:34 li869-90.members.linode.com java[16390]: 12/14 15:02:34.771 [...
Dec 14 15:02:44 li869-90.members.linode.com java[16390]: 12/14 15:02:44.551 [...
Hint: Some lines were ellipsized, use -l to show in full.

If you see any error go back a few steps and try again. Sometimes it is easiest just to reinstall the OS and start from scratch. It only takes 5 minutes.

Open Ports in Firewall

IRI is now running but neighbours can not connect to it. Open the needed ports in the firewall.

$ sudo firewall-cmd --zone=dmz --add-port=15600/tcp  --permanent
$ sudo firewall-cmd --zone=dmz --add-port=14600/udp  --permanent
$ sudo firewall-cmd --reload

Once more check again that firewall rules are what you think they are.

$ sudo firewall-cmd --zone=dmz --list-all
dmz (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: ssh
  ports: 15600/tcp 14600/udp
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

Congrats! You have a running IOTA Full Node. Reboot the machine to make everything starts automatically.

$ sudo reboot

Tighten up Security

There is still few things you should do. First of all go back to the server and disable root logins over ssh. This is the absolute minimum.

$ ssh [email protected]
$ sudo nano -w /etc/ssh/sshd_config
PermitRootLogin no

Also unless you absolutely need it, disable IPv6 protocol from ssh.

AddressFamily inet

Press ctrl-x to save and exit. Next restart the ssh daemon.

$ sudo systemctl restart sshd

Posted in IOTA  on 15 Dec 2017.