Another day in Paradise. So on this beautiful day, I was wondering how I can set up a reverse proxy for Atoma’s test and release tool. Every module of the product runs on different ports and for our clients, it is really a pain in the ass to open up ports on their firewalls. Banking is really secure domain so I was thinking, how I can use a reverse proxy instead of browsing the different modules on nonstandard ports. I use NGINX as a reverse proxy. It is a fast and trusted open-source solution. Here is how I did it.

Firstly, add the NGINX image in Docker. You may use the docker command-line interface:

$ docker pull nginx

or use Portainer:

Docker pull nginx image
Portainer Pull image

The next step is to add the image to the stack. Again we are using the good old Portainer to make this job.

Edit the stack file to use the NGINX image.
Portainer Stack details

Here you need to define the ports that you want to use.

  - "80:80"
  - "443:443"

Then we need to define the volumes as well. The first two volumes are the let’s say default ones. I added a volume for the config file so I do not have to edit the default.conf inside the container. So it can be edited on the docker server.


And one volume for the SSL certificates. The application does have its own certificates so I just used them. If you need to create SSL certification then there are many quick guides on the internet.


In the /opt/docker/nginx-config create the file default.conf with the following content:

server {
         listen 443 ssl default_server;
         listen [::]:443 ssl default_server;        # New root location

         ssl_certificate /etc/ssl/certs/taris.pem;
         ssl_certificate_key /etc/ssl/certs/taris.key;

         location / {
                 root /usr/share/nginx/html;
                 # return 404;
         }        # You may need this to prevent return 404 recursion.
         location = /404.html {
         location /portainer/ {
             proxy_http_version 1.1;
             proxy_set_header Host $host;
             proxy_set_header Connection "";
         location /portainer/api/websocket/ {
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection "upgrade";
             proxy_http_version 1.1;

The main parts were highlighted. For the portainer we need to set a path, eg. /portainer/ and pass the request to the application running on the container on port 9000. Also, we need to add the API, because on the container it is running on the /api/websocket/ path but because portainer is running under the /portainer/ folder we have to add it separately.

Here is the result:

Accessing portainer on port 443 using nginx as reverse proxy.
Accessing portainer on port 443.

And that’s all. Cheers,

6 thoughts to “NGINX Reverse Proxy for Docker Containers and for Portainer

  • bhr

    Very very very elegant and nice solution, I was trying to do using complex rewrite rules, but it breaks some api functions. Thanks for share 🙂

  • Dave H

    Been searching for a solution. The two proxy_set_header for /api/websocket were the key! Thanks so much for sharing this.

  • Alex Balcanquall

    Thanks this was just what I needed.

    Note that when proxying using a domain such as it is only necessary to add this to the default location /

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection “upgrade”;
    proxy_http_version 1.1;

    the /portainer and portainer/api locations are not needed in this scenario

    • Gábor Zsolt Nagy


  • Doc

    Hi, i am trying to setup portainer with ngin x proxy manager using this conf, but i get response “Unable to retrive server settings and status” do i miss something?thx

    • Gábor Zsolt Nagy

      I’ve never used NGINX proxy manager but I would check the error logs to see what could be the problem.
      Were you able to set the “proxy_set_header” options in the proxy manager? That was the key for the reverse proxy for me.
      See also the other comments here. They might also help.


Leave a comment

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload the CAPTCHA.