skip to Main Content

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

2

Answers


  1. Chosen as BEST ANSWER

    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.


  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search