1

I use nginx to reverse proxy to multiple dockerized apps, which work. But I can't get portainer working.

My nginx config includes:

location ^~ /apps/portainer {
  proxy_http_version 1.1;
  proxy_set_header   Connection "";
  set                $upstream portainer:9000;
  proxy_pass         http://$upstream;
}

The page does not load correctly (css and js don't load). The nginx error log:

[error] open() "/var/www/html/apps/main.11b0c8b84d24581.js" failed (2: No such file or directory), request: "GET /apps/main.11b0c8b84d24581.js HTTP/2.0"

I don't understand why nginx is trying to serve static files - everything should be proxied to portainer. (And the path is wrong, though irrelevant).


Is there a regular fix for this, that doesn't involve regex? BTW the answer given below by @EchoMike444 is excellent if you don't mind using regex in a location block.

lonix
  • 896
  • 10
  • 23

1 Answers1

2

By following the config from https://portainer.readthedocs.io/en/stable/faq.html , i was able to connect to http://127.0.0.1/apps/portainer/

You are missing the part that manage websocket connections

my default.conf for ngnix

upstream portainer {
    server portainer:9000;
}

server {
  listen 80;

  location /apps/portainer/ {
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      proxy_pass http://portainer/;
  }
  location /apps/portainer/api/websocket/ {
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_http_version 1.1;
      proxy_pass http://portainer/api/websocket/;
  }
}

My docker-compose.yaml

version: '3.7'
services:
  portainer:
    image: portainer/portainer
    restart: always
    command: -H tcp://10.10.0.1:2375
    ports:
      - target: 8000
        published: 8000
        protocol: tcp
      - target: 9000
        published: 9000
    protocol: tcp
    volumes:
      - portainer_data:/data
  nginx:
    image: nginx
    volumes:
      - ${PWD}/default.conf:/etc/nginx/conf.d/default.conf:ro
    command: ["/bin/sh","-c","exec nginx -g 'daemon off;'"]
    restart: always
    ports:
      - target: 80
    published: 80
    protocol: tcp
    mode: host
volumes:
  portainer_data:

UPDATED after comment

Because nginx do the dns resolution at startup , you want to use a variable , so the default.conf become this .

resolver 127.0.0.11 valid=30s;
resolver_timeout 5s;


server {
  listen 80;

  location ~* ^(/apps/portainer)(/api/websocket/.*)$  {
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_http_version 1.1;
      set        $upstream http://portainer:9000$2;
      proxy_pass $upstream ;
  }
  location ~* ^(/apps/portainer)(/.*)$ {
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      set        $upstream http://portainer:9000$2;
      proxy_pass $upstream;
  }
}
EchoMike444
  • 449
  • 1
  • 3
  • 6
  • Thanks I did read that already. It doesn't help because it shows how to use a root location `/`, whereas I'm using a non-root location `/apps/portainer/`. – lonix Oct 24 '19 at 15:41
  • the point i dont see option in portainer to change the base url . – EchoMike444 Oct 24 '19 at 18:54
  • I'm not sure what you mean? But I noticed in other apps (e.g. wordpress, phpadmin) there is an option to change url so it works nicely with reverse proxy - you mean something like that? – lonix Oct 25 '19 at 07:31
  • yes , i talk about changing url . – EchoMike444 Oct 25 '19 at 17:27
  • i updated my response – EchoMike444 Oct 26 '19 at 17:56
  • Your way works because you don't have a variable in `proxy_pass`. I need the variable to be sure nginx doesn't fail when the upstream is down. See [here](https://stackoverflow.com/a/46232790/9971404) for example. Appreciate the effort though! – lonix Oct 28 '19 at 09:56
  • variables are here .... – EchoMike444 Oct 28 '19 at 15:58
  • I didn't check that, but I'm sure it works, and thanks!.... but.... using regex for location is not recommended practice - it means every request will undergo regex. I think if you need to urgently fix a problem, then regex is a reasonable approach, but to run it in production for every request is a very heavy cost :-) I think many people will benefit from this approach though, in the right circumstances. – lonix Oct 28 '19 at 16:46
  • I'm beginning to think nginx is too painful, maybe traefik is more modern and easy. – lonix Oct 28 '19 at 16:47
  • For `portainer` you don't care , this is a administration tool , so usage will always be very low if you compare to a public facing website . – EchoMike444 Oct 28 '19 at 18:08
  • But if the server has other services as well (e.g. wordpress, etc.) then that regex will be processed all the time. I have about 5 services in the server block, so that regex is heavy. It would be okay if you have portainer by itself in the server - in that case the regex doesn't matter, you're right. – lonix Oct 30 '19 at 11:05
  • except if you have 2 server name configuration on the same ngnix , one for public facing and other for admin , private facing – EchoMike444 Oct 30 '19 at 14:55