How to setup Portainer on Linux

How to setup Portainer on Linux

What is Portainer ?

Portainer is a lightweight and powerful open-source management UI for Docker, Docker Swarm, and Kubernetes. It simplifies container management by providing an intuitive web-based interface to interact with containerized applications and services. Portainer is designed to help both novice and experienced users manage their container environments more efficiently.

Usefulness

It is remarkably useful for most of the

To setup Portainer, we need the following things

  • Running instance of Docker
  • sudo access on the machine
  • By default, Portainer Server will expose the UI over port 9443.

If you do not have Docker installed yet, check out this blog to install Docker first.

Deployment

Portainer

First, create the volume that Portainer Server will use to store its database

docker volume create portainer_data

Then, download and install the Portainer Server container

docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

This will start the portainer docker container. But this is not all, we also need a reverse proxy, if we need to setup more services on the same Linux machine, and for that reverse proxy is indeed required in redirecting the incoming traffic to different services.

NGINX - Reverse Proxy

To setup the nginx, we can simply use run the following cmds

sudo apt install nginx

Then, simply start / restart the nginx service using

# To Start
sudo systemctl start nginx

# To restart
sudo systemctl restart nginx

# To check running status
sudo systemctl status nginx

once installed, we also need to configure the nginx. To do so, we edit the nginx conf file as follows

sudo nano /etc/nginx/conf.d/nginx.conf

Add the following lines

# COPY THIS TEMPLATE TO ADD MORE
server {
    listen 80;
    listen [::]:80;
    root /var/www/html;
    server_name <OUR_DOMAIN_NAME>;
}

and then press CTRL + o followed by CTRL + x to save it.

Next, anytime we make changes to the nginx config file, we can test whether the configuration we added seems to be legit or is there something nginx cannot understand. For that, we can test for nginx syntax errors using the following cmd

sudo nginx -t

If everything is correct, it will print out the following on the terminal

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

And when we are sure, we can reload the nginx service for the changes to take effect, using

sudo nginx -s reload
NoteIt is important to note that, until we reload the nginx, changes to the nginx config files are not reflected. So we need to reload the service everytime we make changes to the conf file.

Since we are setting up our own custom domain, we also need to setup SSL certificate such that the service is securely accessible over the https protocol.
For that, we have two options :-

  • Buy SSL certificate from a SSL certificate providers like Digicert
  • Setup a Free certificate ourself using tool certbot provided by "Let's Encrypt"

We will go with the Free certificate route here, but also explain in the end, how we can simply use the certificates obtained from SSL providers like Digicert etc,

SSL certificate

Now, to setup SSL certificate, we first need a tool called certbot. It is the official tool provided by Lets encypt to obtain SSL certificates easily.

To install, use this

sudo apt-get install certbot python3-certbot-nginx

Once installed, we can use certbot to issue an SSL certificate for our custom domain. We can also specify that it installs the issued certificate in our reverse proxy nginx.

certbot --nginx -d <OUR_DOMAIN_NAME>

Note, the domain is exactly the same which we used in the nginx configuration.
The flag --nginx provided to the certbot will read the nginx configuration file, and check if there exists any config for the domain for which SSL certificate request is issued. If found, certbot automatically edits the nginx config file to add the certificate path.

So, we will see that the nginx configuration now changes and looks like this

server {
    root /var/www/html;
    server_name <OUR_DOMAIN_NAME>;

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/<OUR_DOMAIN_NAME>/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/<OUR_DOMAIN_NAME>/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 {
    if ($host = <OUR_DOMAIN_NAME>) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    listen [::]:80;
    server_name <OUR_DOMAIN_NAME>;
    return 404; # managed by Certbot

}

But until now, we have not added the redirection of the incoming request to portainer service yet. That last part also needs to be added.

For that, lets edit the nginx config file one last time.
As can be seen above, certbot has created two sections in the nginx config file both starting with directive server.
One section is for the https requests while second section is for http request.

On Top, the first server directive is for the incoming request received on port 443 (basically the https requests), while the second server directive is for the request received on port 80 (the http requests).

And upon closely inspecting the second directive, it simply redirects that same request to the https part, that is on port 443.

If that all is clear so far, we understand that we only need to add the redirection section under the https (or to say at port 443 )only.

So, let's enrich the first server directive to something which should look like this

server {
    root /var/www/html;
    server_name <OUR_DOMAIN_NAME>;

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/<OUR_DOMAIN_NAME>/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/<OUR_DOMAIN_NAME>/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

    client_max_body_size 5G;
    location / {
        # Proxy pass to the service for local LAN IP
        proxy_pass  https://127.0.0.1:9443;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout   1200;
    }

}

So, we added that any request coming at the domain root will simply be forwarded (or to say proxied) to the service running at https:127.0.0.1:9443

NoteIt is very important to note that the proxy_passs address in the above section is https address, NOT the http. Otherwise this will NOT work.
I've spent quite few hours already debugging such stupid mistakes.Also, line 12 actually allows files of size upto 5GB in size to be uploaded without nginx disconnecting the conneciton. Otherwise, the default size limit is simply 1 MB.

Finally, we can go to the custom domain we specified, to access the portainer instance, securely over the https.

Conclusion

Portainer is not only easy to use, but also very easy to setup as well. It only takes max 20 minutes of your time if you know what you are doing.

Further reading

For further reading, please refer the official installation guide of Portainer documentation.

Read more