Skip to content
DevOps devops domains 5 min read

Setting Up Subdomains

A subdomain is a prefix you add in front of your main domain, like api.example.com or blog.example.com. It lets you split one domain into many separate sites or services, each pointing wherever you want — a different app, a different server, or a third-party host. Subdomains are the foundation of multi-site hosting: you can run your marketing site, your API, and your blog all under one domain without buying three domains. This page shows you how to create a subdomain in DNS and how to match it in an Nginx server block so the right traffic reaches the right app.

What exactly is a subdomain

Every domain name is read right to left. In api.example.com:

  • com is the top-level domain (TLD) — the rightmost part.
  • example.com is your root domain (also called the apex domain) — the name you registered.
  • api is the subdomain — a label you can create yourself, for free, as many as you like.

You do not register or pay for subdomains. Once you own example.com, you control everything to the left of it. You create a subdomain simply by adding a DNS record (an entry in your domain’s address book that maps a name to a destination).

The special label www is itself just a subdomain. www.example.com is a subdomain of example.com — there is nothing magic about it.

A record vs CNAME record — which to use

To create a subdomain you add one DNS record. You have two main choices.

Record typePoints toWhen to use
A recordAn IP address (e.g. 203.0.113.10)The subdomain runs on a server whose IP you control. Most common for your own VPS.
CNAME recordAnother domain name (e.g. myapp.netlify.app)The subdomain is hosted by a third party (Netlify, Vercel, a load balancer) that gives you a hostname, not a fixed IP.

When to use an A record: you have your own Ubuntu server with a static public IP and you are hosting the app yourself. Point the subdomain straight at the IP.

When to use a CNAME: the destination is managed by someone else and its IP can change. A CNAME follows the target name, so the provider can move their servers without breaking you. Do not put a CNAME on your root domain (example.com with no prefix) — many DNS providers forbid it because the apex must also hold other records like MX (mail). Subdomains are safe for CNAMEs.

Step 1 — create the DNS record

Log in to your DNS provider (Cloudflare, your registrar, Route 53, etc.). Add a record. The fields are the same everywhere:

For an A record pointing api at your server:

Type:  A
Name:  api
Value: 203.0.113.10
TTL:   3600

Name: api automatically means api.example.com — you only type the prefix, not the whole name. TTL (time to live) is how many seconds resolvers cache the answer; 3600 (one hour) is a sane default.

For a CNAME pointing blog at an external host:

Type:  CNAME
Name:  blog
Value: myblog.ghost.io
TTL:   3600

Save the record. DNS changes can take a few minutes to a couple of hours to spread (propagate) across the internet.

Step 2 — verify the record from your server

SSH into your Ubuntu server and confirm the subdomain resolves to the right place. Install the DNS tools if needed:

sudo apt update
sudo apt install -y dnsutils

Then query the subdomain:

dig +short api.example.com

Output:

203.0.113.10

If you get back your server’s IP, DNS is working. If you get nothing, wait a few minutes and try again — the record may still be propagating.

Step 3 — match the subdomain in Nginx

Now that api.example.com reaches your server, you need to tell Nginx which app should answer for it. Nginx (a web server and reverse proxy — a server that sits in front of your app and forwards requests to it) decides this using the server_name directive.

Create a dedicated config file for the subdomain:

sudo nano /etc/nginx/sites-available/api.example.com

Add a server block that forwards traffic to an app listening on a local port (here a Node.js API on port 3000):

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-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

The server_name api.example.com; line is the matching rule: when a request arrives with Host: api.example.com, this block handles it. Other subdomains fall through to their own blocks.

Enable the site by symlinking it into sites-enabled, test the config, and reload:

sudo ln -s /etc/nginx/sites-available/api.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Output:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration test is successful

Always run sudo nginx -t before reloading — it catches typos so a broken config never takes your sites down.

Multi-site hosting — many subdomains, one server

The real power is hosting several sites on one machine. Give each subdomain its own DNS record (all pointing at the same IP) and its own Nginx server block. Nginx routes by server_name:

SubdomainDNS recordNginx server_nameBackend
app.example.comA → 203.0.113.10server_name app.example.com;Frontend on :3001
api.example.comA → 203.0.113.10server_name api.example.com;API on :3000
blog.example.comA → 203.0.113.10server_name blog.example.com;Static files in /var/www/blog

A blog block serving static files instead of proxying looks like this:

server {
    listen 80;
    server_name blog.example.com;

    root /var/www/blog;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

One server, three subdomains, three completely independent sites. If your firewall is on, make sure HTTP and HTTPS are allowed:

sudo ufw allow 'Nginx Full'

After a subdomain works over plain HTTP, secure it with a free SSL certificate. Running sudo certbot --nginx -d api.example.com adds HTTPS and edits the server block for you. Never leave an API serving real traffic on port 80 only.

Best Practices

  • Use an A record for subdomains on your own server, and a CNAME for subdomains hosted by a third party — never put a CNAME on the apex domain.
  • Give each subdomain its own file in /etc/nginx/sites-available so configs stay small and easy to manage.
  • Always run sudo nginx -t before sudo systemctl reload nginx to catch errors before they go live.
  • Verify DNS with dig +short <subdomain> before debugging Nginx — many “site down” issues are just DNS that has not propagated yet.
  • Keep TTL at 3600 for stable records; lower it to 300 shortly before a planned migration so changes take effect quickly.
  • Add a TLS certificate to every public subdomain and redirect HTTP to HTTPS so no traffic is ever unencrypted.
Last updated June 15, 2026
Was this helpful?