I’m writing a multi-tenant web app where admin users create subdomains for each tenant. The subdomain is how the app knows which tenant to use for branding. But how the heck do I test something like that locally on the Mac?
If you’re in the same boat or just tired of polluting your
/etc/hosts file, it’s time to setup Dnsmasq.
In this article, we’ll setup your Mac to answer all requests for a single top-level domain (TLD), in this case,
myproject.test and any domain ending in
.test will all be directed to your local machine.
Keep in mind this process is valid as of macOS 10.15.4 Catalina.
First, make sure you have Homebrew installed. That process is well documented so I won’t go into it here. I will, however, remind you
brew veterans to update your installation and packages.
brew update && brew upgrade
Now, install Dnsmasq.
brew install dnsmasq
Now modify the config file at
/usr/local/etc/dnsmasq.conf and append the following to the bottom of the file:
# Add a new ‘address’ line for each TLD you want to add. address=/.test/127.0.0.1 port=53
Now, create a
/etc/resolver/ directory if it doesn’t already exist (requires sudo or root privileges).
Next, create a file called
/etc/resolver/test with the following content:
You can create additional files in this directory with file names that reflect the TLDs you want to add with the same content.
Now, start the dns service.
sudo brew services start dnsmasq
You’ll get a message about root taking ownership of files. That’s completely normal.
This only has to be done once since the service persists through reboots.
Now you can ping any domain ending in
.test and it will resolve to your localhost at 127.0.0.1.
Special Note For .local Domains
Recently, macOS is handling this TLD since it is technically supposed to refer to LAN traffic. I stumbled across a workaround. If you need to support legacy projects with
*.local domains, you’ll need one more step. In System Preferences -> Network -> Advanced -> DNS, add
local to Search Domains. Now your system will handle
I feel there must be a better solution for this, but it’s working for now.
I hope you find this article helpful. If so, please share! Have a suggestion to make this article better? Let me know in a comment below.