anthonyraymond / joal

An open source command line RatioMaster with an optional WebUI.
Apache License 2.0
593 stars 64 forks source link

Access behind reverse proxy #33

Closed gaglimax closed 6 years ago

gaglimax commented 6 years ago

Hi !

I open another issue because I try to access to the web UI behind a reverse proxy. To run joal, the command is : java -jar /opt/joal/jack-of-all-trades-2.1.3.jar --joal-conf=/opt/joal --spring.main.web-environment=true --server.port=7073 --joal.ui.path.prefix=joal --joal.ui.secret-token="test"

Now, if I visit http://x.x.x.x:7073/joal/ui/ though local network, it works with those parameters :

Now, if I set up a virtual host behind a reverse proxy :

<VirtualHost *:443>
    DocumentRoot "/var/www/html"
    ServerName joal.server.fr
    ServerAlias www.joal.server.fr

    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/joal-error.log
    CustomLog ${APACHE_LOG_DIR}/joal-access.log combined

    RewriteEngine On
    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteRule ^(.*)$ http://www.%{HTTP_HOST}$1 [R=301,L]

    <Directory /var/www/joal/>
        Options +FollowSymLinks -Indexes -MultiViews
        AllowOverride all
        Order allow,deny
        allow from all
    </Directory>

    ProxyPass / http://127.0.0.1:7073/joal/ui/
    ProxyPassReverse / http://127.0.0.1:7073/joal/ui/
    ProxyRequests Off

        Include /etc/letsencrypt/options-ssl-apache.conf
        SSLCertificateFile /etc/letsencrypt/live/joal.server.fr/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/joal.server.fr/privkey.pem
</VirtualHost>
</IfModule>

The web UI works but I've got this message in the right top corner :

The parameters are :

I don't know if it's possible to use it behind a reverse proxy with SSL encryption like but.

Thanks for your help :)

anthonyraymond commented 6 years ago

Joal himself does not support SSL so far. But i use mine behind an SSL enabled reverse proxy, which forward decrypted request to joal. Looking ar your conf you are doing the same thing.

I'll send you my nginx conf tonight. We are in almost the same configuration, expect that you are using apache as a reverse proxy.

If you want to investigate alone until tonight, here are things you may want to try:

gaglimax commented 6 years ago

I have tried to split http and websocket but it still can't reach the websocket. I will wait for your configuration, maybe I will understand something else.

I provide you my apache error log for joal :

[Fri Jun 22 15:00:23.245643 2018] [proxy:error] [pid 31377] (111)Connection refused: AH00957: HTTP: attempt to connect to 127.0.0.1:7073 (127.0.0.1) failed
[Fri Jun 22 15:00:23.245784 2018] [proxy_http:error] [pid 31377] [client x.x.x.x:port] AH01114: HTTP: failed to make connection to backend: 127.0.0.1
anthonyraymond commented 6 years ago
# If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the
# scheme used to connect to this server
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
  default $http_x_forwarded_proto;
  ''      $scheme;
}
# If we receive X-Forwarded-Port, pass it through; otherwise, pass along the
# server port the client connected to
map $http_x_forwarded_port $proxy_x_forwarded_port {
  default $http_x_forwarded_port;
  ''      $server_port;
}
# If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any
# Connection header that may have been passed to this server
map $http_upgrade $proxy_connection {
  default upgrade;
  '' close;
}
# Apply fix for very long server names
server_names_hash_bucket_size 128;
# Default dhparam
# Set appropriate X-Forwarded-Ssl header
map $scheme $proxy_x_forwarded_ssl {
  default off;
  https on;
}
gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
log_format vhost '$host $remote_addr - $remote_user [$time_local] '
                 '"$request" $status $body_bytes_sent '
                 '"$http_referer" "$http_user_agent"';
access_log off;
# HTTP 1.1 support
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
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 $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
# Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy "";
server {
    server_name _; # This is just an invalid value which will never trigger on a real hostname.
    listen 80;
    access_log /var/log/nginx/access.log vhost;
    return 503;
}
# joal.server.fr
upstream joal.server.fr {
          ## Can be connected with "data_default" network
          server 127.0.0.1:7073;
}
# Force SSL
server {
    server_name joal.server.fr;
    listen 80 ;
    access_log /var/log/nginx/access.log vhost;
    return 301 https://$host$request_uri;
}
server {
    server_name joal.server.fr;
    listen 443 ssl http2 ;
    access_log /var/log/nginx/access.log vhost;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS';
    ssl_prefer_server_ciphers on;
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_certificate /etc/nginx/certs/joal.server.fr.crt;
    ssl_certificate_key /etc/nginx/certs/joal.server.fr.key;
    ssl_dhparam /etc/nginx/certs/joal.server.fr.dhparam.pem;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/nginx/certs/joal.server.fr.chain.pem;
    add_header Strict-Transport-Security "max-age=31536000" always;
    include /etc/nginx/vhost.d/default;
    location / {
        proxy_pass http://joal.server.fr;
    }
}

# ws.joal.server.fr
upstream ws.joal.server.fr {
          ## Can be connected with "data_default" network
          server 127.0.0.1:7073;
}
# Force SSL
server {
    server_name ws.joal.server.fr;
    listen 80 ;
    access_log /var/log/nginx/access.log vhost;
    return 301 https://$host$request_uri;
}
server {
    server_name ws.joal.server.fr;
    listen 443 ssl http2 ;
    access_log /var/log/nginx/access.log vhost;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS';
    ssl_prefer_server_ciphers on;
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_certificate /etc/nginx/certs/ws.joal.server.fr.crt;
    ssl_certificate_key /etc/nginx/certs/ws.joal.server.fr.key;
    ssl_dhparam /etc/nginx/certs/ws.joal.server.fr.dhparam.pem;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/nginx/certs/ws.joal.server.fr.chain.pem;
    add_header Strict-Transport-Security "max-age=31536000" always;
    include /etc/nginx/vhost.d/default;
    location / {
        proxy_pass http://ws.joal.server.fr;
    }
}

With such an nginx config you should connect with :

Server address: ws.joal.server.fr Server port: 443 Path prefix: joal Secret token: test

I create two upstream (alias that points to an IP) and then forward them to JOAL. but the two upstreams allow me to differentiate websocket and http.

Of course, you'll need to add those two domains to your host files in order to bypass DNS lookup

gaglimax commented 6 years ago

I have never worked with nginx but I tried this configuration :

My parameters are :

Server address: ws.joal.server.fr Server port: 7073 Path prefix: joal Secret token: test


It still doesn't work. 

I think I will use your tool on in local network because I don't know what to try now...

Thank you very much for your quick replies !
anthonyraymond commented 6 years ago

Do you have some error log in chrome/firefox console?

anthonyraymond commented 6 years ago

Wooops sorry i messes up, the ”Server port" is not 7073 for joal webui config, it's 443. I've edited my previous post

But also, why is the second vhost listening on 80 and not 443 in your config?

gaglimax commented 6 years ago

Yes I have something in Firefox !!

Firefox ne peut établir de connexion avec le serveur à l’adresse wss://ws.joal.server.fr:7073/joal.
error message from websocket 
close
   ​bubbles: false
   ​cancelBubble: false
   ​cancelable: false
   ​code: 1006
   ​composed: false
   ​currentTarget: null
   ​defaultPrevented: false
   ​eventPhase: 0
   ​explicitOriginalTarget: WebSocket { url: "wss://ws.joal.server.fr:7073/joal", readyState: 3, bufferedAmount: 0, … }​
   isTrusted: true​
   originalTarget: WebSocket { url: "wss://ws.joal.server.fr:7073/joal", readyState: 3, bufferedAmount: 0, … }​
   reason: ""​
   target: WebSocket { url: "wss://ws.joal.server.fr:7073/joal", readyState: 3, bufferedAmount: 0, … }
   ​timeStamp: 36309
   ​type: "close"​
   wasClean: false​
   __proto__: CloseEventPrototype​
   ​code: Getter​
   ​constructor: function ()​
   ​reason: Getter​
   ​wasClean: Getter​
   ​__proto__: EventPrototype { composedPath: composedPath(), stopPropagation: stopPropagation(), stopImmediatePropagation: stopImmediatePropagation(), … } JOALStompClient.js:76:6
anthonyraymond commented 6 years ago

Yep as expexcted, apply the two fixes from my above answer and try again :)

gaglimax commented 6 years ago

Ok so I changed the port to 443 and the virtualhost to setup https :

<IfModule mod_ssl.c>
<VirtualHost *:443>
    DocumentRoot "/var/www/html"
    ServerName ws.joal.server.fr
    ServerAlias www.ws.joal.server.fr

    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/ws.joal-error.log
    CustomLog ${APACHE_LOG_DIR}/ws.joal-access.log combined

    ProxyPass / http://127.0.0.1:7073/
    ProxyPassReverse / http://127.0.0.1:7073/

Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/ws.joal.server.fr/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/ws.joal.sever.fr/privkey.pem
</VirtualHost>
</IfModule>

But it still doesn't work :

error message from websocket 
close
bubbles: false
cancelBubble: false
cancelable: false
code: 1006
composed: false
currentTarget: null
defaultPrevented: false
eventPhase: 0
explicitOriginalTarget: WebSocket { url: "wss://ws.joal.server.fr/joal", readyState: 3, bufferedAmount: 0, … }
isTrusted: true
originalTarget: WebSocket { url: "wss://ws.joal.server.fr/joal", readyState: 3, bufferedAmount: 0, … }
reason: ""
target: WebSocket { url: "wss://ws.joal.server.fr/joal", readyState: 3, bufferedAmount: 0, … }
timeStamp: 40944
type: "close"
wasClean: false
__proto__: CloseEventPrototype { wasClean: Getter, code: Getter, reason: Getter, … }
anthonyraymond commented 6 years ago

Have you any more log somewhere ? maybe in joal console, or even in apache. Something that could explain why it does does not work?

anthonyraymond commented 6 years ago

This SO issue might help you. Appearently Apache needs some extra conf for websocket : https://stackoverflow.com/a/27534443/2275818

gaglimax commented 6 years ago

Thanks for your answers.

I red the issue so I activated proxy_wstunnel.

Then I change the virtual host like this :

<IfModule mod_ssl.c>
<VirtualHost *:443>
    DocumentRoot "/var/www/html"
    ServerName ws.joal.server.fr
    ServerAlias www.ws.joal.server.fr

    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/ws.joal-error.log
    CustomLog ${APACHE_LOG_DIR}/ws.joal-access.log combined

    RewriteEngine On
    RewriteCond %{QUERY_STRING} transport=websocket    [NC]
    RewriteRule /(.*) ws://127.0.0.1:7073/$1 [P,L]

    ProxyPass / http://127.0.0.1:7073/
    ProxyPassReverse / http://127.0.0.1:7073/

    Include /etc/letsencrypt/options-ssl-apache.conf
    SSLCertificateFile /etc/letsencrypt/live/ws.joal.server.fr/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ws.joal.server.fr/privkey.pem
</VirtualHost>
</IfModule>

The issue remains the same but I have those Joal logs :

...
[WARN ] 2018-06-25 09:29:05.221 [           main] i.u.w.jsr: UT026009: XNIO worker was not set on WebSocketDeploymentInfo, the default worker will be used
[WARN ] 2018-06-25 09:29:05.221 [           main] i.u.w.jsr: UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
...
[ERROR] 2018-06-25 09:39:04.650 [  XNIO-2 task-2] o.s.w.s.s.s.DefaultHandshakeHandler: Handshake failed due to invalid Upgrade header: null

In Chrome logs :

WebSocket connection to 'wss://ws.joal.server.fr/joal' failed: Error during WebSocket handshake: Unexpected response code: 503
client @ webstomp.js:871
value @ JOALStompClient.js:52
(anonymous) @ JOALStompClient.js:126
CloseEvent {isTrusted: true, wasClean: false, code: 1006, reason: "", type: "close", …}
bubbles:false
cancelBubble:false
cancelable:false
code:1006
composed:false
currentTarget:WebSocket {url: "wss://ws.joal.server.fr/joal", readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: null, …}
defaultPrevented:false
eventPhase:0
isTrusted:true
path:[]
reason:""
returnValue:true
srcElement:WebSocket {url: "wss://ws.joal.server.fr/joal", readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: null, …}
target:WebSocket {url: "wss://ws.joal.server.fr/joal", readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: null, …}
timeStamp:426326.3999999908
type:"close"
wasClean:false
__proto__:CloseEvent
anthonyraymond commented 6 years ago

Sounds better.

You seems to be missing the Upgrade header. I don't know how to achieve this with apache. But here are the revelant parts in nginx.

map $http_upgrade $proxy_connection {
  default upgrade;
  '' close;
}
...
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;

If nginx receives Upgrade header. It will set Connection: "Upgrade" and forward the Upgrade header to the destination. This is what you are missing in your ws.joal.server.fr conf.

gaglimax commented 6 years ago

It works !

It was the RewriteCond. Here are the working virtual hosts

ws.joal.server.conf

<IfModule mod_ssl.c>
<VirtualHost *:443>
    DocumentRoot "/var/www/html"
    ServerName ws.joal.server.fr
    ServerAlias www.ws.joal.server.fr

    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/ws.joal-error.log
    CustomLog ${APACHE_LOG_DIR}/ws.joal-access.log combined

    RewriteEngine On
    RewriteCond %{HTTP:Connection} Upgrade [NC]
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteRule /(.*) ws://127.0.0.1:7073/$1 [P,L]

    ProxyPass / http://127.0.0.1:7073/
    ProxyPassReverse / http://127.0.0.1:7073/

    Include /etc/letsencrypt/options-ssl-apache.conf
    SSLCertificateFile /etc/letsencrypt/live/ws.joal.server.fr/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ws.joal.server.fr/privkey.pem
</VirtualHost>
</IfModule>

joal.server.conf

<IfModule mod_ssl.c>
<VirtualHost *:443>
    DocumentRoot "/var/www/html"
    ServerName joal.gagliardini.fr
    ServerAlias www.joal.gagliardini.fr

    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/joal-error.log
    CustomLog ${APACHE_LOG_DIR}/joal-access.log combined

    RewriteEngine On
    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteRule ^(.*)$ http://www.%{HTTP_HOST}$1 [R=301,L]

    ProxyPass / http://127.0.0.1:7073/
    ProxyPassReverse / http://127.0.0.1:7073/
    ProxyRequests Off

Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/joal.gagliardini.fr/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/joal.gagliardini.fr/privkey.pem
</VirtualHost>
</IfModule>

Thank you very much for your help and your work 👍

romquenin commented 4 years ago

Hello @anthonyraymond !

Sorry to write on this closed issue but i think i have kind of same problem @gaglimax had.

I'm running "Joal" with docker official image on ubuntu and i'm using linuxserver's docker image "Letsencrypt" for all my reversed proxy apps. I can access the Joal interface with the reverse proxy (https://mydomain.duckdns.org/joal/ui) but unfortunately the connexion is not working.

Screenshot 2020-02-23 at 16 04 28 Screenshot 2020-02-23 at 16 35 44

Here are the errors detected with the chrome console:

Screenshot 2020-02-23 at 16 04 01

And here are my nginx settings: from file default.php located in: /letsencrypt/nginx/site-confs

# redirect all traffic to https
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
}

# main server block
server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;

    root /config/www;
    index index.html index.htm index.php;

    server_name _;

    # enable subfolder method reverse proxy confs
    include /config/nginx/proxy-confs/*.subfolder.conf;

    # all ssl related config moved to ssl.conf
    include /config/nginx/ssl.conf;

    # enable for ldap auth
    #include /config/nginx/ldap.conf;

    client_max_body_size 0;

        # joal
    location ^~ /joal {     
        include /config/nginx/proxy.conf;
        resolver 127.0.0.11 valid=30s;
        set $upstream_joal joal;               
        proxy_pass http://$upstream_joal:9001;  
    }   
    location ^~ /joal/ui {      
        include /config/nginx/proxy.conf;
        resolver 127.0.0.11 valid=30s;  
        set $upstream_joal joal;               
        proxy_pass http://$upstream_joal:9001;  
    }

from file nginx.conf located in: /letsencrypt/nginx I haven't made any changes in this file.

## Version 2019/12/19 - Changelog: https://github.com/linuxserver/docker-letsencrypt/commits/master/root/defaults/nginx.conf

user abc;
worker_processes 4;
pid /run/nginx.pid;
include /etc/nginx/modules/*.conf;

events {
    worker_connections 768;
    # multi_accept on;
}

http {

    ##
    # Basic Settings
    ##

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    variables_hash_max_size 2048;
    large_client_header_buffers 4 16k;

    # server_tokens off;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    client_max_body_size 0;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # Logging Settings
    ##

    access_log /config/log/nginx/access.log;
    error_log /config/log/nginx/error.log;

    ##
    # Gzip Settings
    ##

    gzip on;
    gzip_disable "msie6";

    # gzip_vary on;
    # gzip_proxied any;
    # gzip_comp_level 6;
    # gzip_buffers 16 8k;
    # gzip_http_version 1.1;
    # gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    ##
    # nginx-naxsi config
    ##
    # Uncomment it if you installed nginx-naxsi
    ##

    #include /etc/nginx/naxsi_core.rules;

    ##
    # nginx-passenger config
    ##
    # Uncomment it if you installed nginx-passenger
    ##

    #passenger_root /usr;
    #passenger_ruby /usr/bin/ruby;

    ##
    # Virtual Host Configs
    ##
    include /etc/nginx/conf.d/*.conf;
    include /config/nginx/site-confs/*;
    lua_load_resty_core off;

}

#mail {
#   # See sample authentication script at:
#   # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
#   # auth_http localhost/auth.php;
#   # pop3_capabilities "TOP" "USER";
#   # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
#   server {
#       listen     localhost:110;
#       protocol   pop3;
#       proxy      on;
#   }
#
#   server {
#       listen     localhost:143;
#       protocol   imap;
#       proxy      on;
#   }
#}
daemon off;

from the file proxy.conf located in: /letsencrypt/nginx I added the lines you have shared: proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $proxy_connection; but i had to uncomment the Connection line (it breaks the reverse proxy)

## Version 2019/10/23 - Changelog: https://github.com/linuxserver/docker-letsencrypt/commits/master/root/defaults/proxy.conf

client_body_buffer_size 128k;

#Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;

# Advanced Proxy Config
send_timeout 5m;
proxy_read_timeout 240;
proxy_send_timeout 240;
proxy_connect_timeout 240;

# TLS 1.3 early data
proxy_set_header Early-Data $ssl_early_data;

# Basic Proxy Config
proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection $proxy_connection;
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 https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Ssl on;
proxy_redirect  http://  $scheme://;
proxy_http_version 1.1;
proxy_set_header Connection "";
#proxy_cookie_path / "/; HTTPOnly; Secure"; # enable at your own risk, may break certain apps
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 32 4k;
proxy_headers_hash_bucket_size 128;
proxy_headers_hash_max_size 1024;

I'm a complete noob with nginx configuration and i really hope you can help me with this issue.

Thanks again for all the great work you are doing.

anthonyraymond commented 4 years ago

Hi @romquenin Well that sounds like a complicated setup for such a small task ^^.

I may help you make it simple if you want. This imply:

anthonyraymond commented 4 years ago

@romquenin

Here is a tutorial i just wrote: https://github.com/anthonyraymond/joal/wiki/Joal-behind-a-reverse-proxy

JourneyOver commented 3 years ago

god why is setting up nginx and ssl with joal so damn annoying... Even trying your example from https://github.com/anthonyraymond/joal/issues/33#issuecomment-399572788 and switching the server_name and things to what I use does not work at all. Literally have no problems with anything else using nginx and ssl, just joal..

connection works just fine, but I am getting hit with wss errors :/

If I do like:

Server address: ws.joal.DOMAIN.TLD
Server port: 443
Path prefix: MyPathPrefix
Secret token: MySecretToken

in the joal webUI for the connection settings, it just throws 302 errors for wss, I've already set up the required stuff in nginx, as well as setting up a dns record for ws.joal.DOMAIN.TLD.

This is my server block for joal:

server {
  listen 80;
  server_name joal.DOMAIN.TLD;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  server_name joal.DOMAIN.TLD;

  #SSL
  include ./conf/snippets/ssl.conf;

  #Joal
  location / {
    proxy_pass http://10.0.0.14:3000/MyPathPrefix/ui/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

server {
  listen 80;
  server_name ws.joal.DOMAIN.TLD;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  server_name ws.joal.DOMAIN.TLD;

  #SSL
  include ./conf/snippets/ssl.conf;

  location / {
    proxy_pass http://10.0.0.14:3000/MyPathPrefix/ui/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

I do not seem to receive anything in the nginx error logs sadly :/

I don't use docker or anything of the sort, and I really don't want to move to Traefik as I've already got a working set up with nginx for literally everything else that has been working wonderfully for many years, I've just now recently moved away from non-ssl to using ssl and joal is the only one giving me any issues with the move.

joal was working fine before the move with non-https, as well as working fine (and still is) when going to the direct url http://10.0.0.14:3000/MyPathPrefix/ui/, it's just https that joal is not taking any fancy with.

anthonyraymond commented 3 years ago

Hello @JourneyOver Since tou reach the webui, can i see what Host an port you use in the "connection settings" please?

JourneyOver commented 3 years ago

@anthonyraymond I've tried:

Server address (host) with ws.joal.DOMAIN.TLD, joal.DOMAIN.TLD (obviously replacing DOMAIN.TLD with my actual domain) (both of these with and without the https:// in front) and also my default 10.0.0.14 Server port with both 443, and my default port of 3000

this is currently how I have things set up in the connection and also showing the console log: VPKoEUi

also the full red error dropdown: 04-21-2021_15-19-04

also not sure if it makes a difference or not but here is my ssl.conf

## ## Certificates from Let's Encrypt Certbot location placement.
ssl_certificate /Certbot/live/DOMAIN.TLD/fullchain.pem;
ssl_certificate_key /Certbot/live/DOMAIN.TLD/privkey.pem;

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;

ssl_stapling on;
ssl_stapling_verify on;

add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options nosniff;
JourneyOver commented 3 years ago

any ideas @anthonyraymond ?

anthonyraymond commented 3 years ago

I wrote you a big message with a new config to try. Bug appearently it has vanished x) i must have forgot to clic "send". I'll rewrite my answer this morning

JourneyOver commented 3 years ago

Sounds good @anthonyraymond I'll try whatever you post when you get it posted, and hopefully it works!

anthonyraymond commented 3 years ago

I'm pretty sure the problem comes from this line proxy_pass http://10.0.0.14:3000/MyPathPrefix/ui/; the reason is the same as explained in https://github.com/anthonyraymond/joal/issues/33#issuecomment-399415840

Can you try this config don't forget to replace all the DOMAIN.TLD with your own domain

map $http_x_forwarded_proto $proxy_x_forwarded_proto {
  default $http_x_forwarded_proto;
  ''      $scheme;
}
map $http_x_forwarded_port $proxy_x_forwarded_port {
  default $http_x_forwarded_port;
  ''      $server_port;
}
map $http_upgrade $proxy_connection {
  default upgrade;
  '' close;
}

# Apply fix for very long server names
server_names_hash_bucket_size 128;
# Default dhparam
# Set appropriate X-Forwarded-Ssl header
map $scheme $proxy_x_forwarded_ssl {
  default off;
  https on;
}
gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
log_format vhost '$host $remote_addr - $remote_user [$time_local] '
                 '"$request" $status $body_bytes_sent '
                 '"$http_referer" "$http_user_agent"';
access_log off;
# HTTP 1.1 support
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
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 $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
# Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy "";
server {
    server_name _; # This is just an invalid value which will never trigger on a real hostname.
    listen 80;
    return 503;
}

upstream joal.DOMAIN.TLD {
    server 10.0.0.14:3000;
}
# Force SSL
server {
    server_name joal.DOMAIN.TLD;
    listen 80 ;
    return 301 https://$host$request_uri;
}
server {
    server_name joal.DOMAIN.TLD;
    listen 443 ssl http2 ;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS';
    ssl_prefer_server_ciphers on;
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_certificate /Certbot/live/DOMAIN.TLD/fullchain.pem;
    ssl_certificate_key /Certbot/live/DOMAIN.TLD/privkey.pem;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security "max-age=31536000" always;
    location / {
        proxy_pass http://joal.DOMAIN.TLD;
    }
}

upstream ws.joal.DOMAIN.TLD {
    server 10.0.0.14:3000;
}
# Force SSL
server {
    server_name ws.joal.DOMAIN.TLD;
    listen 80 ;
    return 301 https://$host$request_uri;
}
server {
    server_name ws.joal.DOMAIN.TLD;
    listen 443 ssl http2 ;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS';
    ssl_prefer_server_ciphers on;
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_certificate /Certbot/live/DOMAIN.TLD/fullchain.pem;
    ssl_certificate_key /Certbot/live/DOMAIN.TLD/privkey.pem;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security "max-age=31536000" always;
    location / {
        proxy_pass http://ws.joal.DOMAIN.TLD;
    }
}

With such a config, you must:

If it's still not working you might want to enable nginx log so we can investigate deeper.

JourneyOver commented 3 years ago

I'm pretty sure the problem comes from this line proxy_pass http://10.0.0.14:3000/MyPathPrefix/ui/; the reason is the same as explained in #33 (comment)

@anthonyraymond This was it!

I took a look at your config and copied most of it, I had to remove or move some stuff around due to having bits in my nginx.conf file already (like the gzip_types and such) and it would throw errors with just copying your config and leaving things as is (with of course changing the domain.tld bits to my domain), and things started working.

So then I went back to my old joal.conf file and changed just one thing and that was the proxy_pass under ws.joal.domain.tld to not include the /MyPathPrefix/ui/ part while leaving the normal joal.domain.tld alone, and again it worked!

can't believe it was just that simple.

One question I do need to ask now though is, why does the websocket seem to randomly close every now and then and then open again a second or two later? There are no error message or anything in the error.log file for nginx, and I don't remember if this happened on http or not and it doesn't seem to happen at all when I go to the WEBUI through means of just IP address and not through my domain.

anthonyraymond commented 3 years ago

Glad it works :)

One question I do need to ask now though is, why does the websocket seem to randomly close every now and then and then open again a second or two later? There are no error message or anything in the error.log file for nginx, and I don't remember if this happened on http or not and it doesn't seem to happen at all when I go to the WEBUI through means of just IP address and not through my domain.

That an issue with proxy that joal v1 had. It's already solved in the version i'm rewriting from scratch. What happen is: if the webui does not exchange message (receive or send) message with the server for 30s the reverse proxy will consider the connection dead and close it forcefully. Thanksfully the webui has a recover mechanism that connect back as soon as it's closed but i agree that's a pain in the back.

There is a way though to prevent ngnx to auto close every 30s or 1m, you can use some config and i think those are the one:

proxy_connect_timeout 30m;
proxy_send_timeout 30m;
proxy_read_timeout 30m;
JourneyOver commented 3 years ago

Yep putting

proxy_connect_timeout 30m;
proxy_send_timeout 30m;
proxy_read_timeout 30m;

into the location block for ws.joal.domain.tld seems to have worked.

Thanks a bunch for the help, still can't believe it was just a simple thing of needing to change the proxy_pass for ws.joal.domain.tld to not include the /MyPathPrefix/ui/ bit to make things work as needed >.<

Can't wait for the rewrite of joal to be done, so I can get my hands on it!

anthonyraymond commented 3 years ago

I'll let you know, when it be "beta-ready" will you be interested in beign a beta-tester? Also, i already have some very "alpha preview" of some of the webui part (so fat only the layout like app bar and menu), would you like to see it and give me some your though?

JourneyOver commented 3 years ago

Sure! I'll beta test again for V2 when it's beta-ready since I had beta tested V1 for you so long ago :P and sure I'll take a look at the alpha preview for the webUI part, and give any ideas if I have any.

anthonyraymond commented 3 years ago

@JourneyOver i've just sent you an email with previews

JourneyOver commented 3 years ago

@anthonyraymond Great will check it out when I get a chance!

dominicmondello commented 2 years ago

For those interested, I got it to work quite easily, after reading this thread, using Caddy Reverse Proxy:

joal.yourdomain.com { route { } rewrite /joal/ui{uri} reverse_proxy 192.168.1.10:9092 } }

joalws.yourdomain.com { route { reverse_proxy 192.168.1.10:9092 } }

JOAL connections settings would look like this:

vivaldi_jkSNIw96cR