How to install and configure NATS on Ubuntu 16.04

Introduction

NATS is an open source high-performance messaging system, often referred to as "the central nervous system of the cloud." It is capable of routing millions of messages per second, which makes it ideal for connecting microservices and Internet of Things (IoT) devices.

NATS is a PubSub messaging system. In such a system, one or more publishers send messages with a specific topic to the message broker, and the message broker delivers these messages to any client or subscriber of a given topic. Publishers don’t understand or even care about subscribers, and vice versa. This architecture makes it easy to extend the system and add new features, because we can add publishers and subscribers without affecting the rest of the system. This type of system is very suitable for monitoring servers and devices; devices can send messages, we can subscribe to these messages, and send notifications via email or other means.

In this tutorial, we will install the official gnatsd NATS server as a service and access it in a secure way. We will also create a basic server overload warning system that sends emails when the server load is too high and uses gnatsd as its message agent.

Preparation

To complete this tutorial, you need:

Step 1-Download NATS server

Let's first download the gnatsd server and make sure it runs on our system without any problems.

The latest stable gnatsd version is version 0.9.4 at the time this tutorial was written. You can check the NATS download page to get the higher version. If you want to use the newer version, you can adjust the following commands as needed.

First, log in to your server using a non-root account:

ssh sammy@your_server_ip

Then, make sure you are in the user's home directory:

cd

Next, use wget to download gnatsd to your server:

wget https://github.com/nats-io/gnatsd/releases/download/v0.9.4/gnatsd-v0.9.4-linux-amd64.zip

The archive you just downloaded is a compressed archive, so you need to install unzip to unzip the file. You can install it with apt:

sudo apt-get install -y unzip

Then unzip is used to extract gnatsd:

unzip -p gnatsd-v0.9.4-linux-amd64.zip gnatsd-v0.9.4-linux-amd64/gnatsd > gnatsd

Then create the gnatsd executable file to run it:

chmod +x gnatsd

Let's test it, we can run gnatsd by running it from the current directory. Start gnatsd with the following command:

. /gnatsd --addr 127.0.0.1--port 4222

The output you see is similar to this example:

[1851]2016 /09/2305:20:02.247420[INF] Starting nats-server version 0.9.4[1851]2016/09/2305:20:02.248182[INF] Listening for client connections on 127.0.0.1:4222[1851]2016/09/2305:20:02.248626[INF] Server is ready

By default, gnatsd listens on port 0.0.0.0 on the 4222 address corresponding to all interfaces. Using the --port parameter, you can change the port, and you can use --addr to change its listening address. We run gnatsd with --addr 127.0.0.1, so it can only be accessed on our server and cannot be accessed by external clients. Later in this tutorial, we will ensure that gnatsd is open to the world.

Press CTRL+C to close gnatsd.

Now that you know things work, let's set it up in a more formal way.

Step 2-Create directory structure and configuration files

On Linux, third-party service related software is often stored in the /srv directory. We will follow this convention and keep NATS-related files under /srv/nats. We put the gnatsd executable file into /srv/nats/bin.

First, create the /srv/nats/bin folder:

sudo mkdir -p /srv/nats/bin

Then move gnatsd to the /srv/nats/bin folder:

sudo mv ~/gnatsd /srv/nats/bin

The server can load its configuration from a file, which will come in handy when we need to modify the server settings later in this tutorial. Create the file /srv/nats/gnatsd.config:

sudo nano /srv/nats/gnatsd.config

And add the following to the file:

port:4222
net:'127.0.0.1'

This configuration file tells the gnatsd server to listen on port 4222 at address 127.0.0.1, as before, but this time we don't have to specify these options on the command line.

Let's run the server again to make sure we have configured it correctly. Execute the following command to start gnatsd with the new configuration file:

/srv/nats/bin/gnatsd -c /srv/nats/gnatsd.config

The output is similar to what you saw earlier:

[1869]2016 /06/1805:30:55.988856[INF] Starting nats-server version 0.9.4[1869]2016/06/1805:30:55.989190[INF] Listening for client connections on 127.0.0.1:4222[1869]2016/06/1805:30:55.989562[INF] Server is ready

Press CTRL+C again to close gnatsd and return to your prompt. Now let's create a user who will run this service.

Step 3-Create Service User

Running each service with its own user account to limit the damage when the service is compromised is a good security measure. Let's create a user and group with NATS service and NATS related files.

First, let's create a system user and group named nats:

sudo adduser --system --group --no-create-home --shell /bin/false nats
OutputAdding system user `nats' (UID 106) ...
Adding new group `nats' (GID 114)...
Adding newuser`nats' (UID 106) with group `nats' ...
Not creating home directory `/home/nats'.

We assign /bin/falseshell to the nats system user to disable this user's login and prohibit the creation of home directories. We also created a nats group.

Let's change the owner of the /srv directory to the nats user and group:

sudo chown -R nats:nats /srv

Now that we have created the nats user and group, let's continue to create the NATS service.

Step 4-Run gnatsd as a service

We want gnatsd to start when the system starts, and restart if it crashes. We will use systemd to deal with this problem.

systemd is a service manager for Linux systems. It is responsible for starting services at startup, restarting them as needed, and stopping them in a controlled manner when the system is shut down.

We need to create a service configuration to define how and when the NATS service should be started. The service file created by the user exists in /etc/systemd/system, so create the file /etc/systemd/system/nats.service:

sudo nano /etc/systemd/system/nats.service

In the file, place this script to define how gnatsd should be started:

[ Unit]
Description=NATS messaging server
​
[ Service]
ExecStart=/srv/nats/bin/gnatsd -c /srv/nats/gnatsd.config
User=nats
Restart=on-failure
​
[ Install]
WantedBy=multi-user.target

Once the service description is in place, we can start it with the following command:

sudo systemctl start nats

Let's confirm that gnatsd is running by sending a PING message:

printf "PING\r\n"| nc 127.0.0.14222

We just used nc to communicate with gnatsd. nc is a command line utility to communicate with TCP or UDP server. The command we used prints output similar to the following:

INFO {"server_id":"Os7xI5uGlYFJfLlfo1vHox","version":"0.9.4","go":"go1.6.3","host":"127.0.0.1","port":4222,"auth_required":false,"ssl_required":false,"tls_required":false,"tls_verify":false,"max_payload":1048576}
PONG

The response to PONG lets us know that the server is listening and working as expected. We need to run the last command to make our NATS server start at boot time:

sudo systemctl enable nats

You will see the following output, confirming that the service is installed:

OutputCreated symlink from/etc/systemd/system/multi-user.target.wants/nats.service to /etc/systemd/system/nats.service.

We have successfully configured gnatsd to run as a service. Now let us protect it and make it accessible to external clients.

Step 5-Secure the connection with the NATS service

If all the publishers and subscribers gnatsd we want to use are running on the same server, we can call it complete and move on, but this rarely happens now. We need to allow the external client gnatsd to connect and publish messages in a secure way.

gnatsd supports TLS transmission, so we will use it to protect the communication between gnatsd NATS clients.

First, we need a certificate. You can purchase commercial certificates, retrieve commercial certificates from [Let's Encrypt] (http://letsencrypt.org/) or generate self-signed certificates. We will use the latter method because obtaining a certificate is beyond the scope of this article.

Create a directory to temporarily store certificates:

mkdir ~/priv

Then use the following command to create a self-signed certificate:

openssl req -x509 -nodes -days 3650-newkey rsa:2048 \
 - keyout priv/gnatsd.key -out priv/gnatsd.crt \
 - subj "/C=US/ST=Texas/L=Austin/O=AwesomeThings/CN=www.example.com"

This command creates a 2048-bit RSA certificate with a validity period of 10 years. Please note that we used an arbitrary domain name because we will not enable TLS verification for the gnatsd server in this article.

You should now have these files gnatsd.key and gnatsd.crt in the ~/priv directory. Let's move these files to our /srv/nats/ directory structure so that everything is in one place. Execute the following commands:

sudo mv ~/priv /srv/nats

Now, only the nats user and group are allowed to access /srv/nats/priv:

sudo chmod 440/srv/nats/priv/*
sudo chmod 550 /srv/nats/priv
sudo chown -R nats:nats /srv/nats/priv

Now we update /srv/nats/gnatsd.config to include the certificate and key we just created. Open the configuration file again:

sudo nano /srv/nats/gnatsd.config

And add the following section to tell gnatsd to use your certificate and key:

...
​
tls {
 cert_file:"/srv/nats/priv/gnatsd.crt"
 key_file:"/srv/nats/priv/gnatsd.key"
 timeout:1}

Save the file and exit the editor. Then restart the service so that it can pick up the changes.

sudo systemctl restart nats

Let's test whether our certificate is valid. Run this command:

printf "PING\r\n"| nc localhost 4222

This time, the command outputs the following message:

INFO {"server_id":"npkIPrCE5Kp8O3v1EfV8dz","version":"0.9.4","go":"go1.6.3","host":"127.0.0.1","port":4222,"auth_required":false,"ssl_required":true,"tls_required":true,"tls_verify":false,"max_payload":1048576}-ERR 'Secure Connection - TLS Required'

The server returns the message -ERR'Secure Connection-TLS Required', confirming that it has received the new configuration and requires a secure connection, but nc does not know how to operate.

In order to be able to communicate with our NATS service without installing a complete NATS client, we will use a tool called catnats. Let's download it first:

wget https://github.com/yuce/catnats/raw/0.1.2/catnats.py

And make it executable:

chmod +x catnats.py

Finally, move catnats.py to the /srv/nats/bin folder and rename it to catnats:

sudo mv catnats.py /srv/nats/bin/catnats

Let's catnats check whether we can communicate using our NATS service by sending the same message sent before PING:

printf "PING\r\n"|/srv/nats/bin/catnats --addr 127.0.0.1:4222

You will see this output indicating that our connection is secure:

INFO {"server_id":"npkIPrCE5Kp8O3v1EfV8dz","version":"0.9.4","go":"go1.6.3","host":"127.0.0.1","port":4222,"auth_required":false,"ssl_required":true,"tls_required":true,"tls_verify":false,"max_payload":1048576}
PONG

Now that we have secured the communication, let's enable authentication so that connecting to NATS requires a username and password.

Step 6-ID verification required

Our NATS service does not require authentication by default. This is fine when the service can only be accessed on a private network, but we want our NATS service to be accessible on the Internet, so we should enable authentication. gnatsd supports username and password authentication and is easy to enable.

Open the /srv/nats/gnatsd.config file:

sudo nano /srv/nats/gnatsd.config

Add a new authorization section specifying credentials. We will use the username user1 and password pass1 for this tutorial. You should use longer, more complex passwords in a production environment:

...

authorization {
 user: user1
 password: pass1
}

Save the file, and then change the owner of /srv/nats/gnatsd.configto nats and make it readable by this user to protect the usernames and passwords of other users on the system:

sudo chown nats /srv/nats/gnatsd.config
sudo chmod 400/srv/nats/gnatsd.config

Then restart the service for the changes to take effect:

sudo systemctl restart nats

Let us send a PING message to gnatsd to check if everything is normal. Once again, use catnats to send messages:

printf "PING\r\n"|/srv/nats/bin/catnats --addr 127.0.0.1:4222

You will see the following output:

NFO {"server_id":"sY0SSJBNbEw53HxzS9mH1t","version":"0.9.4","go":"go1.6.3","host":"127.0.0.1","port":4222,"auth_required":true,"ssl_required":true,"tls_required":true,"tls_verify":false,"max_payload":1048576}-ERR 'Authorization Violation'

This tells us that the changes have been successfully applied, and now we need to send the correct username and password to connect to the service. Let's try again, this time providing username user1 and password pass1:

printf "PING\r\n"|/srv/nats/bin/catnats --addr 127.0.0.1:4222--user user1 --pass pass1

As you can see from the output below, it worked this time:

INFO {"server_id":"sY0SSJBNbEw53HxzS9mH1t","version":"0.9.4","go":"go1.6.3","host":"127.0.0.1","port":4222,"auth_required":true,"ssl_required":true,"tls_required":true,"tls_verify":false,"max_payload":1048576}+OK
PONG

Now that we have restricted this service to clients that know the username and password, we can reconfigure the service so that external clients can connect.

Step 7-Open the service to the world

We have configured our NATS server to listen on 127.0.0.1, which is the local interface. If we let it listen to 0.0.0.0, then the world will be able to use it. Our last update of /srv/nats/gnatsd.config:

sudo nano /srv/nats/gnatsd.config

Then change the IP address associated with the net setting:

...
net:'0.0.0.0'...

Save the file and restart the service:

sudo systemctl restart nats

Now our NATS service is ready for external client connections. To learn how to use it, let's create a simple monitoring service that uses our NATS server as a message broker.

Step 8-(Optional) Configure server overload notification

In this section, you will create a simple overload monitoring system using NATS services. The system will receive the average load of the server and send an email to the administrator when any server is overloaded.

The sample project will contain the following components:

For simplicity, we will run all these components on the same server, but you can try to run each component on a different server after completing this tutorial.

Setting up the monitor

You can read the average load of the Linux system /proc/loadavg from it. For this project, we are only interested in the last-minute load average, which is the first field of the output. Use this command to get the value:

cat /proc/loadavg | cut -f1 -d" "

You will see the following output:

0.11

The average load obtained by reading /proc/loadavg depends on the number of processors, so you must normalize it by dividing the average load by the number of processors. You can use the following command to get the number of processors in the server:

getconf _NPROCESSORS_ONLN

You will see the result displayed in the terminal:

1

Since the default shell of our server cannot handle floating point arithmetic, we will send the load average value and the number of processors and host name as the payload of the message, and divide it in the notification program later. This is the command we use to construct the payload:

echo $(hostname)`cat /proc/loadavg | cut -f1 -d" "``getconf _NPROCESSORS_ONLN`

This command displays the host name, average load and number of processors respectively:

your_hostname 0.281

Let's create a shell script that uses the hostname stats.loadaverage to publish the load average and the number of processors to our NATS server. We will configure our system to run this script regularly. Create a new file named ~/publish_load_average.sh:

nano ~/publish_load_average.sh

In the file, add the following script:

NATS_ADDR=127.0.0.1:4222
LOADAVG=$(cat /proc/loadavg | cut -f1 -d" ")
NPROC=$(getconf _NPROCESSORS_ONLN)
SUBJECT="stats.loadaverage"
PAYLOAD=$(echo $(hostname) $LOADAVG $NPROC)
MESSAGE="PUB $SUBJECT ${#PAYLOAD}\r\n${PAYLOAD}\r\n"
printf "$MESSAGE"|/srv/nats/bin/catnats -q --raw --addr $NATS_ADDR --user user1 --pass pass1

This script creates a message and then delivers the message to catnats, which publishes the message to the NATS service. Our catnats runs with the -q switch to suppress any output, we use the --raw switch, so catnats will not try to interpret the input. $NATS_ADDR If the NATS service is located on a different server, you can change the value of the variable.

Let's test the script to send the load average to NATS.

The following command runs ~/publish_load_average.sh every 5 seconds. Note that we use the characters at the end of the & line to run commands in the background:

whiletrue;do sh ~/publish_load_average.sh; sleep 5; done &

You will see the output showing that the command is running in the background with a process ID:

[1]14123

Note: Write down the process ID somewhere because you need to use that ID to stop the command later.

Now connect to NATS and subscribe to the topic stats.loadaverage to retrieve the load average:

printf "SUB stats.loadaverage 0\r\n"|/srv/nats/bin/catnats --raw --no-exit --pong --user user1 --pass pass1

We use the --no-exit flag to disable automatic exit, and --pong to keep our connection with NATS active. If everything is correct, you should get output similar to the following, updated every 5 seconds:

INFO {"server_id":"A8qJc7mdTy8AWBRhPWACzW","version":"0.8.1","go":"go1.6.2","host":"0.0.0.0","port":4222,"auth_required":true,"ssl_required":true,"tls_required":true,"tls_verify":false,"max_payload":1048576}+OK
+ OK
MSG stats.loadaverage 027
your_hostname 0.081

Press CTRL+C to exit catnats. Let's stop the calling publish_load_average.sh loop, because we will have a better way to run publish_load_average.sh:

kill 14123

The method we just adopted is very suitable for testing, but it is not the method we want to use permanently. We want the system to be able to run publish_load_average.sh every minute. To achieve this, we can add a crontab entry. The Linux system uses cron, a system that can run commands or "jobs" according to the schedule we specify. The crontab command allows us to manage these jobs.

To create a new entry, execute the following command:

crontab -e

If you have never run the above command, you may see the following prompt asking you to choose a text editor to manage entries:

no crontab for demo - using an empty one

Select an editor.  To change later, run 'select-editor'.1./bin/ed
 2. /bin/nano        <---- easiest
 3. /usr/bin/vim.basic
 4. /usr/bin/vim.tiny

Choose 1-4[2]:

Enter the number corresponding to the editor you are most familiar with, and press ENTER. The file will be displayed in the editor of your choice.

At the end of the opened file, add the following line, but if you used the following, please replace your username sammy:

* /1**** bash /home/sammy/publish_load_average.sh

The above entry tells cron that we run the publish_load_average.sh script every minute. Save the file and close the editor.

Now let us test whether the periodic release of load averages is effective:

printf "SUB stats.loadaverage 0\r\n"|/srv/nats/bin/catnats --raw --no-exit --pong --user user1 --pass pass1

Wait a few minutes and the output you see will be similar to the following:

INFO {"server_id":"A8qJc7mdTy8AWBRhPWACzW","version":"0.8.1","go":"go1.6.2","host":"0.0.0.0","port":4222,"auth_required":true,"ssl_required":true,"tls_required":true,"tls_verify":false,"max_payload":1048576}+OK
+ OK
MSG stats.loadaverage 027
your_hostname 0.011
MSG stats.loadaverage 027
your_hostname 0.001

Press CTRL+C to exit catnats.

We have successfully set up the monitor and it is sending messages to our NATS server. Next, we will set up a notification program that uses this data.

Create notification program

Let's create a notification program that connects to our NATS service and listens for stats.loadaverage messages. Whenever our program receives a message, it calculates the average load of each processor. If it is higher than 0.6 or 60% CPU utilization per processor, it will set a warning flag for the host publishing the message and send the email to the predefined address. If the average load of each processor is less than 0.4, the warning flag of the host is cleared. To prevent flooding the inbox, we will send an email when the warning flag is set.

We will use Node.JS to create the notification program, because Node.js has a great NATS client. So, first install Node.js:

sudo apt-get install -y npm

Next, create a directory for the notification program and switch to that directory:

mkdir ~/overload_notifier && cd ~/overload_notifier

The Node.js project uses a file called package.json, which contains information about the project and its dependencies. Execute the following command to create the file:

npm init -y

Then install the NATS client for Node.js, and the nodemailer module we will use in this project to send warning emails:

npm install [email protected] [email protected]

Now we can create the notification program. Create the file notifier.js:

nano notifier.js

Then add the following code to the file:

var NATS_URL ='nats://127.0.0.1:4222';var NATS_USER ='user1';var NATS_PASS ='pass1';var EMAIL_TO ='[email protected]';

Be sure to change these options to match the username and password of the NATS service, and your email address.

Next, add this code to import the Node.js NATS client and connect to the gnatsd service:

var tlsOptions ={
 rejectUnauthorized:false,};var nats =require('nats').connect({url: NATS_URL,
         tls: tlsOptions,
         user: NATS_USER,
         pass: NATS_PASS});

Then add this code to set up the mail program and connect to the SMTP server that will send emails. We will set up this server soon:

var nodemailer =require('nodemailer');var transport = nodemailer.createTransport('smtp://localhost:2525');

Then add the rest of the code to calculate the load average and determine if a notification email needs to be sent:

// keep the state of warnings for each hostvar warnings ={};
​
functionsendEmail(subject, text){
 transport.sendMail({
  to: EMAIL_TO,
  subject: subject,
  text: text
    });}
​
functionprocessMessage(message){// message fields: host load processor_countvar fields = message.split(" ");var host = fields[0];var loadAverage =parseFloat(fields[1])/parseInt(fields[2]);if(loadAverage >0.6){if(!warnings[host]){// send warning email if one wasn't already sentvar res =sendEmail('Warning! Server is Overloaded: '+ host,'Load average: '+ loadAverage);// set warning for the host
   warnings[host]=true;}}elseif(loadAverage <0.4){if(warnings[host]){// clear the warning
   warnings[host]=false;}}}
​
nats.subscribe('stats.loadaverage', processMessage);

We subscribe to the message, and every time we receive a message, we will execute the processMessage function, which parses the payload we sent and determines the average load. If it is too high, we send a message, and we track whether we have sent a message before by setting a flag based on the host name. This way we can track notifications by host. If the load average is below our threshold, we clear the flag.

With the monitor and notification program, we can test our sample project.

Test items

Let's try it. We will generate some artificial load and check whether the notifier will send a warning email when the load is too high.

Let's install the stress tool to generate CPU load on our server:

sudo apt-get install -y stress

Next, we need to set up an SMTP server to post messages from the notification program. Installing and configuring a complete SMTP server is overkill for this test, so we will use a simple SMTP server that only displays emails delivered to it, rather than actually sending them. The Python programming language has a DebuggingServer module that we can load. It discards the emails it receives, but displays them on the screen so that we can make sure it works. Python is already installed on our Ubuntu server, so this is a perfect solution.

We start and debug the SMTP server in the background. We will listen on the localhost port 2525, which matches the SMTP address we configured in the notifier.js code. Execute this command to start the SMTP server:

python -m smtpd -n -c DebuggingServer localhost:2525&

Then use the following command to start the notification program in the background:

nodejs ~/overload_notifier/notifier.js &

Finally, let's generate some load on all the processors of the server. Execute the stress command with the following options:

stress --cpu $(getconf _NPROCESSORS_ONLN)

After a few minutes, you will see output similar to the following because the SMTP server starts to display messages sent by the notifier:

- - - - - - - - - - MESSAGE FOLLOWS ----------
Content-Type: text/plain
To: [email protected]
Subject: Warning! Server is Overloaded: your_hostname
Message-Id:<1466354822129-04c5d944-0d19670b-780eee12@localhost>
X-Mailer:nodemailer(2.4.2;+http://nodemailer.com/;
 SMTP/2.5.0[client:2.5.0])
Content-Transfer-Encoding: 7bit
Date: Sun,19 Jun 201616:47:02+0000
MIME-Version:1.0
X-Peer:127.0.0.1

Load average:0.88------------ END MESSAGE ------------

This will let you know that you have successfully sent emails when the server load is too high.

Press CTRL+C to stop generating load. You have completed the sample project, and now you should know how to work for you in your own environment.

in conclusion

In this article, you learned about the NATS PubSub messaging system, installed it as a service in a secure way, and tested it in a sample project. The sample project uses the Node.JS client, but NATS has clients with more languages and frameworks, you can find them on NATS download page. You can learn more about NATS in its Official Document.

For more Ubuntu tutorials, please go to [Tencent Cloud + Community] (https://cloud.tencent.com/developer?from=10680) to learn more.

Reference: "How To Install and Configure NATS on Ubuntu 16.04"

Recommended Posts

How to install and configure NATS on Ubuntu 16.04
How to install and configure Gogs on Ubuntu 18.04
How to install and configure Cyberpanel on Ubuntu 18.04
How to install and configure ownCloud on Ubuntu 16.04
How to install and configure ownCloud on Ubuntu 16.04
How to install and configure GitLab on Ubuntu 18.04
How to install and configure Ansible on Ubuntu 18.04
How to install and configure Elasticsearch on Ubuntu 16.04
How to install and configure PostGIS on Ubuntu 14.04
How to install and configure VNC on Ubuntu 18.04
How to install and configure Sphinx on Ubuntu 16.04
How to install and configure OrientDB on Ubuntu 14.04
How to install and configure AppScale on Ubuntu 12.04
How to install and configure PostGIS on Ubuntu 14.04
How to install Pycharm and Ipython on Ubuntu 16.04/18.04
How to install and configure Elasticsearch on CentOS 7
How to install and secure phpMyAdmin on Ubuntu 16.04
How to install and use Docker on Ubuntu 20.04
How to install and configure VNC on CentOS 8
How to install and use Curl on Ubuntu 18.04
How to install and use Composer on Ubuntu 18.04
How to install and use Wine on Ubuntu 18.04
How to install and secure phpMyAdmin on Ubuntu 16.04
How to install and configure Redis on CentOS 8
How to install and use Composer on Ubuntu 20.04
How to install and use BaasBox on Ubuntu 14.04
How to install and use PostgreSQL on Ubuntu 16.04
How to install and configure phpMyAdmin on CentOS 6
How to install and configure Owncloud on CentOS 8
How to install and use Docker on Ubuntu 16.04
How to install and configure Redmine on CentOS 8
How to install Ruby on Ubuntu 20.04
How to install Memcached on Ubuntu 20.04
How to install Java on Ubuntu 20.04
How to install MySQL on Ubuntu 20.04
How to install VirtualBox on Ubuntu 20.04
How to install Elasticsearch on Ubuntu 20.04
How to install Protobuf 3 on Ubuntu
How to install Nginx on Ubuntu 20.04
How to install Apache on Ubuntu 20.04
How to install Git on Ubuntu 20.04
How to install Node.js on Ubuntu 16.04
How to install MySQL on Ubuntu 20.04
Install and configure MySQL on Ubuntu
How to install Vagrant on Ubuntu 20.04
How to install Bacula-Web on Ubuntu 14.04
How to install PostgreSQL on Ubuntu 16.04
How to install Git on Ubuntu 20.04
How to install Anaconda3 on Ubuntu 18.04
How to install Memcached on Ubuntu 18.04
How to install Jenkins on Ubuntu 16.04
How to install MemSQL on Ubuntu 14.04
How to install Go on Ubuntu 20.04
How to install MongoDB on Ubuntu 16.04
How to install Mailpile on Ubuntu 14.04
How to install PrestaShop on Ubuntu 16.04
How to install Skype on Ubuntu 20.04
How to install Jenkins on Ubuntu 20.04
How to install Python 3.8 on Ubuntu 18.04
How to install KVM on Ubuntu 18.04
How to install KVM on Ubuntu 20.04