How to Point a Subdomain to a Different App or Port
Run several apps on one VPS, each on its own subdomain — api.yourdomain.com, app.yourdomain.com — using a reverse proxy. DNS plus the Nginx and Caddy configs.

You've got several apps on one VPS — an API on port 3000, a dashboard on 4000, a docs site on 8080 — and you want api.example.com, app.example.com and docs.example.com to reach each one. DNS alone can't do this (it only knows IPs, not ports); you need a reverse proxy. This guide covers the DNS plus working Nginx and Caddy configs.
Why DNS isn't enough
A DNS record maps a name to an IP address, full stop — there's no port in an A record. So api.example.com and app.example.com both point at the *same* VPS IP, and a reverse proxy on that box reads the incoming Host header and forwards each subdomain to the right local port. That's the missing piece.
Step 1: Point every subdomain at the VPS
Add an A record per subdomain, all pointing at the same server IP:
- Type: A, Name:
api, Value:203.0.113.10 - Type: A, Name:
app, Value:203.0.113.10 - Type: A, Name:
docs, Value:203.0.113.10
Or add a single wildcard * record to cover them all — see how to set up a wildcard subdomain on a VPS. The record basics are in how to set up an A record for your server.
Step 2: Reverse proxy with Nginx
Give each subdomain a server block that proxies to its local port:
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:4000;
proxy_set_header Host $host;
}
}
Test and reload:
nginx -t && systemctl reload nginx
Each app keeps running on its own port, bound to localhost (127.0.0.1) so it isn't exposed directly — only Nginx faces the internet.

Step 3: Or use Caddy for automatic HTTPS
Caddy does the same with far less config and provisions SSL automatically:
api.example.com {
reverse_proxy 127.0.0.1:3000
}
app.example.com {
reverse_proxy 127.0.0.1:4000
}
docs.example.com {
reverse_proxy 127.0.0.1:8080
}
Caddy fetches and renews Let's Encrypt certs for each subdomain with zero extra steps — see set up Caddy for automatic HTTPS on a VPS.
Step 4: Add SSL (if using Nginx)
Caddy handles TLS itself; with Nginx, add certs via Certbot:
certbot --nginx -d api.example.com -d app.example.com -d docs.example.com
Certbot edits your server blocks to serve HTTPS and sets up renewal. More on free certs: set up Nginx with free SSL using Let's Encrypt.
Step 5: Verify
dig +short api.example.com
curl -I https://api.example.com
The dig should return your VPS IP; the curl should hit the right app. If a subdomain lands on the wrong app, check the server_name in each block. This is also how you host many sites on one box — see how to host multiple websites on one VPS.
Lock the app ports to localhost
The security half of this setup is making sure nobody bypasses the proxy by hitting the app port directly. Two layers:
- Bind each app to
127.0.0.1, not0.0.0.0. A Node app started withapp.listen(3000, "127.0.0.1")simply isn't reachable from outside the box. - Firewall the app ports as a backstop, leaving only 80/443 open:
ufw allow 80/tcp
ufw allow 443/tcp
ufw deny 3000/tcp
ufw deny 4000/tcp
Now the only public doorway is the reverse proxy, and each app is reachable only through its subdomain. General hardening lives in securing your first Linux VPS: 10 steps.
Support WebSockets and long connections
Default proxy configs buffer and drop upgraded connections, so real-time apps (chat, live dashboards, dev servers) break. Tell Nginx to pass the upgrade headers:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600s;
}
Caddy's reverse_proxy handles WebSocket upgrades automatically, one of the reasons it's popular for app hosting — see set up Caddy for automatic HTTPS on a VPS.
Path-based routing as an alternative
Subdomains aren't the only way to split apps. If you'd rather keep everything under one hostname, route by path instead:
location /api/ { proxy_pass http://127.0.0.1:3000/; }
location /app/ { proxy_pass http://127.0.0.1:4000/; }
Now example.com/api/ and example.com/app/ reach different apps with no extra DNS records — handy when you can't add subdomains, though subdomains keep apps cleanly separated for cookies and CORS. Whichever you choose, this is the same engine behind how to host multiple websites on one VPS, and you can add more subdomains at once with a wildcard record.
FAQ
Can DNS point a subdomain to a specific port?
No — DNS only maps names to IPs, with no port. Use a reverse proxy (Nginx, Caddy) on the server to route each subdomain to its local port. (SRV records carry ports but few clients use them.)
Do all my subdomains share one IP?
Yes, typically. They all point at the same VPS, and the reverse proxy distinguishes them by the Host header to forward to the right app.
Nginx or Caddy for this?
Caddy is simplest — automatic HTTPS and tiny config. Nginx is more configurable and ubiquitous. Both handle subdomain-to-port routing well; pick by preference.
How do I keep each app's port private?
Bind each app to 127.0.0.1 (localhost) so only the reverse proxy can reach it, and let the firewall block the app ports from the outside.
Can I run different apps on different ports without subdomains?
Yes — path-based routing lets one hostname serve several apps by URL path instead of subdomain. In your reverse proxy you send example.com/api/ to one port and example.com/app/ to another, so no extra DNS records are needed at all. The trade-off is that everything shares one origin, which means shared cookies and simpler CORS but weaker separation between apps; a bug or a permissive cookie in one path is visible to the others. Subdomains keep each app cleanly isolated (separate cookie scope, independent certificates) at the cost of a DNS record each. Choose path-based routing when you can't add subdomains or want a single unified site, and subdomains when isolation and independent scaling matter more.
One VPS can comfortably host a whole stack of apps this way. Get a fast NVMe VPS with full root access from Nxeon, or containerise it all with Docker hosting.