Reverse proxy configuration examples


#1

If you want to run OctoPrint behind a reverse proxy such as Nginx, HAProxy or Apache's mod_proxy you can find some configuration examples here.

Nginx

For Nginx the basic forwarding configuration is something like this:

    worker_processes  1;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include            mime.types;
        default_type       application/octet-stream;
        sendfile           on;
        keepalive_timeout  65;

        map $http_upgrade $connection_upgrade {
            default upgrade;
            '' close;
        }
  
        upstream "octoprint" {
            server 127.0.0.1:5000;
        }
    
        upstream "mjpg-streamer" {
            server 127.0.0.1:8080;
        }
    
        server {
            listen       80;
            server_name  localhost;
            
            location / {
                proxy_pass http://octoprint/;
                proxy_set_header Host $http_host;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Scheme $scheme;
                proxy_http_version 1.1;

                client_max_body_size 0;    
            }

            location /webcam/ {
                proxy_pass http://mjpg-streamer/;
            }

            # redirect server error pages to the static page /50x.html
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }

:warning: Warning

Be extra sure to include proxy_http_version 1.1 or the web socket connection will fail.

If you want to serve OctoPrint on a different base URL than / (e.g. /octoprint/), you'll need to adjust its location definition slightly by changing the location path itself, the proxy_pass target and adding the X-Script-Name header:

    location /octoprint/ {
        proxy_pass http://octoprint/; # make sure to add trailing slash here!
        proxy_set_header Host $http_host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header X-Script-Name /octoprint;
        proxy_http_version 1.1;

        client_max_body_size 0;    
    }

HAProxy

If you just want to run OctoPrint on the server root of the reverse proxy with mjpg-streamer running under /webcam, the following configuration is sufficient:

global
        maxconn 4096
        user haproxy
        group haproxy
        daemon
        log 127.0.0.1 local0 debug

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        retries 3
        option redispatch
        option http-server-close
        option forwardfor
        maxconn 2000
        timeout connect 5s
        timeout client  15min
        timeout server  15min

frontend public
        bind *:80
        use_backend webcam if { path_beg /webcam/ }
        default_backend octoprint

backend octoprint
        option forwardfor
        server octoprint1 127.0.0.1:5000

backend webcam
        reqrep ^([^\ :]*)\ /webcam/(.*)     \1\ /\2
        server webcam1  127.0.0.1:8080

If you want to make it run on a different base URL, you'll need to instruct HAProxy to send a X-Script-Name header with each forwarded request to make OctoPrint generate correct URLs on its pages:

backend octoprint
  reqrep ^([^\ :]*)\ /octoprint/(.*)  \1\ /\2
  reqadd X-Script-Name:\ /octoprint
  option forwardfor
  server octoprint1 127.0.0.1:5000

If you also want to run it SSL encrypted with HAProxy being the SSL terminator, you should also send a header of X-Scheme with each forwarded request to indicate https requests. You can configure this in the backend section like this:

backend octoprint
  ...
  reqadd X-Scheme:\ https if { ssl_fc }
  ...

Apache

:warning: Not recommended

Apache is somewhat heavy weighted compared to other options, and the configuration is also a bit messy. If possible it's highly recommended to rather use Nginx or haproxy.

For Apache (with mod_proxy, mod_proxy_http, mod_proxy_wstunnel and mod_headers enabled) the basic configuration is something among these lines:

<Location />
  ProxyPass http://<myOctoPrintHost>:5000/
  ProxyPassReverse http://<myOctoPrintHost>:5000/

  RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} =websocket [NC]
  RewriteRule .* ws://<myOctoPrintHost>%{REQUEST_URI} [P,L]
</Location>

or with https:

<Location />
  RequestHeader set X-SCHEME https
  ProxyPass http://<myOctoPrintHost>:5000/
  ProxyPassReverse http://<myOctoPrintHost>:5000/

  RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} =websocket [NC]
  RewriteRule .* ws://<myOctoPrintHost>%{REQUEST_URI} [P,L]
</Location>

If you want to use a different base URL, the configuration will be slightly different:

<Location /octoprint/>
  RequestHeader set X-SCRIPT-NAME /octoprint/
  ProxyPassReverse http://<myOctoPrintHost>:5000/

  RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} =websocket [NC]
  RewriteRule /octoprint/(.*) ws://<myOctoPrintHost>/$1 [P,L]
  RewriteCond %{HTTP:UPGRADE} !=websocket [NC]
  RewriteRule /octoprint/(.*) http://<myOctoPrintHost>/$1 [P,L]
</Location>

If you also want to use https:

<Location /octoprint/>
  RequestHeader set X-SCRIPT-NAME /octoprint/
  RequestHeader set X-SCHEME https
  ProxyPassReverse http://<myOctoPrintHost>:5000/

  RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} =websocket [NC]
  RewriteRule /octoprint/(.*) ws://<myOctoPrintHost>/$1 [P,L]
  RewriteCond %{HTTP:UPGRADE} !=websocket [NC]
  RewriteRule /octoprint/(.*) http://<myOctoPrintHost>/$1 [P,L]
</Location>

#2

I have some questions. Am I correct in assuming that in your example nginx and octoprint are running on the same box?

I am trying to get nginx running on a 2nd box to rev-proxy my octopi box and while it is indeed working it is only proxying the HTML and im am kinda stuck as to why.


#3

Yes. If things are running on a different box, you'll have to substitute 127.0.0.1:5000 accordingly.


#4

Thank you for that. I assumed as much. I am still having issues - its like the java isnt getting through the proxy. All I am getting is straight HTML. Im sure I have overlooked something simple, but I for the life of me can not seem to figure out what it is.

This is what I am getting through nginx:


#5

Have you put it under a different base URL (eg /octoprint/)? If so, you need to tell OctoPrint about that so it can generate the correct URLs.

If not I'd suggest to check the network tab and the js error console, try to figure out from where it's trying to load stuff from which is failing and then cross reference that with my config.


#6
location /octo {
proxy_pass http://192.168.0.84/;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Script-Name /octo;
proxy_http_version 1.1;
client_max_body_size 0;
}

This is what i got as a location block from octoprint. Im a bit confused about the rest.


#7

Try /octo/ instead of /octo. Maybe there's an issue with base URLs not ending in a slash - I have to admit that I never tested with those.


#8

Thank you very much for taking the time with this. Yes I realized with how old your original post was and had no comments that this might not be something others have done.

I am just sandboxing right now- but the plan is to have an nginx in the DMZ of my home network and use it as the jumping off point to everything - including my octoprint install.

So - the change you suggested did indeed bring me a lot closer to an answer.


#9

I had some hang up with the webcam, but I think I was able to get that working with a full URL setting in octoprint.

The only remaining issue is the page is taking VERY long to initially load.

The cam feed doesnt show up and I can not click the login button for 45-60 seconds after I try to reach the page. Anyone have any ideas why it is taking so long to load and how I can speed it up.

I currently have both on an internal network segment so networking speed is not the issue. Im at a bit of a loss.


#10

As am I. Normally I'd say either network latencies or it's a first time load, but if it stays slow on repeated reloads something else is off. If possible, try loading without the reverse proxy in between, to rule that out as the problem.


#11

I am sure it is not latency. I am on the same small subnet and do not have much other traffic.

I have loaded it up with out nginx in the middle and it is super fast per usual.

WITH nginx doing rev proxy octoprint loads quickly - it is just the cam and login button drop down that take a long time to load.

Once the cam loads and I log in everything is super fast as it is with nginx out of the picture.


#12

This is just a guess again, but it sounds like the initial page initialization might be taking up quite some time, causing the JS not to bind (and hence the login button to not be "armed"). When you disable the webcam, do you get the same issue? Just to rule out that it's the webcam stream through nginx somehow blocking any kind of needed request for full page initialization...


#13

I like your thought process.

With webcam disabled it still takes "a long time" for the login button to "arm".


#14

Next step will be a deep dive into the JS error console and the Network tab I fear. Something's hanging. Oh, also - same issue in safe mode?


#15

Same issue in safe mode. just tried it.

There are for sure console errors :frowning:


#16

Looks like it isn't connecting via the websocket and falling back on a long poll transport, and running into timeout issues with that.

The question is why it's not connecting via proper websocket in the first place, the Network tab might have the answer to that.


#17

I can see the problem in the network tab, but im getting near the limit of my webapp knowledge


#18

Hm, nope, the problem is higher up. Or at least I'd expect it to be higher up. The first thing that happens on socket initialization is a request to sockjs/info (IIRC), then a websocket will be attempted to be opened, then if that fails it's a fallback to various long polling approaches. Here I see an open websocket :face_with_raised_eyebrow: and a failed attempt to use the eventsource backend.

Frankly, this confuses me :wink:


#19

well - good. because I am confused by it also.

This being a current sandbox env I am throwing the kitchen sink at it.

I took the stack-overflow advice and changed the owner of the /var/lib/nginx to the nginx user who is running the worker process.

The /var/cache/nginx dir was already owned by the nginx user.

I also changed the:

proxy_buffers 8 1024k; proxy_buffer_size 1024k;

all to no current avail. I have not totally broken nginx though - so I guess that is a good thing.


#20

I have read some stack over flow threads and searched around to no avail - these seem to be the errors that are making it hang