LowEndBox - Cheap VPS, Hosting and Dedicated Server Deals

Protecting and Remapping Apps with NGINX Reverse Proxying

Web services traditionally run on ports 80 (for http) and 443 (for https). Many other services run on other ports. Often times you’ll install a web-based app and discover that it runs on its own port.  In this tutorial, we’ll show you how to take an app running on a port like 4440 and have it appear on its own subdomain or URL on port 80/443.

Why Proxy Apps

This can cause a few different issues:

  1. The client devices you typically work from (e.g., your web browser) may be behind a firewall that does not allow connections to ports other than ports 80 and 443. For example, things may work great at home, but if you want to access that web app while you’re at work, you’re out of luck.
  2. If you expose that port to the Internet and it’s well-known port generally associated with that app, anyone scanning your VPS will immediatley know you’re running that app. If there is a vulnerability found, your VPS will be targeted. This is not true for ports 80/443 because there are millions of apps people might be running (or no app at all, just static content).

You could change the port. For example, I love RunDeck, which runs on port 4440. I could change it to run on port 443, but there are two problems…

  1. Because ports 80 and 443 are below the number 1024, they’re considered privileged ports, which means that the software would have to either run as root or be engineered to first grab the port and then drop switch users. Most software is not engineered this way, which means running it as root may be opening your VPS up to a lot of security issues.
  2. What if I have two or more apps? They can’t both bind to 80 or 443.

Finally, not all web apps are security- or multiuser-focused. I’ve sometimes written quick apps for my use and didn’t want to spend time to make a user login/authentication system. One easy way to wrap everything in login is to use http basic authentication, which is as simple as adding a webserver directive and creating a users file (and using https so passwords aren’t sent in the clear). But your webserver has to be in the picture – it can’t help you if it never sees the request because you’re directly connecting to port 3000 or whatever.

The Solution: Reverse Proxies

In this example, I’ll setup Rundeck on a VM and reverse proxy it. Rundeck runs on port 4440. What I want is:

www.lowend.party: show the lowend.party web site
rundeck.lowend.party: show Rundeck

In DNS, the A record is server1.lowend.party and both www.lowend.party and rundeck.lowend.party are CNAMEs to this A record.

Here’s my nginx server setup. Note that this is not a complex nginx setup – you would normally configure log locations, SSL, perhaps PHP, etc.

server {
  listen 80;
  server_name www.lowend.party;

  location / {
    root /web/www.lowend.party;
    index index.html;
  }
}

server {
  listen 80;
  server_name rundeck.lowend.party;
  location / {
    proxy_pass http://localhost:4440;
  }
}

The first directive should be pretty familiar to any nginx user. It defines the port to listen on (80, http), the server name to listen for (www.lowend.party), and then I setup the location directives. There’s only one in this case and it defines a web root and order of index.

The second directive is where we see the proxying magic. Once again, I define the port to listen on and the server name. But now for location, instead of defining a web root, I use the proxy_pass directive. This says “take all requests and direct them to this URL”. In this case, the URL is Rundeck running on port 4440 on localhost.

Note that Rundeck could be running a different host entirely – nginx just wants a URL.

I could also do something like this, if I wanted Rundeck to appear on www.lowend.party/rundeck:

server {
  listen 80;
  server_name www.lowend.party;

  location /rundeck {
    proxy_pass http://localhost:4440;
  }

  location / {
    root /web/www.lowend.party;
    index index.html;
  }
}

Note that sometimes you may need to adjust the proxied app’s configuration, particularly if it is publishing a URL as part of its output. But normally, the app thinks its running on localhost (it is) and is allowed to live in ignorant bliss.

raindog308

4 Comments

  1. Why not use Caddy instead? It’s out-of-the-box support of free-to-use certificate authorities, automatic HTTPS, HTTP2, etc, is probably a better drop-in solution for a lot of folks that are looking to enhance their security.

    Perhaps an opportunity for the next article in the series? :)

    February 6, 2021 @ 7:54 am | Reply
  2. dotcomUNDERGROUND:

    Can this be used as a proxy to remote mailserver (imap/smtp)?

    February 6, 2021 @ 2:28 pm | Reply
    • Simon:

      No. But you can use something like HAProxy to achieve this.

      February 6, 2021 @ 10:43 pm | Reply
  3. Onoitsu2:

    I personally like using Proxmox (since I see your more recent things about it also) with Docker, and in Docker using jlesage/docker-nginx-proxy-manager. Can have it reverse proxy into proxmox’s port 8006 with websockets being used even so dead simple and easily integrate existing certs or have it generate itself.

    January 31, 2023 @ 4:31 pm | Reply

Leave a Reply to dotcomUNDERGROUND Cancel reply

Some notes on commenting on LowEndBox:

  • Do not use LowEndBox for support issues. Go to your hosting provider and issue a ticket there. Coming here saying "my VPS is down, what do I do?!" will only have your comments removed.
  • Akismet is used for spam detection. Some comments may be held temporarily for manual approval.
  • Use <pre>...</pre> to quote the output from your terminal/console, or consider using a pastebin service.

Your email address will not be published. Required fields are marked *