AdrienPoupa / docker-compose-nas

Simple Docker Compose NAS featuring Sonarr, Radarr, Prowlarr, Jellyfin, qBittorrent, PIA VPN and Traefik with SSL support
893 stars 116 forks source link

Different path prefix for heimdall #6

Closed RogueGhost93 closed 1 year ago

RogueGhost93 commented 1 year ago

First of all thank you for this, it works like a charm! just fyi I raplaced cloudflare part with

changing path prefix for heimdall to

Thanks!

AdrienPoupa commented 1 year ago

Hello!

and it also works like a charm, the only difference is that you initially have to have domain pointing to your public IP and open the ports, once you get the certificate you can point your domain back to local IP and close the ports.

hm, why? With the DNS01 challenge, you don't need to open any ports and it works without pointing to a public IP. I understand not wanting to use CloudFlare, but there's many different providers that support this challenge: https://go-acme.github.io/lego/dns/

Overall, this seems like a much more complicated and less secure way to do things.

traefik.http.routers.heimdall.rule=(Host(${HOSTNAME}) && PathPrefix(/heimdall) || PathPrefix(/heimdall)) turns into 404, any idea why or how to fix that?

If you want Heimdall to be accessible at HOSTNAME/heimdall, this seems like the right configuration indeed. From what I saw, additional tinkering is required as Heimdall does not support this out of the box (subfolder method is currently not supported: https://github.com/linuxserver/Heimdall#reverse-proxy). This will probably help: https://github.com/linuxserver/reverse-proxy-confs and especially https://github.com/linuxserver/reverse-proxy-confs/blob/master/heimdall.subfolder.conf.sample

Alternatively, you may have some luck trying out a custom Traefik middleware, similar to what was done for qBittorrent:

      # https://community.traefik.io/t/middleware-to-add-the-if-needed/1895/19
      - traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.regex=(^.*\/qbittorrent$$)
      - traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.replacement=$$1/
      - traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.permanent=false

Let me know if it works!

And if one were to add nextcloud or photoprism or similar, how would that same path be replaced? just like

  • traefik.http.routers.heimdall.rule=(Host(${HOSTNAME}) && PathPrefix(/nextcloud) || PathPrefix(/nextcloud))

Yes, just make sure to replace the router name by the application name (it should read traefik.http.routers.nextcloud.rule)

Since heimdall is not working why would nextcloud and would you have any idea how to fix it and make nextcloud/heimdall stil accessible? My idea is to add a few more services to this and make it one giant media stack.

That depends on the application. Some will fare better being in a subfolder. For example, the *arrs and Jellyfin will work, but only after specifying the base URL configuration.

Good luck!

RogueGhost93 commented 1 year ago

Yes, the reason was primarily to avoid using cloudflare since i already have some paid domains from No-IP and with No-IP dns challenge doesnt work as far as i know. Also, i really dont get those API keys from cloudflare xD

So, ive been experimenting with your setup all day and since this path prefix causes different issue from app to app I decided to use

AdrienPoupa commented 1 year ago

That's good to hear! I also saw this SO post relevant to your issue: https://stackoverflow.com/questions/65280910/traefik-v2-redirect-http-servername-foo-to-http-servernameport

Yes, the reason was primarily to avoid using cloudflare since i already have some paid domains from No-IP and with No-IP dns challenge doesnt work as far as i know.

What do you mean? Did you register a "real" (ie not a free subdomain) at No-IP and are using their admin panel to manage your DNS records?

If that is the case, then yes No-IP does not seem to be supported. Interestingly, it looks like you can run the challenges manually, maybe from a different Docker image: https://go-acme.github.io/lego/dns/manual/

The issue with your method is that auto renewal may not work until you open the ports again - not ideal.

I guess you could change your domain's DNS servers and point to CloudFlare or a different DNS provider that is supported by Lego if you wanted to automate your process.

RogueGhost93 commented 1 year ago

Yes im managing paid domains at no-ip and point them to whichever ip i want, sometimes public sometimes local ip. Yes, for renewal i would have to open the ports again. When subscription expires i might switch to cloudflare and make it how you originally intended but still keep the Host(container_name.)" alternative, it just works without any issues for any app.

You said if we use tailscale we will have to use it at home too, but, is there a way to add for example two different domains that would point to yur host? I just started with traefik so idk. Something like this

im not sure what || represents in traefik but if this would work then if you are controling two different domains you could easily have one for tailscale and one for local network. Would you know by any chance?

Intead of tailscale, you can run an open source project like https://github.com/Nyr/wireguard-install which installs a private vpn server, similar to PiVPN, although you would have to have that port open in order to connect to your server, which in my view in combination with geoIP block and fail2ban etc etc is safer than closed source tailscale. Just a thought for enthusiasts, tailscale is easier ofc.

AdrienPoupa commented 1 year ago

You are right, subdomains are easier and work fine. I just thought it would be cleaner to use subpaths for *arrs apps, but otherwise there's absolutely no drawbacks using those, in fact this is how most people do it from what I saw.

Yes, you can do this in Traefik and it should work for two domains. Let me know if it doesn't!

The alternative would be to rewrite the DNS record locally, so that if you are home the domain resolves to 192.168.x.x, and if you are out it does not. Adguard Home lets you do that. That was my initial approach, but I resorted to keeping Tailscale running on all my devices at all time, with the added benefit of getting an ad blocker on all my devices, anywhere ;)

You are right that there's many Tailscale alternatives. I guess I just fell in love with the product, it's so easy to use and well thought. The company really is developer friendly on top of that.

By the way, only the server code is closed source. If Tailscale ever goes rogue or I really wanted to only use open source software, I would use headscale, an OSS implementation of the server (similar to what Vaultwarden is to Bitwarden) with the added benefit of official client apps still working: https://github.com/juanfont/headscale

RogueGhost93 commented 1 year ago

I havent heard of headscale, thanks for that. Yes i was aware of rewriting DNS record locally as im using OPNsense (which also comes with adguar plugin) but most people arent so i think it would be easier if it was possible to just use two different domains, i will try and let you know!

RogueGhost93 commented 1 year ago

I created a domain at cloudflare to test these things out. Im using it with wildcard so my Host(container_name. setup can still work. However traefik is unable to generate certificates for some reason. Im getting this error:

level=error msg="Unable to obtain ACME certificate for domains \"heimdall.MYDOMAIN.COM\": unable to generate a certificate for the domains [heimdall.MYDOMAIN.COM]: error: one or more domains had a problem:\n[heimdall.MYDOMAIN.COM] [heimdall.MYDOMAIN.COM] acme: error presenting token: cloudflare: failed to create TXT record: Authentication error (10000)\n" providerName=myresolver.acme routerName=heimdall@docker rule="Host(heimdall.MYDOMAIN.COM)" ACME CA="https://acme-v02.api.letsencrypt.org/directory"

I also tried using their global API as it is suggested by lets encrypt https://doc.traefik.io/traefik/v1.6/configuration/acme/ CLOUDFLARE_EMAIL, CLOUDFLARE_API_KEY - The Global API Key needs to be used, not the Origin CA Key But then i get this error

level=error msg="Unable to obtain ACME certificate for domains \"heimdall.MYDOMAIN.COM\": unable to generate a certificate for the domains [heimdall.MYDOMAIN.COM]: error: one or more domains had a problem:\n[heimdallMYDOMAIN.COM] time limit exceeded: last error: read udp 172.18.0.16:41753->173.245.58.101:53: i/o timeout\n" ACME CA="https://acme-v02.api.letsencrypt.org/directory" providerName=myresolver.acme routerName=heimdall@docker rule="Host(heimdall.MYDOMAIN.COM)"

Domain name is pointing to my local IP, i havent tried with public IP and open ports as you said it should work this way too which made me buy one domain and try it out :D if i go to heimdall.MYDOMAIN.com it works just fine but the connection is insecure so i know the hostname works just fine, the problem is either API keys or something else with cloudflare or something else i cant think of. I would appreciate your help with this as im sure others would and will run into the same problem. Maybe my API are setup in a wrong way? Here are some screenshots from cloudflare but i do believe i set them up right.

Screenshot_20230310_185314

Screenshot_20230310_185237 bd.png) Screenshot_20230310_185258

I also tried to regenerate APIs Another error i get sometimes is this level=error msg="Unable to obtain ACME certificate for domains \"photoprism.MYDOMAIN.COM\": unable to generate a certificate for the domains [photoprism.MYDOMAIN.COM]: error: one or more domains had a problem:\n[photoprism.MYDOMAIN.COM] [photoprismMYDOMAIN.COM] acme: error presenting token: cloudflare: failed to create TXT record: Record already exists. (81057)\n" providerName=myresolver.acme ACME CA="https://acme-v02.api.letsencrypt.org/directory" rule="Host(photoprism.MYDOMAIN.COM)" routerName=photoprism@docker

But if i visit photoprism.mydomain.com it is still insecure, there is no certificate.

Thanks!

AdrienPoupa commented 1 year ago

Hi, it looks like the tokens were not created properly. The full documentation is here: https://go-acme.github.io/lego/dns/cloudflare/

Create a token with Zone / Zone / Read and Zone / DNS / Edit rights: image image

Then specify it in CLOUDFLARE_DNS_API_TOKENand CLOUDFLARE_ZONE_API_TOKEN. Don't forget to set your CLOUDFLARE_EMAIL too.

RogueGhost93 commented 1 year ago

I did make it exactly the same as in your screenshot, i suppose i use that one API key and populate those two variables with the same API basically. Just wanted to clarify there are not two different API keys involved.

However, i still get this error

level=error msg="Unable to obtain ACME certificate for domains \"calibreweb.MYDOMAIN.COM\": unable to generate a certificate for the domains [calibreweb.MYDOMAIN.COM]: error: one or more domains had a problem:\n[calibreweb.MYDOMAIN.COM] time limit exceeded: last error: read udp 172.22.0.9:58439->108.162.193.243:53: i/o timeout\n" ACME CA="https://acme-v02.api.letsencrypt.org/directory" providerName=myresolver.acme routerName=calibreweb@docker rule="Host(calibreweb.MYDOMAIN.COM)" Screenshot_20230310_201542 Screenshot_20230310_201557

Just to clarify, i have a container also listening on MYDOMAIN.COM without any subdomain, to make sure the wildcard is not the problem and i get the same error in both cases.

AdrienPoupa commented 1 year ago

Looks like a different error this time, you had Authentication error, now time limit exceeded so you may want to retry later or investigate if something is preventing Traefik from reaching the web.

RogueGhost93 commented 1 year ago

docker exec qbittorrent sh -c "ping 1.1.1.1" docker exec gluetun sh -c "ping 1.1.1.1" both work and ping just fine

but traefik cant ping for anything some reason docker exec traefik sh -c "ping 1.1.1.1" docker exec traefik sh -c "ping 8.8.8.8"

I had this same setup without dns challenge and it worked, all i did was add 3 variables to traefik, CF email CF APIs. And switched

- --certificatesresolvers.myresolver.acme.tlschallenge=true

for

im really confused at this point. Are you sure we are using exactly the same API key for both of those variables?

environment:
  - LETS_ENCRYPT_EMAIL=${LETS_ENCRYPT_EMAIL}
  - CLOUDFLARE_EMAIL=${CLOUDFLARE_EMAIL}
  - CLOUDFLARE_DNS_API_TOKEN=${CLOUDFLARE_DNS_API_TOKEN}
  - CLOUDFLARE_ZONE_API_TOKEN=${CLOUDFLARE_ZONE_API_TOKEN}
command:
  #- --api.dashboard=true
  - --providers.docker=true
  - --providers.docker.exposedbydefault=false
  - --entrypoints.web.address=:80
  - --entrypoints.web-secure.address=:443
  - --entrypoints.web.http.redirections.entryPoint.to=web-secure
  - --entrypoints.web.http.redirections.entryPoint.scheme=https
  - --entrypoints.web.http.redirections.entrypoint.permanent=true
  - --certificatesresolvers.myresolver.acme.dnschallenge=true
  - --certificatesresolvers.myresolver.acme.dnschallenge.provider=cloudflare
  #- --certificatesresolvers.myresolver.acme.tlschallenge=true
  - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
  - --certificatesresolvers.myresolver.acme.email=${LETS_ENCRYPT_EMAIL}
ports:
  - "80:80"
  - "443:443"
  #- "8080:8080"
volumes:
  - ${INSTALL_LOCATION}/config/letsencrypt:/letsencrypt
  - "/var/run/docker.sock:/var/run/docker.sock:ro"

.env LETS_ENCRYPT_EMAIL=myemail@provider.com CLOUDFLARE_EMAIL=myemail@provider.com CLOUDFLARE_DNS_API_TOKEN=xxx # note that these apis are the same CLOUDFLARE_ZONE_API_TOKEN=xxx # note that these apis are the same

EDIT: After turning off my network wide VPN i ran docker-compose down then up and now traefik gives this

level=error msg="Unable to obtain ACME certificate for domains \"radarr.MYDOMAIN.COM\": unable to generate a certificate for the domains [radarr.MYDOMAIN.COM]: failed to post JWS message: failed to sign content: failed to sign content: go-jose/go-jose: Error generating nonce: failed to get nonce from HTTP HEAD: Head \"https://acme-v02.api.letsencrypt.org/acme/new-nonce\": net/http: timeout awaiting response headers" ACME CA="https://acme-v02.api.letsencrypt.org/directory" routerName=radarr@docker rule="Host(radarr.MYDOMAIN.COM)" providerName=myresolver.acme

and this one

level=error msg="Unable to obtain ACME certificate for domains \"heimdall.MYDOMAIN.COM\": unable to generate a certificate for the domains [heimdall.MYDOMAIN.COM]: error: one or more domains had a problem:\n[heimdall.MYDOMAIN.COM] failed to initiate challenge: Post \"https://acme-v02.api.letsencrypt.org/acme/chall-v3/209812013857/cxos5g\": read tcp 172.25.0.19:43306->172.65.32.248:443: read: connection reset by peer\n" ACME CA="https://acme-v02.api.letsencrypt.org/directory" providerName=myresolver.acme routerName=heimdall@docker rule="Host(heimdall.MYDOMAIN.COM)"

However now traefik pings just fine docker exec traefik sh -c "ping 1.1.1.1"

EDIT2: AAAND they are obtained, somehow, the errors are still there but certificates too, i have no idea how or why.... Maybe, just maybe the reason could be something like this https://www.reddit.com/r/Traefik/comments/n9pjcz/how_to_increase_time_limit_when_generating_a/ I have all traffic to port 53 forwarded to AdGuard and then to Unbound so maybe thats why, even though that doesnt make any sense since the regular tls (no DNS01) challenge was working just fine....weird Im sorry to bother you, i saw on reddit you are trying to learn traefik so i just bombarded you :P

AdrienPoupa commented 1 year ago

It seems like Traefik's access to the web is flaky at best, possibly because of DNS issues as you suggested. I am glad it works now!

I am closing this since it is now resolved.