lucaslorentz / caddy-docker-proxy

Caddy as a reverse proxy for Docker
MIT License
2.82k stars 168 forks source link

[question] suggested method to proxy domain path versus caddy wiki #227

Closed zilexa closed 3 years ago

zilexa commented 3 years ago

The documentation suggests the following to proxy domain path (mydomain.tld/path) to container root:

Proxying domain path to container root

caddy: example.com
caddy.route: /source/*
caddy.route.0_uri: strip_prefix /source
caddy.route.1_reverse_proxy: {{upstreams}}

This works (tested it on firefox-sync server as the container is not very picky, does not have a webUI).

Now I tested other containers: Syncthing webui, OnlyOffice Documentserver and Bitwarden_rs. They do not work.. syncthing gives me a plain text version of the webUI, Bitwarden_rs only shows the plain text word "bitwarden" and onlyoffice redirects from mydomain.tld/office to mydomain.tld/welcome.

These containers probably do not support running from a subfolder. Is there a way to force them to work?

I noticed: Caddy wiki has an article: https://caddy.community/t/the-subfolder-problem-or-why-cant-i-reverse-proxy-my-app-into-a-subfolder/8575 Suggesting the use of header Location combined with reverse proxy or to use replace_response. Unfortunately, no examples are provided, documentation is quite limited (I really prefer yours). Can you perhaps point me in the right direction to make this work?

francislavoie commented 3 years ago

Generally the best approach is to just use a subdomain for each of those apps. Many apps were just not designed to be run in a subpath, and it's not worth going down the rabbithole of trying to replace parts of the responses to work around it.

Also FYI you can use handle_path instead of route here, which has implicit strip_prefix behaviour - saves you a line. https://caddyserver.com/docs/caddyfile/directives/handle_path

zilexa commented 3 years ago

Ha, now I have funny behaviour. With 2 containers adjusted:

    labels:
      caddy: $DOMAIN
      caddy.handle_path: /firefoxsync
      caddy.reverse_proxy: "{{upstreams 5000}}"
      caddy.tls: $EMAIL

and:

    labels:
      caddy: $DOMAIN
      caddy.handle_path: /firefoxsync
      caddy.reverse_proxy: "{{upstreams 5000}}"
      caddy.tls: $EMAIL

Now when I go to https://$DOMAIN/firefoxsync I get the Syncthing webUI (fully working though). It also fully works at https://$DOMAIN/syncthing.

I tried to isolate caddy configs as in your example caddy_0 for all labels of the first container, caddy_1 for all labels of the second container etc. but now, /syncthing works, all others like /firefoxsync also load syncthing but don't load the full page.

I am trying to switch to subfolders completely from a security perspective: obscuring my exposed services, by not having a public subdomain. Perhaps it's just a nice-to-have, but at least to bot will scan any service, as there is nothing runnning on https://mydomain.tld or subdomains.

francislavoie commented 3 years ago

You still need the * on the matcher, and reverse_proxy needs to be inside of handle_path.

I am trying to switch to subfolders completely from a security perspective: obscuring my exposed services, by not having a public subdomain. Perhaps it's just a nice-to-have, but at least to bot will scan any service, as there is nothing runnning on mydomain.tld or subdomains.

Frankly, security by obscurity is a bit of a myth. You're not gonna gain much from that. Just make sure people have proper passwords for your services and make sure you keep things updated, and you'll be fine. Don't overcomplicate it.

zilexa commented 3 years ago

Thanks, now I have a few working as long as I use a / at the end:

I see now why everyone just sticks to subdomains!

What is strange though: in Portainer, the log, shows a caddy file that has several labels that belong to one of the services, nested higher in the hierarchy. I am trying to copy the caddyfile from the log to show you.

francislavoie commented 3 years ago

Thanks, now I have a few working as long as I use a / at the end:

Just use a matcher like /firefoxsync*

zilexa commented 3 years ago

Thanks it works without slash now except for syncthing webui. The remaining question I have. With this in my Compose:

Should the Caddy file look like this? Labels for onlyoffice or bitwarden for example are not nested within, this means some labels will be applied to all. This probably makes sense as now I do everything via a single domain:

services:
  firefox:
    (...)
    labels:
      caddy_1: $DOMAIN
      caddy_1.handle_path: /firefoxsync*
      caddy_1.handle_path.reverse_proxy: "{{upstreams 5000}}"
      caddy_1.tls: $EMAIL
  bitwarden:
    (...)
    labels:
      caddy_2: $DOMAIN
      caddy_2.handle_path: /bitwarden*
      caddy_2.handle_path.reverse_proxy: "{{upstreams 80}}"
     # caddy2.handle_path.reverse_proxy_2: "/notifications/hub/negotiate {{upstreams 80}}"
     # caddy2.handle_path.reverse_proxy_3: "/notifications/hub {{upstreams 3012}}"
      caddy_2.tls: $EMAIL
      caddy_2.encode: gzip
      caddy_2.header.X-XSS-Protection: '"1; mode=block;"'
      caddy_2.header.X-Frame-Options: "DENY"
      caddy_2.header.X-Content-Type-Options: "none"
  syncthing:
    (...)
    labels:
      caddy_3: $DOMAIN
      caddy_3.handle_path: /syncthing*
      caddy_3.handle_path.reverse_proxy: "{{upstreams 8384}}"
      caddy_3.tls: $EMAIL
  onlyoffice:
    (...)
    labels:
      caddy_5: $DOMAIN
      caddy_5.handle_path: /office*
      caddy_5.handle_path.reverse_proxy: "{{upstreams 80}}"
      caddy_5.tls: $EMAIL
      caddy_5.file_server: ""
      caddy_5.encode: gzip
      caddy_5.header.X-Content-Type-Options: "nosniff"

Caddyfile from log:

mydomain.tld {
        encode gzip
        file_server
        handle_path /bitwarden* {
                reverse_proxy 172.26.0.3:80
        }
        handle_path /firefoxsync* {
                reverse_proxy 172.26.0.4:5000
        }
        handle_path /office* {
                reverse_proxy 172.26.0.6:80
        }
        handle_path /syncthing* {
                reverse_proxy 172.26.0.5:8384
        }
        header {
                X-Content-Type-Options none
                X-Content-Type-Options nosniff
                X-Frame-Options DENY
                X-XSS-Protection "1; mode=block;"
        }
        tls mydomain@mydomain.tld
}
francislavoie commented 3 years ago

That's correct. If you want header only for that one site, then you should put them inside handle_path. And remove file_server, it's probably not useful for you.

francislavoie commented 3 years ago

This seems resolved (see https://caddy.community/t/classic-subfolder-issues-i-read-the-wiki/11935), so I'll close it.