1

This is prob very easy to solve(I hope) I never deployed wasm apps before and now I have a working frontend(rust yew) and backend(actix) working locally on my laptop and PC when I run it without nginx, just raw dev. Problem comes when I have:

  • deployed on remote server
  • deployed backend, working fine listening on port 8000: cargo watch -q -c -w src/ -x run this is temporary until I get everything working, then I will research how to run that without cargo *
  • added the frontend to work behind nginx, it loads and works until I try to create a user or anything that talks with the backend API.
server {
    listen 443 ssl; # IPv4
    listen [::]:443 ssl; # IPv6
    server_name my-portal.org;

    
    ssl_certificate /etc/letsencrypt/live/my-portal.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my-portal.org/privkey.pem;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams-2048.pem;

   #this is temp until is running ok, is a simple way to not allow people to play with it. 
    auth_basic           "Invitation Token";
    auth_basic_user_file /etc/nginx/.htpasswd;


    location / {
      root /home/portal/my-portal/dist;
      try_files $uri $uri/ /index.html;
    }
  • I build yew wasm with trunk build --release
  • this puts the files into the "dist" folder that is what nginx is poiting to.

What is not right: — I do not see my app ever talking to my backend, like I do on my dev environment, works fine with curl curl localhost:80000/test

I suspect this could be: — Web socket I just find out I am getting when I inspect the site and is trying to connect to: wss://my-portal.org/_trunk/ws

NS_ERROR_WEBSOCKET_CONNECTION_REFUSED

— somehow CORS is wrong? (even do I added as allowed origin the same I see on the headers like

# I have on my local only the localhost in deployement I add the domain, because it was not # working I added/changing this adding/removing diff options.

 HttpServer::new(move || {
        let cors = Cors::default()
            .allowed_origin("http://127.0.0.1:3000")
            .allowed_origin("http://127.0.0.1")
            .allowed_origin("https://my-portal.org")
            .allowed_methods(vec!["GET", "POST", "OPTIONS"])
            .allowed_headers(vec![
                header::CONTENT_TYPE,
                header::AUTHORIZATION,
                header::ACCEPT,
            ])
  • I am suspecting that I need to add something else to nginx for WS? Maybe CORS the issue? PD: Trying to see an example nginx config for a yew frontend project, but I have been searching with no success :(

the only yew wasm example I found is this: https://www.workfall.com/learning/blog/deploy-a-yew-rust-application-on-an-aws-ec2-ubuntu-instance-nginx/ since is wasm it does not need to run on its own like the backen does, nginx can load its index.html and this loads the wasm binary that runs on the browser, so no need to reverse proxy is running now with nginx, I need websockets somehow to work tho. More info in WHY this should not be run on its own webserver, nginx should do that, is a frontend not a backend. https://github.com/yewstack/yew/issues/2376

rek2
  • 101
  • 12
  • The nginx config is broken. Did you paste the entire config? – berkes Jul 25 '23 at 17:14
  • I run 9 other apps in this nginx so no, I only pasted the whole block for this vhost/server block server {} I suspect is related to my nginx config, of course is why works without it, but doing nginx -t all seems OK. And I have similar config for other vhosts, this is the first one with wasm/websocket tho. – rek2 Jul 25 '23 at 17:15
  • Can you connect to the WS backend on localhost? Try with wscat or so. And when you can, can you connect to it over the internet, e.g. on wss://my-portal.org/_trunk/ws ? – berkes Jul 26 '23 at 12:15
  • why the backend? is trying to connect to the frontend that is run by nginx on 443 so only way to connect to it is by domain since is vhost. again I repeat, frontend does NOT run on its own port is all run from nginx. _trunk/ws is part of the frontend not backend, backend does not speak websocket only rest http. I shared links below, did you read the link as I gived you below? to run a frontend with trunk is wrong for production only on development, nginx should run the app not run on its own. – rek2 Jul 26 '23 at 14:19
  • I know some dev because of lack of systems knowladge will run everything server side like if it was on dev machine but that is wrong for frontends, specially for wasm sites, nginx is capable of running yew with out configuring nginx as a reverse proxy for the whole thing, we may need to add something for nginx to understand websockets, but no need to pass it back is a vhost, already grabs all the trafit for that domain and loads the wasm site. – rek2 Jul 26 '23 at 14:28
  • ok so for the heck and trial and error I added this using nginx as a reverse proxy, still the same issue, so is def something else, also using wscat I get 301 when connecting to _trunk/ws – cfernandezlinux Jul 26 '23 at 17:05
  • Your problem is a bit unclear (to me). It seems you misunderstand your problem, but maybe I'm not understanding you. I understand that your frontend cannot connect to the backend over WS. Is that correct? And if so, can other clients than your frontend connect to the WS? e.g. wscat. And can they connect to it on localhost, and then also over the internet? – berkes Jul 27 '23 at 15:04
  • no is not correct, the ws issue was only a side problem generated because something else, and trying to get nginx to work as a reverse proxy made even more problems, because the webassambly yew app was not able to connect to the backend I explained below on an answer. wasm apps run on the browser such why nginx should just run as a normal webserver for this vhost. – rek2 Jul 27 '23 at 18:08

2 Answers2

1

This has little to do with Yew, but everything with your nginx config.

The config you shared, has no entry to actually connect to the running service on port 80000.

You'll need a line that configures nginx as a proxy. So that it passes requests along to the backend.

Typically, that will look something like:

server {
  listen 443 ssl;
  listen [::]:443;

  ## SSL cert stuff here.

  root /path/to/app/public/data;

  server_name example.com;

  try_files $uri/index.html $uri @app;

  location @app {
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header Host $http_host;
     proxy_set_header X-Forwarded-Proto https;
     proxy_redirect off;
     proxy_pass http://localhost:80000;
  }
}

Since you also need websockets, you'll need some additional nginx magic.

location /ws/ {
    proxy_pass http://localhost:80000; # Or whatever port yew has websockets exposed on.
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
}

This will upgrade any request to example.com/ws to a Websocket connection. You may need to finetune this further for production. As mentioned in the article linkeed, a.o. to properly close the connection.

berkes
  • 26,996
  • 27
  • 115
  • 206
  • Thanks, I will try this, but just to be clear is port 8000 and that is the backend. The front end is working on regular 443(tls) is what I am having the issue, that runs fine but web socket is not for what it seems, note, I would rather or was under the confusion that since is a wasm with its own index.html site it can run on its own, so nginx is only there for TLS/vhost not as proxy, with your example above it will send all data to my backend on 8000? I dont think nginx should even care about backend? – rek2 Jul 25 '23 at 17:22
  • What the config does, is it proxies any requests to https://example.com/foo to http://localhost:80000/foo. So, on the server you are running some process (yew serverside?) that serves itself on localhost:80000. Nginx on that same machine will now proxy any req on https://example.com to this backend. – berkes Jul 25 '23 at 17:27
  • no I am not, is all running behind nginx like a regular site. only the backend api is running on its own port 8000 and nginx has nothing to do with that one. url -> nginx(runs yew) and only yew in localhost talk to backend on port 8000 internally) – rek2 Jul 25 '23 at 17:29
  • this is the only example I found to deploy a wasm/yew app on nginx is for ec2 but does not matter https://www.workfall.com/learning/blog/deploy-a-yew-rust-application-on-an-aws-ec2-ubuntu-instance-nginx/ yew only needs to run on its port for dev, but since is a wasm app is like php/ruby etc nginx can run its index.html and the browser will load the page, so is only the websockets part that i need to figure out – rek2 Jul 25 '23 at 18:01
  • @berker see here https://github.com/yewstack/yew/issues/2376 this should NOT be run behind nginx is a frontend only backends should run that way nginx is capable of running/loading wasm and php and ruby etc – rek2 Jul 25 '23 at 21:52
1

ok so I was right, the issue was not in nginx,, rust yew is a webassembly site so runs completely on the browser/client side so does not need a nginx acting as reverse proxy at all to serve the wasm binary, just run it as a regular site, so I needed to do a couple steps:

  • websockets need to be under https/wss this is autofix when running as a regular site and not trin g to have proxy_pass for / location.
  • the main issue here was at first in my errors with cors but someone told me is not really cors the issue but that the browser needs access to the backend but the app was looking for localhost is why it was working on my laptop/PC.

Solution: expose the backend port, change the yew frontned to call by domain not localhost so clients know to contact the server, then nginx will reverse proxy only /api that is what I exposed on the backend

example:

server {
    listen 443 ssl; # IPv4
    listen [::]:443 ssl; # IPv6
    server_name my-portal.org;

    
    ssl_certificate /etc/letsencrypt/live/my-portal.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my-portal.org/privkey.pem;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams-2048.pem;

    
    auth_basic           "Invitation Token";
    auth_basic_user_file /etc/nginx/.htpasswd;


    location / {
      root /home/portal/my-portal/dist;
      try_files $uri $uri/ /index.html;
      include /etc/nginx/mime.types;
      default_type application/octet-stream;
    }
 
    location /api {
        proxy_pass        http://localhost:8000;
        proxy_set_header  X-Real-IP $remote_addr;
        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header  Host $http_host;

    }
}   

now is all working and frontend is working as intended 100% from nginx not its own dev web server that is wrong for a frontend, the backend yes, and only /api exposed to the frontend that is a wasm running on peoples browser.

rek2
  • 101
  • 12