Closed tylerball closed 5 years ago
The websocket protocol is hard coded in the javascript part of forked-daapd. In order to connect with wss:// you would need: https://github.com/chme/forked-daapd/commit/08584a87f76b1cf949e39ed7529c72cbcad35c79 (plus rebuilding the web interface with nodejs).
With this change, the web interface should connect with wss:// to the reverse proxy and the reverse proxy would still connect with ws:// to forked-daapd (similar how it works with http/https).
I did start working on support for https/wss directly in forked-daapd (e. g. with self signed certificates) in: https://github.com/chme/forked-daapd/commits/https. If i remember correctly it did work fine, but is in need of some polishing.
Ah the rebuilding step is what I was missing.
if (window.location.protocol == 'https:') {
protocol = 'wss://'
}
This seems like a way better approach without the need to add configuration. Would you accept a PR with just this change?
Yes, the change is fine. Feel free to open a PR.
Merged with #669
@tylerball I am trying to accomplish a similar setup. Could you share your reverse proxy setup?
I keep getting
reconnecting-websocket.js:227 WebSocket connection to 'wss://XXXXXXX.XX:3688/' failed: WebSocket is closed before the connection is established"
Did you proxy ports 3688 and 3689 separately?
I have the same problem and the same question Getting the same error
@tylerball I am trying to accomplish a similar setup. Could you share your reverse proxy setup? I keep getting
reconnecting-websocket.js:227 WebSocket connection to 'wss://XXXXXXX.XX:3688/' failed: WebSocket is closed before the connection is established"
Did you proxy ports 3688 and 3689 separately?
Were you able to solve this somehow?
Nope, I am still hoping something comes up. I spent quite some time trying different things in nginx to no avail.
@Porco-Rosso - I'm actually using Traefik.
I had the problem you're having, then forwarded the 3688
port to the Traefik host on the router. Make sure you did that.
This lead me to another error:
WebSocket connection to 'wss://xxxxxxxx.xxx:3688/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
I tried also forwarding this port directly from the router to the host with forked-daapd
- but same result
Also tried using https://www.websocket.org/echo.html and other sites - still getting the same result
I'm still clueless
Actually - made some progress:
entryPoint
for port 3688 - and a service - sending it forward to the host itselfNow, I'm getting:
WebSocket connection to 'wss://xxxxxxx:3688/' failed: Error during WebSocket handshake: Unexpected response code: 404
I tried running NMAP to the daapd host and I see only this port is open 3689/tcp open rendezvous
,
no 3688
@chme I really tried everything to use NGINX as a reverse proxy to access forked-daapd via HTTPS. The web interface is working fine but i can't get the websocket connection to work. Does anybody have a example configuration file or something.
I've tried and failed too. Maybe just running the web UI separately so you can change the WebSocket endpoint?
@larrybolt When proxying with NGINX the webinterface tries to connect to
wss://example.com:3688/
instead of
ws://example.com:3688/
and this always fails with SSL_ERROR_RX_RECORD_TOO_LONG
according to my console. Trying with websocat
also yields WebSocketError: TLS failure
. I just can"t make any sense of it. Appending my .conf for reference.
server {
listen 443 ssl;
server_name example.com;
allow x.x.x.x/xx;
deny all;
ssl_certificate /etc/letsencrypt/live/***/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/***/privkey.pem;
#include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/chain.pem;
location / {
proxy_pass http://localhost:3689;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
@chme Do you have an example config that shows how to make this work?
I figured it out... This may not be 100% right but it works for me...
server {
server_name music.example.com;
location / {
proxy_pass http://music.home.example.com:3689;
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_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/media.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/media.example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
server_name music.example.com;
location / {
proxy_pass http://music.home.example.com:3688;
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_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
listen 33688 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/media.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/media.example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = music.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name music.example.com;
return 404; # managed by Certbot
}
On my firewall I forward port 443 to port 80 internally and 3688 to port 33688 internally. Need to use a different port since I'm running nginx and forked-daapd on the same host.
also - add geo based auth...
geo $authentication {
default "Authentication required";
127.0.0.1 "off";
192.168.1.0/24 "off";
}
server {
server_name music.example.com;
location / {
auth_basic $authentication;
auth_basic_user_file /etc/nginx/.htpasswd;
.
.
Thanks for the contribution @p3ck, will give it a try sometime soon.
Thank you @p3ck for pointing me in the right direction. I also figured out how to make it work without using a port redirect.
src/websocket.c
to bind the websocket to localhost only by adding info.protocols = "127.0.0.1";
@@ -388,6 +388,7 @@
memset(&info, 0, sizeof(info));
info.port = websocket_port;
info.protocols = protocols;
+ info.iface = "127.0.0.1";
if (!cfg_getbool(cfg_getsec(cfg, "general"), "ipv6"))
info.options |= LWS_SERVER_OPTION_DISABLE_IPV6;
info.gid = -1;
Then I used @p3ck nginx configuration provided above, but now you can bind nginx to the same websocket port as forked-daapd on your local network interface and redirect it to localhost.
server {
listen X.X.X.X:3688 ssl;
server_name music.example.com;
location / {
proxy_pass http://127.0.0.1:3688;
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_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
ssl_certificate /etc/letsencrypt/live/media.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/media.example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
info.protocols
for the websocket.Edit:
I created a draft pull request #1143.
Sorry for digging out this older issue. Maybe someone is interested in reverse proxy solution using apache2.
Here's my working owntone/apache2 config:
owntone.conf (restart of owntone required)
# Websocket interface to bind listener to (e.g. "eth0"). Default is
# disabled, which means listen on all interfaces.
websocket_interface = "127.0.0.1"
apache2/ports.conf
<IfModule ssl_module>
Listen 443
# you have to bind port 3688 explicitly to an IP; not 0.0.0.0
Listen 10.1.1.30:3688
</IfModule>
apache2/sites-enabled/vhost-owntone.conf
<VirtualHost *:80>
ServerName owntone.domain.xy
RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^127\.0\.0\.1$
RewriteRule ^/(.*) https://owntone.domain.xy/$1 [R=301,L]
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName owntone.domain.xy
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:3689/
ProxyPassReverse / http://127.0.0.1:3689/
SSLEngine on
SSLCertificateFile /path/to/your/fullchain.pem
SSLCertificateKeyFile /path/to/your/privkey.pem
</VirtualHost>
</IfModule>
<IfModule mod_ssl.c>
<VirtualHost *:3688>
ServerName owntone.domain.xy
<IfModule mod_alias.c>
RedirectMatch 403 favicon.ico
</IfModule>
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteRule /(.*) ws://127.0.0.1:3688/$1 [P,L]
RewriteRule /(.*) http://127.0.0.1:3688/$1 [P,L]
SSLEngine on
SSLCertificateFile /path/to/your/fullchain.pem
SSLCertificateKeyFile /path/to/your/privkey.pem
</VirtualHost>
</IfModule>
And of course port has to be permitted for localhost in firewall-settings.
Hope, i haven't forgotten anything.
forked-daapd is working great for me, the music solution I've been looking for after trying many.
I've been experimenting with using traefik to reverse proxy to my forked-daapd instance so I can serve it behind
https
to the outside world. This works fine except for the websocket connection, which is hardcoded withws://
and is blocked by mixed-content restrictions. Would it be possible to make this configureable? I took a shot at it but I'm not a C developer and I'm clearly missing something.