nextcloud / documentation

📘 Nextcloud documentation
https://docs.nextcloud.com
Other
489 stars 1.72k forks source link

redirect /.well-known/ to correct port in nginx #899

Open macmeck opened 5 years ago

macmeck commented 5 years ago

Currently, the documentation for service discovery in nginx proposes to redirect /.well-known/ to proper paths.

    location = /.well-known/carddav {
      return 301 $scheme://$host/remote.php/dav;
    }
    location = /.well-known/caldav {
      return 301 $scheme://$host/remote.php/dav;
    }

This only works for the standard ports but fails if Nextcloud runs on a different port. A dynamic port parameter should be added to the redirect but I did not yet find out how.

MorrisJobke commented 5 years ago

@josh4trunks Do you have an idea for this? This is basically then the case when there is a reverse proxy infront of Nginx as well :/

josh4trunks commented 5 years ago

I'm confused what a proxy in front of NGINX has to do with return 301. Isn't a return 301 pretty much handled by the client doing a new request for the updated URI.

@macmeck does this work for your scenario? return 301 $scheme://$host:PORT/remote.php/dav;

MorrisJobke commented 5 years ago

I'm confused what a proxy in front of NGINX has to do with return 301. Isn't a return 301 pretty much handled by the client doing a new request for the updated URI.

It is because the Nginx port is a different one, than the one of the reverse proxy in front of it. Thus the redirect goes to the port of Nginx instead of the reverse proxy. See https://github.com/nextcloud/server/issues/11789 for more details.

josh4trunks commented 5 years ago

ahh, ok makes sense. i assume handcoding it like i propose resolves this

MorrisJobke commented 5 years ago

i assume handcoding it like i propose resolves this

Yes - was reported to solve the issue in the original and linked on in the server repo.

macmeck commented 5 years ago

@josh4trunks , yes, hardcoding the redirect port works. But is there a way to do this dynamically?

josh4trunks commented 5 years ago

@macmeck if there is a reverse proxy in front of NGINX, NGINX would not know what port that reverse proxy is using. There is the PROXY Protocol, which allows the reverse proxy to forward additional information about the client connection including client IP:port and server (reverse proxy) IP:port. https://www.haproxy.com/blog/haproxy/proxy-protocol/

NGINX does support this, but currently does not save the server IP or port to a variable. See a feature request here. https://trac.nginx.org/nginx/ticket/1206

There are ways to hack this, like forwarding an HTTP header from the reverse proxy, then mapping that in NGINX. This is protocol specific, and not as efficient as if we had full PROXY Protocol support.

map $http_x_forwarded_proto $host_port {
    default 80;
    https 443;
}
macmeck commented 5 years ago

Hm, I just realized that the setup is even worse. Port forwarding is already done by the router upfront. So the machine running nginx and Nextcloud already gets the request on port 443.

So to fix this, we need to find out the port the client used in its initial request.

josh4trunks commented 5 years ago

@macmeck I'm not sure what you are asking me to help with? I though I was helping with deficiencies with the documentation, but it sounds like you need help with your specific setup.

enoch85 commented 5 years ago

Another use case:

I use Nginx Reverse Proxy with Apache2 as backend. Nginx talks to the internet on port 443 but on port 80 with the Apache backend.

I tried adding the 301 Redirect stuff suggested in issues here on Github in the Apache2 vhost on the backend, but it didn't help.

I'm very interested in how to solve this issue.

josh4trunks commented 5 years ago

@enoch85 We are talking about the NGINX configuration documentation here. If you are doing your redirect in Apache2 that wouldn't be using the NGINX docs.

Also, I am fairly certain my earlier post mentioning PROXY Protocol could be implemented with NGINX > Apache2. With PROXY Protocol Apache2 could always know what port the client is connecting to without any tricks.

enoch85 commented 5 years ago

With PROXY Protocol Apache2 could always know what port the client is connecting to without any tricks.

Yeah, never was an issue before. Seeing this in my "Overview" since 14.0.something.

josh4trunks commented 5 years ago

@enoch85 Your redirect is in NGINX or Apache2? You already can solve it using hardcoded ports in NGINX. I can't really help with Apache2, I'm pretty much a n00b at apache.

enoch85 commented 5 years ago

@josh4trunks This is how it looks like basically:

Nginx listens:

listen 192.168.4.201:443 ssl http2;

forwards to Apache2:

server_name cloud.techandme.se;
set $upstream 192.168.4.111;80
      location / {
                proxy_pass_header Authorization;
                proxy_pass http://$upstream;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP  $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_http_version 1.1;
                proxy_set_header Connection "";
                proxy_buffering off;
                proxy_request_buffering off;
        client_max_body_size 0;
                proxy_read_timeout  36000s;
                proxy_redirect off;
                proxy_ssl_session_reuse off;
        }

I tried setting this in the Apache2 vhost:

Redirect 301 /.well-known/carddav https://cloud.techandme.se/remote.php/dav
Redirect 301 /.well-known/caldav  https://cloud.techandme.se/remote.php/dav
Redirect 301 /.well-known/webdav  https://cloud.techandme.se/remote.php/dav
josh4trunks commented 5 years ago

@enoch85 And the issue is redirts to /.well-known/* go to port 80? Redirect 301 /.well-known/carddav https://cloud.techandme.se:443/remote.php/dav Would this not help?

enoch85 commented 5 years ago

@josh4trunks Nope, sorry :( Thanks for trying though.

I tried http as well and no avail.

I don't know what the issue is, everything is working correctly, but the status checks says that it doesn't.

josh4trunks commented 5 years ago

ohh, if it's just the status check, I don't know exactly how that works. But I assume the PHP Nextcloud code needs to know what protocol (http/https), domain, and port to check. Maybe it doesn't know.

enoch85 commented 5 years ago

Well, the issue for me is that check won't work then as it will always produce an error due to the fact that the proxy runs on 443 and the backend on 80.

macmeck commented 5 years ago

Don't we have this issue always if Nextcloud listens on standard http/https ports but sits behind a router that does port forwarding? So the router receives on https://some.domain:12345 from the Internet and forwards internally to https://nextcloud.lan:443? If I'm not mistaken, the redirects would now point to https://some.domain:443 which would not work, right?

enoch85 commented 5 years ago

This issue is solved for me with this.

macmeck commented 5 years ago

@enoch85, I think I do not fully understand the solution here. Do you suggest to replace the dynamic $scheme by static https:// ? In this case, this is not a working solution for the issue since Nextcloud is indeed accessed via https (no https offloading upfront) which is correctly being resolved by $scheme.

The issue behind a router that does port forwarding will be that from outside the system needs to be accessed via a non-standard port which is not inserted in the redirect by now.

bekl101 commented 5 years ago

Same promblem here. I use the 15.0 RC2 and recieve the message ".well-known" problems. I use a forward-proxy (nginx) in front of the nextcloud-server. Everything works fine before, but now i can´t configure carddav or caldav on an iPad. Nothing in my server installation, neither forward-proxy nor nextcloud-server, changed exept nextcloud version. Is there any change in Nextcloud which can cause this problem?

MorrisJobke commented 5 years ago

I guess the hardcoding still makes sense, or am I completely wrong? See #1114

pgnd commented 5 years ago

I've NC 17 on nginx 1.17.1

I'm behind a proxy atm; this is just a simple site.

I've changed my nginx config

    location = /.well-known/carddav {
-       return 301 $scheme://$host/remote.php/dav;
+       return 301 https://$host/remote.php/dav;
    }
    location = /.well-known/caldav {
-       return 301 $scheme://$host/remote.php/dav;
+       return 301 https://$host/remote.php/dav;
    }

still, currrently,

Your web server is not properly set up to resolve "/.well-known/caldav". Further information can be found in the documentation. Your web server is not properly set up to resolve "/.well-known/carddav". Further information can be found in the documentation.

djamolsky commented 4 years ago

@pgnd, I have a similar setup (not proxy but using NAT dest). Hardcoding the external port makes the job:

location = /.well-known/carddav {
      return 301 $scheme://$host:externalport/remote.php/dav;
 }
location = /.well-known/caldav {
      return 301 $scheme://$host:externalport/remote.php/dav;
}