Host web app on sub-route with reverse proxy

In this tutorial, we will see how to host a frontend application (React) on a sub-route with and without reverse proxy.

There are two ways in which we can host the website on the sub-route

  1. If the web application is client-side rendered, we can serve it directly through CDN (content-delivery-network).
  2. If the web application is placed on any server, we can create a reverse proxy through Nginx and serve the application.

In both cases, we will have to first change the base route in the application so that it can match the sub-route.

In react, we can set the base name on the react-router.

function App() {
  return (
    <BrowserRouter basename="/app">
      <Routes>
        <Route path="/" /> {/* 👈 Renders at /app/ */}
      </Routes>
    </BrowserRouter>
  );
}

Basename tells the react application that the base URL of the application is /app and it will render on that.

Once this is in place, we can create a build of the web application and host it as per our requirements.

Hosting web application on the CloudFront on sub-route

In the S3 bucket, create a sub-folder with the same name as the sub-route i.e. /app, and dump our build files in this folder.

Then configure the CloudFront to access the files from the origin path /app which notifies the CDN that files from the given folder have to be served.

Cloudfront origin  path settings

Once the configuration at the cloudfront is done, we can configure the domain to point to this CDN URL.

Host web app on sub-route with reverse proxy using Nginx

The second way is to serve the same CDN URL or the static files through the reverse proxy.

We can configure the Nginx and set that if a sub-route is encountered, then proxy the request to the CDN or the file path.

server {
  listen 80;
  listen 443 ssl;
  server_name  statics.yourside.com;
  access_log  /var/log/nginx/statics.access.log  combined;
  error_log   /var/log/nginx/statics.error.log;
  set $bucket "ucodevn.s3-ap-southeast-1.amazonaws.com";
  sendfile on;

location /app {
    resolver 8.8.8.8;
    proxy_http_version     1.1;
    proxy_redirect off;
    proxy_set_header       Connection "";
    proxy_set_header       Authorization '';
    proxy_set_header       Host $bucket;
    proxy_set_header       X-Real-IP $remote_addr;
    proxy_set_header       X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_hide_header      x-amz-id-2;
    proxy_hide_header      x-amz-request-id;
    proxy_hide_header      x-amz-meta-server-side-encryption;
    proxy_hide_header      x-amz-server-side-encryption;
    proxy_hide_header      Set-Cookie;
    proxy_ignore_headers   Set-Cookie;
    proxy_intercept_errors on;
    add_header             Cache-Control max-age=31536000;
    proxy_pass             https://$bucket; # without trailing slash
  }
}