Type something to search...
How to configure DNS for a staging or development site?

How to configure DNS for a staging or development site?

To configure DNS for a staging or development site, the simplest approach is to create a subdomain such as staging.example.com and point it at your staging server with an A record (for an IP address) or a CNAME record (for a hostname provided by your hosting platform). For local development, you don't need public DNS at all: add an entry to your computer's hosts file or use a reserved name such as myapp.localhost or myapp.test. Whichever you choose, keep staging out of search engines and protect it with authentication, because a public DNS record makes it findable.

There's more than one sensible pattern, and the right one depends on how many environments you have, who needs access and how much separation you want from production. This guide covers subdomains, separate staging domains, wildcard records for preview deployments, delegating a whole subzone to a different DNS provider, local development options, TLS certificates for non-production hosts, and how to keep staging from leaking into Google or becoming a security risk.

Option 1: A Staging Subdomain

For most websites, a subdomain of the production domain is the obvious choice. It's quick to set up, needs no extra domain registration and makes the environment's purpose clear.

If your staging server has a fixed IP address, add A and, if supported, AAAA records:

staging      300  IN  A     203.0.113.40
staging      300  IN  AAAA  2001:db8:40::1

If your staging site runs on a platform that gives you a hostname, such as a load balancer or a platform-as-a-service app, use a CNAME instead:

staging      300  IN  CNAME  example-staging.platform.example.net.

Then check it resolves:

dig staging.example.com +short
example-staging.platform.example.net.
198.51.100.77

A short TTL such as 300 seconds is a good default for non-production records, because staging infrastructure tends to change more often than production.

Naming Conventions

Pick a consistent scheme and stick to it, especially if several teams create environments:

PatternExampleGood for
Environment namestaging.example.com, dev.example.comSmall teams with a few fixed environments
Environment plus serviceapi.staging.example.comMulti-service apps that mirror production
Service plus environmentapi-staging.example.comKeeping everything one level deep
Branch or PR previewspr-142.preview.example.comTemporary environments created by CI

The "environment plus service" pattern mirrors production neatly, so api.example.com becomes api.staging.example.com. Be aware that a single wildcard certificate only covers one level of subdomain. *.example.com covers api-staging.example.com but not api.staging.example.com.

Option 2: A Separate Staging Domain

Some organisations register a separate domain for non-production environments, such as example-staging.com or example.dev. Each production hostname gets a staging twin on the other domain.

Advantages of a separate domain:

  • Cookie isolation: Cookies set for .example.com by production aren't sent to example-staging.com, and staging can't set cookies that affect production. With a subdomain, a carelessly scoped cookie can cross between environments.
  • Separate DNS permissions: Developers can be given full control of the staging domain's zone without touching production DNS.
  • Lower risk of mistakes: A broken record on the staging domain can't affect production email or websites.
  • Cleaner security boundaries: Content Security Policy and CORS rules that trust *.example.com won't accidentally trust staging.

The downsides are the cost of an extra domain and the need to keep its configuration in step with production. For applications that handle logins or payments, the cookie isolation alone often makes it worthwhile.

Option 3: Wildcard Records for Preview Environments

If your CI pipeline creates a fresh environment for every branch or pull request, creating a DNS record each time is tedious. A wildcard record answers for any name under a given label:

*.preview    300  IN  CNAME  preview-ingress.example.net.

Now pr-142.preview.example.com, feature-login.preview.example.com and any other name under preview all resolve to the same ingress or load balancer:

dig pr-142.preview.example.com +short
dig anything-at-all.preview.example.com +short
preview-ingress.example.net.
203.0.113.60
preview-ingress.example.net.
203.0.113.60

The ingress controller or reverse proxy then routes each request to the right environment based on the Host header. Explicit records always win over the wildcard, so you can still add a specific record for one name if it needs to go somewhere else.

Keep wildcards scoped under a dedicated label like preview. A wildcard at the top of your production zone (*.example.com) makes typos resolve and can hide missing records.

Option 4: Delegate a Subzone

Sometimes the staging environment's DNS should be managed by a different team, account or provider. For example, production DNS might be in a tightly controlled account, while developers need to create records freely through a cloud provider's API.

You can delegate a subdomain to different nameservers by adding NS records for it in the parent zone:

; In the example.com zone
dev          3600  IN  NS  ns-1234.awsdns-26.org.
dev          3600  IN  NS  ns-567.awsdns-07.net.
dev          3600  IN  NS  ns-890.awsdns-47.co.uk.
dev          3600  IN  NS  ns-12.awsdns-01.com.

Then create a zone for dev.example.com at the other provider. Every name under dev.example.com is now answered by that provider, while the rest of example.com stays where it is.

Check the delegation:

dig dev.example.com NS +short
dig +trace app.dev.example.com | tail -n 6

The +trace output will show the query moving from your main provider's nameservers to the delegated ones.

Delegation is especially useful for Kubernetes tools such as ExternalDNS, which create records automatically. Giving them a delegated subzone means a bug can never touch production records.

Option 5: Local Development Without Public DNS

For work on your own machine, public DNS records are unnecessary and can be a hindrance. You have several local options.

Use localhost Names

Names ending in .localhost are reserved for loopback. Modern browsers such as Chrome and Firefox resolve any *.localhost name to 127.0.0.1 and ::1 without consulting DNS, and systemd-resolved on Linux does the same:

http://myapp.localhost:3000
http://api.myapp.localhost:8080

Browsers also treat localhost origins as secure contexts, so features that normally require HTTPS, such as service workers, work over plain HTTP.

Edit the hosts File

The hosts file overrides DNS for your machine only. It's useful when you want a production-like name, or when testing a staging server before its public DNS exists.

On macOS and Linux:

sudo nano /etc/hosts

On Windows, open Notepad as Administrator and edit:

C:\Windows\System32\drivers\etc\hosts

Add lines in the form IP name:

127.0.0.1      myapp.test
127.0.0.1      api.myapp.test
203.0.113.40   staging.example.com

The hosts file doesn't support wildcards, so each name needs its own line. Remember to remove overrides when you're done, or you'll be confused later when a real DNS change seems to have no effect.

Use the Reserved .test and .internal TLDs

Never invent a fake TLD for development, such as .dev or .app. Both are real, Google-operated TLDs, and they're on browsers' HSTS preload list, so they force HTTPS. Instead, use names that are reserved and will never exist on the public internet:

NameStatusTypical use
.localhostReserved for loopbackApps on your own machine
.testReserved for testingLocal development and test suites
.exampleReserved for documentationExamples and docs
.internalReserved by ICANN for private useInternal networks and private services

Wildcards Locally With dnsmasq

If you need wildcard names locally, for example *.myapp.test for multi-tenant development, a small local resolver such as dnsmasq can answer them. On macOS with Homebrew:

brew install dnsmasq
echo 'address=/test/127.0.0.1' >> "$(brew --prefix)/etc/dnsmasq.conf"
sudo brew services start dnsmasq

Then tell macOS to send queries for .test to dnsmasq:

sudo mkdir -p /etc/resolver
echo "nameserver 127.0.0.1" | sudo tee /etc/resolver/test

Test it:

ping -c 1 tenant1.myapp.test
PING tenant1.myapp.test (127.0.0.1): 56 data bytes

Note that dig bypasses the macOS resolver configuration and queries your default DNS server directly, so use ping or dscacheutil -q host -a name tenant1.myapp.test to test it.

TLS Certificates for Staging

Staging should use HTTPS just like production, otherwise you won't catch mixed content warnings, secure cookie problems or HSTS issues until launch.

For a public staging subdomain, a free Let's Encrypt certificate works the same as for production. For wildcard preview domains, you need a DNS-01 challenge, because wildcards can't be validated over HTTP. With Certbot's manual mode:

sudo certbot certonly --manual --preferred-challenges dns \
  -d preview.example.com -d '*.preview.example.com'

Certbot asks you to create a TXT record at _acme-challenge.preview.example.com. In practice, use a DNS plugin for your provider so renewals happen automatically.

Check your CAA records too. If production has a CAA record that only allows one certificate authority, staging subdomains inherit it unless they have their own CAA record:

dig example.com CAA +short
0 issue "letsencrypt.org"

For purely local development, a tool such as mkcert creates a locally trusted certificate authority and issues certificates for names like myapp.test.

Keeping Staging Private

A DNS record makes a hostname public, and certificate transparency logs publish the name of every publicly trusted certificate. Assume people, and crawlers, will find your staging site. Protect it in layers.

Require Authentication

The most reliable protection is to require a login before anything loads. With Nginx, basic authentication is a few lines:

sudo apt install apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd-staging tester
server {
    listen 443 ssl;
    server_name staging.example.com;

    auth_basic "Staging";
    auth_basic_user_file /etc/nginx/.htpasswd-staging;

    add_header X-Robots-Tag "noindex, nofollow" always;

    location / {
        proxy_pass http://127.0.0.1:3000;
    }
}

Alternatively, restrict access by IP address, put the site behind your VPN or use an identity-aware proxy.

Tell Search Engines Not to Index It

The X-Robots-Tag: noindex header in the example above tells search engines not to index any page. It's more reliable than a robots.txt file that blocks crawling, because blocked URLs can still appear in search results if other sites link to them. With authentication in place, crawlers can't see the content anyway.

Consider Private DNS

If staging only needs to be reachable from inside your network or VPN, you don't need public DNS at all. Use a private DNS zone in your cloud provider, or a name under .internal, so the hostname never appears publicly.

Clean Up Old Environments

Non-production environments come and go, and their DNS records are often left behind. A CNAME pointing at a deleted cloud resource is a classic route to subdomain takeover, where someone else claims the resource and serves their content on your domain.

Good habits:

  • Delete DNS records when you delete the environment, ideally in the same script or pipeline.
  • Use wildcards for short-lived previews, so there are no per-environment records to forget.
  • Review non-production records regularly and check that each one still points at something you own.

You can list the staging names from a zone export, which normally uses fully qualified names, and check each one still resolves:

awk '$1 ~ /staging/ {print $1}' example.com.zone | sort -u | while read -r name; do
  printf "%-40s %s\n" "$name" "$(dig +short "$name" | tail -n 1)"
done

Anything with an empty result, or an address you don't recognise, needs a closer look.


FAQ: DNS for Staging and Development Sites

A subdomain such as staging.example.com is simplest and fine for many sites. A separate domain gives better cookie and security isolation and lets you hand DNS control to developers, so it's often worth it for applications with logins or payments.

Yes. A record such as *.preview.example.com pointing at your ingress or load balancer lets every branch or pull request get its own hostname without creating new DNS records each time.

Use names ending in .localhost or .test, which are reserved and will never exist on the public internet. Avoid inventing TLDs such as .dev, which is a real TLD that forces HTTPS in browsers.

Put staging behind authentication so crawlers can't reach it, and send an X-Robots-Tag: noindex header as a second layer. A robots.txt block on its own doesn't stop URLs appearing in results.

Yes, staging needs a certificate that covers its own hostname. A free Let's Encrypt certificate works for public staging hosts, and wildcard preview domains need a DNS-01 challenge to issue a wildcard certificate.

dig sends queries straight to a DNS server and ignores the hosts file. Use ping, curl or your browser to test hosts file overrides, as they use the operating system's resolver.


Conclusion

DNS for staging and development doesn't need to be complicated. A subdomain with an A or CNAME record covers most cases, a separate domain adds isolation when security matters, wildcards handle preview environments, and a delegated subzone lets other teams or tools manage their own records safely. For local work, .localhost, .test, the hosts file and dnsmasq keep public DNS out of it entirely.

Whatever pattern you choose, treat staging as public once it has a DNS record. Put it behind authentication, add a noindex header, use HTTPS just as you would in production, and remove records when environments are retired so they can't be taken over.

Tags :
Share :

Related Posts

What is the difference between an A record and a CNAME record?

What is the difference between an A record and a CNAME record?

The difference between an A record and a CNAME record is what they point to. An A record points a hostname directly at an IPv4 address, such

Dive Deeper
What are the best DNS providers for websites?

What are the best DNS providers for websites?

The best DNS providers for most websites are Cloudflare for a fast, free, easy starting point, Amazon Route 53 if you already run on AWS, **G

Dive Deeper
What are the best public DNS resolvers?

What are the best public DNS resolvers?

The best public DNS resolvers for most people are Cloudflare (1.1.1.1) for speed and privacy, Google Public DNS (8.8.8.8) for reliability and

Dive Deeper