What Is a Subdomain?
A subdomain is a prefix added to your root domain that functions as a separate address while remaining part of your main domain. When you type blog.example.com, blog is the subdomain, example is the second-level domain, and com is the top-level domain. Subdomains allow you to organize different services, applications, and content areas under a single domain name without purchasing additional domains.
Subdomain
Domain
TLD
From a DNS perspective, a subdomain is simply another record pointing to an IP address. There is no technical limit to the number of subdomains you can create (the DNS protocol supports up to 127 levels of subdomain nesting, though practically no one goes beyond two or three). Each subdomain can point to the same server, a different server, or even a third-party service.
Common Use Cases for Subdomains
Before diving into the technical setup, it helps to understand why you would use subdomains in the first place. Each use case comes with different DNS, web server, and SSL requirements:
blog.example.com
Separate your blog or content marketing from your main application. Common with WordPress running alongside a SaaS product.
app.example.com
Host your web application on a subdomain while keeping the marketing site on the root domain.
api.example.com
Dedicated subdomain for your API. Allows separate CORS policies, rate limiting, and load balancing.
staging.example.com
Staging or preview environment. Often password-protected and not indexed by search engines.
cdn.example.com
Content delivery — serve static assets (images, CSS, JS) from a cookieless subdomain for performance.
mail.example.com
Mail server hostname used in MX records, SPF, and DKIM configuration for email delivery.
Step 1: Creating DNS Records
Every subdomain starts with a DNS record. You need to tell the DNS system which IP address (or hostname) your subdomain should resolve to. The two most common record types for subdomains are A records and CNAME records.
A Record (Direct IP)
An A record maps a subdomain directly to an IPv4 address. Use this when you know the exact IP address of the server hosting the subdomain:
blog IN A 203.0.113.50
app IN A 203.0.113.50
api IN A 203.0.113.51
staging IN A 203.0.113.50
CNAME Record (Alias)
A CNAME record creates an alias that points to another hostname. If the target hostname's IP changes, the subdomain automatically follows. Use CNAME when pointing to external services or when you want a single point of IP management:
blog IN CNAME example.com.
cdn IN CNAME d1234abcd.cloudfront.net.
shop IN CNAME shops.myshopify.com.
| Feature | A Record | CNAME Record |
|---|---|---|
| Points to | IP Address | Another hostname |
| Can be used on root domain | Yes | No |
| Can coexist with other records | Yes | No |
| IP changes automatically | No | Yes |
| Extra DNS lookup | No | Yes (1 extra) |
example.com) because root domains must have SOA and NS records. Some DNS providers offer ALIAS/ANAME records as a workaround, but these are non-standard.
DNS Propagation
After creating a DNS record, it takes time to propagate across the global DNS network. The speed depends on the TTL (Time to Live) of your records:
| TTL Value | Propagation Time | Use Case |
|---|---|---|
| 300 (5 min) | 5-15 minutes | Records that change frequently |
| 3600 (1 hour) | 1-4 hours | Standard production records |
| 86400 (24 hours) | Up to 48 hours | Stable records that rarely change |
203.0.113.50
$ dig blog.example.com +trace
...
blog.example.com. 300 IN A 203.0.113.50
Step 2: Nginx Server Block for Subdomains
Once the DNS record is in place, you need to tell your web server to handle requests for the subdomain. In Nginx, this means creating a new server block with the subdomain as the server_name.
Basic Subdomain Server Block
server {
listen 80;
listen [::]:80;
server_name blog.example.com;
root /var/www/blog.example.com/public;
index index.html index.php;
access_log /var/log/nginx/blog.example.com.access.log;
error_log /var/log/nginx/blog.example.com.error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}
$ sudo ln -s /etc/nginx/sites-available/blog.example.com /etc/nginx/sites-enabled/
$ sudo nginx -t && sudo systemctl reload nginx
Subdomain as Reverse Proxy
For subdomains hosting applications (Node.js, Python, Go), use a reverse proxy configuration:
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Step 3: Apache VirtualHost for Subdomains
If you are using Apache instead of Nginx, the concept is the same but the configuration syntax differs:
<VirtualHost *:80>
ServerName blog.example.com
DocumentRoot /var/www/blog.example.com/public
<Directory /var/www/blog.example.com/public>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/blog.example.com.error.log
CustomLog ${APACHE_LOG_DIR}/blog.example.com.access.log combined
</VirtualHost>
$ sudo a2ensite blog.example.com.conf
$ sudo systemctl reload apache2
Wildcard Subdomains
A wildcard subdomain catches all subdomains that do not have an explicit DNS record. This is useful for multi-tenant SaaS applications where each customer gets their own subdomain (e.g., customer1.example.com, customer2.example.com).
DNS Wildcard Record
* IN A 203.0.113.50
# This matches ALL subdomains: anything.example.com → 203.0.113.50
# Explicit records (blog, api) still take priority over wildcard
Nginx Wildcard Server Block
listen 80;
server_name *.example.com;
# Extract subdomain name into a variable
set $subdomain "";
if ($host ~* ^([a-z0-9-]+)\.example\.com$) {
set $subdomain $1;
}
# Serve from subdomain-specific directory
root /var/www/subdomains/$subdomain/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
SSL Certificates for Subdomains
Every subdomain needs SSL, and you have three approaches: individual certificates, wildcard certificates, and Subject Alternative Name (SAN) certificates.
Individual Certificates
Free (Let's Encrypt)
- One cert per subdomain
- Simple to set up with Certbot
- Auto-renews independently
- Best for a few subdomains
Wildcard Certificate
Covers all subdomains
- Single cert for
*.example.com - Requires DNS validation
- Cannot cover sub-subdomains
- Best for many subdomains
Individual Certificate (Certbot)
Successfully received certificate.
Certificate: /etc/letsencrypt/live/blog.example.com/fullchain.pem
Key: /etc/letsencrypt/live/blog.example.com/privkey.pem
Wildcard Certificate (DNS Challenge)
-d "*.example.com" -d "example.com"
Please deploy a DNS TXT record under the name:
_acme-challenge.example.com
with the following value:
gfj9Xq...Rg5nTWIGy-15...7KiHYmCA
(Press Enter after deploying the TXT record)
*.example.com covers blog.example.com and api.example.com, but it does NOT cover v2.api.example.com. For sub-subdomains, you need a separate wildcard (*.api.example.com) or individual certificates.
Subdomain vs Subfolder: SEO Considerations
A common debate in web development is whether to use blog.example.com (subdomain) or example.com/blog (subfolder). The answer depends on your SEO strategy and technical requirements:
| Factor | Subdomain | Subfolder |
|---|---|---|
| SEO authority | Treated as separate site | Inherits domain authority |
| Technical isolation | Full isolation | Shared server config |
| Different tech stack | Easy (different server) | Requires proxy rules |
| Cookie scope | Isolated by default | Shares parent cookies |
| SSL complexity | Separate cert needed | Same cert as parent |
example.com/blog). Google treats subdomains as separate entities, so link authority from your blog does not directly strengthen your main domain. However, if you need technical isolation (different server, different technology, different team), subdomains are the correct choice.
Subdomain Isolation and Security
Subdomains provide a natural security boundary. A vulnerability in your blog subdomain does not directly compromise your main application because they can run as different system users, in different directories, with different PHP versions and configurations.
Directory Structure
├── example.com/
│ └── public/
│ └── index.html
├── blog.example.com/
│ └── public/
│ ├── index.php
│ └── wp-config.php
├── api.example.com/
│ └── public/
│ └── index.js
└── staging.example.com/
└── public/
└── index.html
Restricting Access to Staging
Staging subdomains should not be publicly accessible. Use HTTP Basic Auth or IP whitelisting:
listen 443 ssl http2;
server_name staging.example.com;
# IP whitelist + basic auth fallback
satisfy any;
allow 203.0.113.0/24; # Office IP range
deny all;
auth_basic "Staging Environment";
auth_basic_user_file /etc/nginx/.htpasswd;
# Prevent search engine indexing
add_header X-Robots-Tag "noindex, nofollow" always;
root /var/www/staging.example.com/public;
index index.html;
}
Common Mistakes and Troubleshooting
DNS Propagation Delay
Symptom: Subdomain shows "site not found" or DNS errors after adding the record.
Solution: Wait for TTL to expire. Check propagation with dig blog.example.com +trace or use an online DNS checker. Lower the TTL to 300 seconds before making DNS changes.
Wrong Document Root
Symptom: 404 errors or default Nginx page instead of your subdomain content.
Solution: Verify the root directive path exists and contains your files. Check file permissions — Nginx runs as www-data and needs read access.
Missing server_name
Symptom: Subdomain shows the wrong site (usually the default server block).
Solution: Ensure the server_name directive exactly matches the subdomain. Nginx falls back to the default_server if no match is found.
SSL Certificate Mismatch
Symptom: Browser shows "Your connection is not private" with NET::ERR_CERT_COMMON_NAME_INVALID.
Solution: The SSL certificate must cover the specific subdomain. A cert for example.com does not cover blog.example.com — you need a separate cert or a wildcard.
Subdomains with Panelica
Subdomain Setup Checklist
- Create an A or CNAME DNS record pointing to your server
- Verify DNS propagation with
digbefore configuring the web server - Create a dedicated server block (Nginx) or VirtualHost (Apache)
- Set correct
server_namematching the full subdomain - Create the document root directory with correct permissions
- Configure per-subdomain access and error logs
- Obtain an SSL certificate for the subdomain
- Set up HTTP to HTTPS redirect
- Add security headers to the server block
- Restrict staging/internal subdomains with auth or IP whitelist