How to proxy subdomains to /username while ignoring reserved subdomains?

Hi all,

I’m building a linktree style website hosted on example.com. Each user profile is accessible via a path like example.com/username.

I’d like to extend the functionality so that subdomains automatically map to their corresponding profile path. For example:

  • https://john.example.com/ → should internally route to → https://example.com/john

In other words, I want NGINX to rewrite all non-reserved subdomains to /username/..., while ignoring a whitelist of reserved subdomains like:

dashboard.example.com
api.example.com
admin.example.com

Example Behavior:

Request URL Should:
https://john.example.com/ display → /john
https://dashboard.example.com/ redirect → https://example.com/dashboard
https://admin.example.com redirect → https://example.com

Has anyone implemented something similar? I’m especially looking for:

  • Clean rewrite logic
  • Avoiding infinite rewrite loops
  • Reserved subdomain whitelist best practices

Also I must add the fact that example.com is behind a proxy_pass (Next.js project).
Thanks in advance!

1 Like

You should be able to achieve this in NGINX using a combination of map, server_name, and rewrite directives.

Reference:

General approach:

  1. Define a map for reserved subdomains (whitelist).

  2. Match all subdomains using a wildcard server block.

  3. Rewrite requests for non-reserved subdomains to “username”.

Apologies, I missed the last bit about the proxy. For this ensure that the rewritten URL is passed correctly to your Next.js backend.

Refrence:

I tried doing that but it doesn’t work at all.

Are you comfortable sharing a sanitized version of your current configs?

Hold on a second, because I am still trying to figure it out, will post in couple of mins.

1 Like

If you have specific questions as your working the problem shoot them our way and we will do our best to help.

By the way hats off to your approach, I also like to noodle out a problem before I look for assistance, best way to learn IMO.

I think i did it

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    map $host $is_whitelisted {
        default                    0;
        dashboard.example.com        1;
        rules.example.com            1;
    }

    # Main domain
    server {
        listen 443 ssl;
        server_name example.com;

        ssl_certificate     C:/nginx/_wildcard.example.com+3.pem;
        ssl_certificate_key C:/nginx/_wildcard.example.com+3-key.pem;

        location / {
            proxy_pass http://localhost:3000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }

    # Wildcard subdomains
    server {
		listen 443 ssl;
		server_name ~^(?<subdomain>.+)\.example\.com$;

		ssl_certificate     C:/nginx/_wildcard.example.com+3.pem;
		ssl_certificate_key C:/nginx/_wildcard.example.com+3-key.pem;

		# Redirect whitelisted subdomains to example.com
		if ($is_whitelisted = 1) {
			return 301 https://example.com;
		}

		location / {
			set $target_path /$subdomain;

			proxy_pass http://localhost:3000$target_path;
			proxy_set_header Host example.com;
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header X-Forwarded-Host $host;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		}
	}

    # Redirect HTTP to HTTPS
    server {
        listen 80;
        server_name example.com *.example.com;
        return 301 https://$host$request_uri;
    }
}

is this fine?
or do you have any other suggestions?

2 Likes

Looking good, at this juncture only a couple of suggestions I think will be useful to you.

You might consider:

  • Using map and return directives at the server level, if possible, instead of the if directive, this can be more reliable.

  • Adding proxy timeout settings to avoid connection hanging.

proxy_read_timeout
proxy_connect_timeout
proxy_send_timeout