Dynamic Per-User Subdomain Proxy

Hello, I am developing an application that has a main application (example.com) which (amongst other things) has auth and links to per-user subdomains that proxy to other servers. The main site operates as a standard adonis app, routes, etc.

Then, a user can click a link in that appp, and can redirect users to their specific device, so for example:

User A can access device1.example.com and device2.example.com but NOT device3.example.com
User B can access only device3.example.com

All based upon their ownership of that device.

When they hit that page, it needs to be a completely transparent proxy to another IP/URL/endpoint that is dynamically assigned, some of which have websockets.

What I am trying to figure out is the best way of tackling this. I am not sure middleware is the best approach, whether to override something in the start/http.js or start/app.js?

Thanks!

1 Like

Are all the servers internet facing?

If so any user can access any server, and you will need to have some form of login security on each server. Even if the users log into your main server first, that will not log them in to the other servers that you want to proxy them to, so it sounds like it is either is not secure or it can not be transparent.

Why not put some form of security on each server requiring the user to login, then put a proxy server at the front end which directs traffic for device3.example.com to device 3.

Hi @AddoSolutions

I have half the idea.
You can use main server to sign JWT and add scopes into it.
Then in any child server you can check if given subdomain / child server is listed in scope. If not, then throw Access denied error

This scope check you can make as middleware.

I am little bit confused are you making dynamic proxy with Adonis / Node or something like Nginx / Apache?

These devices are NOT internet facing, all behind NAT and this is the users way of accessing those devices.

Adonis will be running the proxy. I did end up with an okay solution using server middleware and bumping the auth up. Will post my results here soon

// kernel.js

const globalMiddleware = [
  'Adonis/Middleware/BodyParser',
  'Adonis/Middleware/AuthInit',
  'Adonis/Middleware/GuardInit'
]

const serverMiddleware = [
  'Adonis/Middleware/Session',
  'App/Middleware/Proxy',
  'Adonis/Middleware/Static',
  'Adonis/Middleware/Cors',
]

then

// App/Middleware/Proxy.js

class Proxy {
  /**
   * @param {object} ctx
   * @param {Request} ctx.request
   * @param {Function} next
   */
  async handle({request, response, auth, guard}, next) {
    // call next to advance the request

    let host = request.request.headers.host;

    // Check if host matches the subomain template

    if (match) {
      let user;
      user = await auth.getUser();

      // Check if can access device

      if (device && device.ip && user) {


        try {
          await new Promise((resolve, reject) => proxy.web(request.request, response.response, {
            // some options
            target: 'http://' + device.ip,
          }, (e, data) => {
            if (e) reject(e);
            resolve(data);
          }));
        } catch (e) {
          console.error(e);
          response.status(500).send({
            success: false,
            error: e.message
          });
        }
        return;
      }
    }

    await next()
  }
}
2 Likes