Kitware / paraviewweb

Web framework for building interactive visualization relying on VTK or ParaView to produce visualization data
http://kitware.github.io/paraviewweb/
BSD 3-Clause "New" or "Revised" License
160 stars 50 forks source link

ParaviewWeb behind Nginx #526

Closed ocni-dtu closed 3 years ago

ocni-dtu commented 3 years ago

Hi everyone!

I have troubles getting a setup with paraview to work behind a nginx container. When I got to http://0.0.0.0/visualizer my connection times out.

My Docker stack:

version: "3.8"

services:
  paraview:
    image: kitware/paraviewweb:pvw-egl-demo-v5.6.0
    command: "ws://localhost:9000/"
    entrypoint: "/opt/paraviewweb/scripts/start.sh"

  nginx:
    image: nginx:stable-alpine
    ports:
      - 80:80
      - 443:443
    volumes:
    - $HOME/pwtest/nginx/conf.d:/etc/nginx/conf.d/
    - $HOME/pwtest/nginx/nginx.conf:/etc/nginx/nginx.conf

I have the following nginx configuration files:

# conf.d/http.conf
resolver 127.0.0.11;

server {
    listen 80;
    server_name *;
    proxy_read_timeout 3600s;

    location ~ /ws {
        proxy_set_header Host $host;
        proxy_pass http://paraview:80;
    }

    location / {
        proxy_set_header Host $host;
        proxy_pass http://paraview:80;
    }

}

server {
    listen 9000;
    server_name *;
    proxy_read_timeout 3600s;

    location ~ / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Connection $connection_upgrade;
        proxy_pass http://paraview:9000;
    }

}
# nginx.conf
user  root;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

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

    map $http_upgrade $connection_upgrade {
            default upgrade;
            ''      close;
    }

    # Log format
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';

    # Access log
    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    # Set maximum file upload size
    client_max_body_size 500M;

    # Specific server blocks
    include /etc/nginx/conf.d/*.conf;

}

Did anyone successfully get paraview web to run behind nginx or can anyone see the issues with my setup? Thanks /Christian

jourdain commented 3 years ago

Does it timeout after 1 minute? If so, you need to increase client_body_timeout.

One thing that I'm also not sure of in your setup is command: "ws://localhost:9000/" in your docker stack. That URL should be using the actual name (+port) where you server can be reached from the outside (external ip or name).

Also, the /proxy?... is the path for websocket not /ws when used with a docker that embeds the launcher.

HTH,

Seb

ocni-dtu commented 3 years ago

No it times out after 25s. It is actually the call to /paraview/ that times out:

error 
XMLHttpRequest { onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, responseURL: "http://localhost/paraview/", status: 200, statusText: "OK", responseType: "json", response: {…} }
 Session did not start before timeout expired. Check session logs. Visualizer.js:1:232974

I actually don't think the location /ws or /proxy as it is caught in the / location anyways. Is it important that the command is the actually url? nginx passes the request on to the container with http://paraview:9000 so I thought that might be the url to give to the contianer

jourdain commented 3 years ago

There is several connection stage and you did not reach the "command one" just yet. The command string is what get sent to the client (browser) to make the ws connection to the actual process that had been started for him. So if it is localhost, there is very little chance the browser will actually reach the server you've setup.

Anyhow, right now, you are running into the fact that your paraview process fail to start. I believe it is because you did not start your container with access to the GPU and/or your drivers are not properly installed on your host machine or you don't even have a NVidia GPU with EGL support. You can double check that part by looking at the log of the started (failed) session in /pvw/launcher/log (or /opt/launcher/log as I don't remember which path is used for 5.6) of the paraview container.

ocni-dtu commented 3 years ago

I fixed the issue with the nvidia-container-runtime and it fails much faster now (there is no timeout issues). I'm still having troubles with establishing the websocket connection. In Firefox I get this error message: Firefox can’t establish a connection to the server at ws://localhost:9000/proxy?sessionId=a291f6ca-6c4c-11eb-9a75-02420a000906&path=ws.

Chrome gives me this one: ebSocket connection to 'ws://localhost:9000/proxy?sessionId=b5df943a-6c4c-11eb-9a75-02420a000906&path=ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED

I tried changing the ws://localhost:9000 command to ws://paraview:9000 and ws://0.0.0.0:9000 but I still get the same errors

jourdain commented 3 years ago

Yes like I said, what you are setting as argument is wrong. It needs to be what the browser connect to.

For example, if you want to reach your service via: https://my.super.domain.com/ then the argument should be wss://my.super.domain.com. If it is http instead, then you should use ws://my.super.domain.com.

And if you have some sub-path, you will have to add them as well...

ocni-dtu commented 3 years ago

Thank you for the help @jourdain I just wanted to circle back and say that I solved this now. I ended up with the following files:

#stack.yml
version: "3.8"

services:
  paraview:
    image: kitware/paraviewweb:pvw-egl-demo-v5.6.0
    command: "ws://localhost"
    entrypoint: "/opt/paraviewweb/scripts/start.sh"

  nginx:
    image: nginx:stable-alpine
    ports:
      - 80:80
      - 443:443
    volumes:
    - $HOME/pwtest/nginx/conf.d:/etc/nginx/conf.d/
    - $HOME/pwtest/nginx/nginx.conf:/etc/nginx/nginx.conf
# conf.d/http.conf
resolver 127.0.0.11;

server {
    listen 80;
    server_name *;
    proxy_read_timeout 3600s;

    location ~ /proxy {
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Connection $connection_upgrade;
        proxy_pass http://paraview:80;
    }

    location / {
        proxy_set_header Host $host;
        proxy_pass http://paraview:80;
    }

}

and nginx.conf is the same as in the original post.

jourdain commented 3 years ago

Thanks for providing the solution, but I still think that command: "ws://localhost" is wrong. localhost should be replaced by your external/public name that your users are going to connect to.

Also, if you were exposing your service on 443 with https, that command should use wss rather than ws.

ocni-dtu commented 3 years ago

On my local setup I can mix and match 0.0.0.0 and localhost. In the production settings I changed it to the right url. Locally I just used port 80 and http, so it worked as expected with ws. In production I use wss

jourdain commented 3 years ago

Perfect, I just wanted to clarify for anyone using that as reference.