docker

How to manage Docker with portainer on Ubuntu 16.04 LTS with Apache2 as reverse proxy

Today I want to show how to manage your Docker containers with portainer . We use the portainer docker image, Apache2 as a reverse proxy, and we will secure our installation with LetsEncrypt.

Prerequisites:
– an Ubuntu VPS
– LAMP stack installed
– Reverse Proxy Module enabled in Apache2
– Docker installed
– certbot installed
– DNS-A record for our Apache2-vHost

If requirements are missing, of course we have to do this first.

LAMP stack:

 sudo apt-get install lamp-server^

Enable reverse proxy modules:

sudo a2enmod proxy proxy_http proxy_ajp rewrite deflate headers proxy_balancer proxy_connect proxy_html proxy_wstunnel authz_core authn_core setenvif ssl

Docker:
Version from the official package sources:

sudo apt-get install docker.io
sudo systemctl start docker
sudo systemctl enable docker

or directly from Docker:

sudo curl -sSL https://get.docker.com/ | CHANNEL=stable sh
sudo systemctl enable docker.service
sudo systemctl start docker.service

Certbot:

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-apache

Afterwards we can continue and put Portainer into operation.

Step 1: Run Portainer docker Image

With the following command we start the container on our server:

sudo docker run -d -p 9000:9000 --restart always -v /var/run/docker.sock:/var/run/docker.sock -v /opt/portainer:/data portainer/portainer

We check, if the container was started:

sudo docker ps

Portainer now listens on port 9000.

Step 2: Create Apache2 vHost

When the container is running, we create a vHost so we can use the reverse proxy functionality and call it in the browser without a port specification later:

sudo nano /etc/apache2/sites-available/003-portainer.conf

we add the following content:

<VirtualHost *:80>

ServerName portainer.your-domain.tld

</VirtualHost>

Save file, activate site and restart Apache2:

sudo a2ensite 003-portainer.conf
sudo systemctl restart apache2

Now Portainer would already be accessible via http: //portainer.your-domain.tld. But we are working with password input, so we encrypt the connection with SSL.

we use Certbot:

sudo certbot --apache

Select the corresponding host and at the end select „2“ for „redirect“.

Now we have to edit the generated conf:

sudo nano /etc/apache2/sites-available/003-portainer-le-ssl.conf

and add the following block after ServerName:

# Proxy to Portainer
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:9000/
ProxyPassReverse / http://127.0.0.1:9000/
RequestHeader set X-Forwarded-Proto "https"

ProxyVia Block

<Proxy *>
Require all granted
</Proxy>

# SSL Configuration - uses strong cipher list - these might need to be downgraded if you need to support older browsers/devices
SSLEngine on
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder On

# HSTS (optional)
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"
# Prevent MIME based attacks
Header set X-Content-Type-Options "nosniff"

ErrorLog /var/log/apache2/portainer-error.log
CustomLog /var/log/apache2/portainer-access.log combined

#Proxy to docker container console

<Location /api/websocket/>
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteRule /api/websocket/(.*) ws://127.0.0.1:9000/api/websocket/$1 [P]
</Location>

Save File and Restart Apache2 again.

sudo systemctl restart apache2

Step 3: Configure Portainer

via the browser of our choice we call https://portainer.your-domain.tld and must first assign a password for the admin:

In the next dialog we set the setting to „Local“:

click on the button „Connect“ and after a short time you will see the dashboard of portainer:

If we select „Container“, we can see more information about the individual containers or restart, stop, etc.:

Container details:

Update:

If you want to call Portainer in a subfolder of an existing vHost (as example: https://hostname.your-domain.tld/portainer/) than you have to add the following block to this conf:

<Location /portainer/>
ProxyPass http://127.0.0.1:9000/
ProxyPassReverse http://127.0.0.1:9000/
RequestHeader set X-Forwarded-Proto "https"
</Location>

<Location /portainer/api/websocket/>
ProxyPass http://127.0.0.1:9000/api/websocket/
ProxyPassReverse http://127.0.0.1:9000/api/websocket/
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteRule /api/websocket/(.*) ws://127.0.0.1:9000/api/websocket/$1 [P]
</Location>

Don not forget to enable reverse proxy modules.

That’s it for today, have fun 🙂

12 Gedanken zu „How to manage Docker with portainer on Ubuntu 16.04 LTS with Apache2 as reverse proxy

  1. Hi Markus,
    thanks for updating the post with the „standalone“ version of the config. And with your help, I got it to work. Thanks a lot for sharing!
    Regards,
    Michael

  2. Hello,
    all works fine, thank you, but if I want to use the web console I get an error „timeout waiting for exec session ready“

  3. Hi Markus,
    thank you for your guide.

    I have a docker container with Apache/2.4.25 and all above mentioned mods enables with an existing https-vhost that hast port 443 exposed.
    My portainer image has no ports exposed but is reachble from the apache container.
    I am able to access the login page of portainer bun cannot login and I get two error messages telling me that endpoints and servers settings are unrechable.
    Here is my config, I would apreciate if you took the time to have a look:

    ProxyPass http://portainer-ip:9000/
    ProxyPassReverse http://portainer-ip:9000/
    RequestHeader set X-Forwarded-Proto „https“

    ProxyPass http://portainer-ip:9000/api/websocket/
    ProxyPassReverse http://portainer-ip:9000/api/websocket/
    RequestHeader set X-Forwarded-Proto „https“

    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule /api/websocket/(.*) ws://portainer-ip:9000/api/websocket/$1 [P]

    Thanks a lot

  4. Markus, I couldn’T stop working on my problem, and I found the following to work, but only if I use a trailing slash in the calling url like this: https://portainerserver/portainer/
    code:

    ProxyPass http://localhost:9000
    ProxyPassReverse http://localhost:9000
    #RequestHeader set X-Forwarded-Proto „https“

    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule /portainer/api/websocket/(.*) ws://localhost:9000/portainer/api/websocket/$1 [P]

    I will have to get to do some reading on ProxyPass and …Reverse – this can by quite tricky it seems
    Cheers!!!

    1. Hi Michael,
      Your Welcome 🙂
      Rapidly, I would test the following directives:

      ProxyPreserveHost On
      ProxyPass /portainer http://127.0.0.1:9000/
      ProxyPassReverse /portainer http://127.0.0.1:9000/
      RequestHeader set X-Forwarded-Proto "https"
      
      <Location /portainer/api/websocket/>
      ProxyPass http://127.0.0.1:9000/
      ProxyPassReverse /
      RequestHeader set X-Forwarded-Proto "https"
      
      RewriteEngine on
      RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
      RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
      RewriteRule /portainer/api/websocket/(.*) ws://127.0.0.1:9000/api/websocket/$1 [P]
      </Location>

      Have you try this?

      Regards
      Markus

  5. Markus, thanks for the great write-up. I am however having a hard time getting this constellation to work with portainer being available as /portainer behind aapache acting as reverse proxy.
    It only loads the title page as text and then some 404s appear in Apache’s access log (no error entries btw). I also think I’d have to change settings in portainer to make it reply with /portainer being its root dir…?!?
    Could you point out where to make changes? I tried sth like this:

    ProxyPass http://localhost:9000
    ProxyPassReverse http://localhost:9000/portainer
    RequestHeader set X-Forwarded-Proto „https“

    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule /api/websocket/(.*) ws://localhost:9000/api/websocket/$1 [P]

    Thanks a bunch in advance

  6. Hi there! This guide was really useful and I managed to setup portainer correctly under apache. However, the console access for the containers is not working. Do you know any workaround?

    Thanks again for this post!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.