I use .localhost for all my projects. Just one annoying note: Safari doesn't recognize the TLD localhost so it will try to perform a search. Adding a slash at the end will fix this; ie example.localhost/
Avoid using `.local`. In my experience Chrome does not like it with HTTPS. It takes much much longer to resolve. I found a Chrome bug relating to this but do not have it handy to share. `.localhost` makes more sense for local development anyways.
if you add your CA to the list of trusted certificate, everything will be fine. I do not recommend using custom certificates and would stick to http, unless you really know what you are doing
I use .local all the time and it works just fine. For TLS I use my existing personal CA, but HTTP links don't cause issues for me.
That said, I do use mDNS/Bonjour to resolve .local addresses (which is probably what breaks .local if you're using it as a placeholder for a real domain). Using .local as a imaginary LAN domain is a terrible idea. These days, .internal is reserved for that.
.local is mDNS/Rendezvous/Bonjour territory. In some cases it takes longer to resolve because your machine will multicast a query for the owner of the name.
I use it extensively on my LAN with great success, but I have Macs and Linux machines with Avahi. People who don't shouldn't mess with it...
The reason is .local is a special case TLD for link-local networking with name resolution through things like mdns, by trying to hijack it for other use things might not go as you intend. Alternatively, .localhost is just a reserved TLD so it has no other usage to check.
Honestly, if I had my druthers there would be a standardized exception for .local domains that self-signed HTTPS certs would be accepted without known roots. It's insane how there's no good workflow for HTTPS on LAN-only services.
Technically speaking you could use DANE with mDNS. Nobody does it, browser don't implemented it, but you can follow the spec if you'd like.
Practically speaking, HTTPS on LAN is essentially useless, so I don't see the benefits. If anything, the current situation allows the user to apply TOFU to local devices by adding their unsigned certs to the trust store.
Sure, but you can connect those devices to a real domain and use Let's Encrypt on them, or you can TOFU and add the self-signed cert to your browser; after you've verified that you're not being MitM'd by one of those untrusted devices, of course (I dunno, by printing the public key on the side of the device or something?).
In practice, you probably want an authorized network for management, and an open network with the management interface locked out, just in case there's a vulnerability in the management interface allowing auth bypass (which has happened more often than anyone would like).
The former just aren't practical for small business and home consumers, though. Browsers just don't have good workflow for TOFU.
I agree on the latter, but that means your IoT devices being accessible through both networks and being able to discriminate which requests are coming from the insecure interface and which are coming from secure admin, which isn't practical for lay users to configure as well. I mean, a router admin screen can handle that but what about other devices?
I know it seems pedantic, but this UI problem is one of many reasons why everything goes through the Cloud instead of our own devices living on our own networks, and I don't like that controlling most IoT devices (except router admin screens) involves going out to the Internet and then back to my own network. It's insecure and stupid and violates basic privacy sensibilities.
Ideally I want end users to be able to buy a consumer device, plug it into their router, assign it a name and admin-user credentials (or notify it about their credential server if they've got one), and it's ready and secure without having to do elaborate network topology stuff or having to install a cert onto literally every LAN client who wants to access its public interface.
The TLD hasn't been registered, but it has been added to the list of reserved names so effectively that's the domain you should use if you don't want to use real names.
.local also works fine, of course, if you enable mDNS and don't try to use normal DNS.
.local wasn't assigned to an organization, it was assigned to mDNS: multicast DNS. mDNS is the ask everyone on the local network if they like to be called that name which used to be better known under Apple's brand/trademark Bonjour, but now is a true standard.
Yes, but why couldn't they have assigned .mdns for that instead? Or even better given it it's own .arpa domain? E.G. .mdns(.arpa) rather than the .local TLD? ( https://en.wikipedia.org/wiki/.arpa )
Because .local looks nice and is a better name/explainer for what mDNS does than the standard name or the old brand name? Because the old brand was already using .local even if Apple Devices were somewhat a minority at the time?
At this point a lot of TLD changes are going to step on someone's project or home/business/private network. I think .local is a good name for mDNS. I appreciate why you maybe aren't happy with it, but don't share your concern.
Those are both reasons that .local should be static DNS on the _network_ like localhost is a standard name for the loopback address(es).
There's no reason .mdns or .mdns.arpa couldn't have just been added to the default domains search list (the list of suffixes tried for non FQDN searches); which given it ISN'T a nice human obvious word to append wouldn't have conflicted with anyone who'd already had a .local at the time, and anyone else in the future who thinks an obvious phrase like .local would not be in use by some other resolver system.
It's a neat trick, but it comes with some caveats. For instance, `localhost` often resolves to both 127.0.0.1 and ::1, but `.localhost` is described in RFC2606 as "traditionally been statically defined in host DNS implementations as having an A record pointing to the loop back IP address and is reserved for such use". In other words, your server may be binding to ::1 but your browser may be resolving 127.0.0.1. I'm sure later RFCs rectify the lack of IPv6 addressing, but I wouldn't assume everyone has updated to support those.
Another neat trick to combine with .localhost is using 127.0.0.0/8. There's nothing preventing you from binding server/containers to 127.0.0.2, 127.1.2.3, or 127.254.254.1. Quite useful if you want to run multiple different web servers together.
The RFC treats .localhost as a full TLD. I believe Windows does as well, as does Ubuntu (using default systemd-resolved), but macOS doesn't seem to resolve .localhost by default, necessitating the host file trickery.
Of course, in the early internet, the difference between a TLD and a host name weren't quite as clear as they are right now.
I haven't done it for a while (I've mostly just used 127.*), but I found the best one to use for dev purposes was the IETF-reserved `.test` TLD [0]. The main benefit at the time I was messing with this (10ish years ago now) was that all the browsers I needed to test on would actually attempt to resolve `.test`. If I remember correctly, firefox seemed to have issues with `localhost` being anything other than 127.0.0.1 (and would simply go to that address ignoring whatever was in /etc/hosts or DNS, again IIRC). It's been a while, though, so that behavior might have changed.
.test seems like an excellent choice for testing/debugging/developing applications, but for running services you want to use I'd stick to .internal these days, as it was reserved for local domains last year.
This is what I've done for years: doing app development using the .test TLD, and .internal for, well, internal services that are more like "production IT".
I've had nothing but trouble with .local and .localhost. Specifically, .local is intended for other purposes (multicast DNS) and .localhost has a nasty habit of turning into just "localhost" and in some cases, resolvers don't like to allow that to point to anything other than 127.0.0.1.
More recently, I've stuck to following the advice of RFC 6762 and use an actual registered TLD for internal use, and then sub-domain from there. I don't use my "production" TLD, but some other, unrelated TLD. For example, if my company is named FOO and our corporate homepage is at foo.com, I'll have a separate TLD like bar.com that I'll use for app development (and sub-domain as dev.bar.com, qa.bar.com, and maybe otherqa.bar.com as needed for different environments). That helps avoid any weirdness around .localhost, works well in larger dev/qa environments that aren't running on 127.0.0.1, and allows me to do things like have an internal CA for TLS instead of using self-signed certs with all of their UX warts.
For "local network" stuff, I stick to ".internal" because that's now what IANA recommends. But I would distinguish between how I use ".internal" to mean "things on my local network" from "this is where my team deploys our QA environment", because we likely aren't on the same network as where that QA environment is located and my ".internal" might overlap with your ".internal", but the QA environment is shared.
For development, "localhost" has a convenience bonus: it has special treatment in browsers. Many browser APIs like Service Workers are only available on pages with a valid WebPKI cert, except for localhost.
Yeah, I've been using localhost domains on Linux for a while. Even on machines without systemd-resolved, you can still usually use them if you have the myhostname module in your NSS DNS module list.
I ended up writing a similar plugin[1] after searching in vain for a way to add temporary DNS entries.
The ability to add host entries via an environment variable turned out to be more useful than I'd expected, though mostly for MITM(proxy) and troubleshooting.
Neat setup! I do something similar on OpenBSD. I have a CSV file that maps IP, MAC address, and hostname for various devices on my LAN. A shell script reads the file and creates a matching hosts file, dhcpd config, and unbound config, then restarts dhcpd and unbound (caching DNS server).
Whenever a host requests a DHCP lease it receives its assigned IP which matches the unbound record, then I can always access it by hostname.
I think you don't really need the /etc/hosts entry, I use this since google started using .dev domains and switched to using .localhost for everything local.
I wrote a super basic DNS server in go (mostly fun and go practice) which allows you to specify hosts and ips in a json config file. This eliminates the need for editing your /etc/hosts file. If it matches a host in the json config file it returns that ip, else uses Cloudflare public DNS resolver as a fallback. Please; easy on my go code :-). I am a total beginner with go.
The *.home.arpa domain in RFC 8375 has been approved for local use since 2018, which is long enough ago that most hardware and software currently in use should be able to handle it.
It's ugly and clunky, which is why after seven years it's had very little adoption. Home users aren't network engineers so these things actually do matter even if it seems silly in a technical sense.
The ".localhost" TLD has traditionally been statically defined in
host DNS implementations as having an A record pointing to the
loop back IP address and is reserved for such use
The RFC 8375 suggestion (*.home.arpa) allows for more than a single host in the domain. If not in name/feeling, but the strictest readings [and adherence] too.
RFC 8375 seems to have approved it specifically to use in Home Networking Control Protocol, though it also states "it is not intended that the use of 'home.arpa.' be restricted solely to networks where HNCP is deployed. Rather, 'home.arpa.' is intended to be the correct domain for uses like the one described for '.home' in [RFC7788]: local name service in residential homenets."
Anyone familiar with HNCP? Are there any concerns of conflicts if HNCP becomes "a thing"? I have to say, .home.arpa doesn't exactly roll of the tongue like .internal. Some macOS users seem to have issues with .home.arpa too: https://www.reddit.com/r/MacOS/comments/1bu62do/homearpa_is_...
Thanks, I always mix up mold and mildew. However, "arpa" is specifically a lottery ticket, whereas there are tickets for concerts, tickets to ride, tickets in Jira etc...
Arpa is used for all kinds of random chance things, not specifically for lottery. I feel like ticket would still be the equivalent but I guess that would be more transliteration and opinion than direct translation? Also my view for lottery may be skewed due to the Finnish lottery culture, and how lottery has more meanings in English. Sorry turned ranty.
I have been commandeering .home for the boxes on my LAN since forever. Why change it?
If I were going to do a bunch of extra work messing with configs I'd be far more inclined to switch all my personal stuff over to GNS for security and privacy reasons.
I simply quoted RFC 8375. It specifically called out that while RFC 7788 mentions ".home" (quoted below), it wasn't reserved, which ".home.arpa" aims to fix. But while you say "home.arpa is for HNCP", I also quoted RFC 8375 stating it's available for other uses as well.
> A network-wide zone is appended to all single labels or unqualified zones in order to qualify them. ".home" is the default; [...]
It would be great if there was an easy way to get trusted certificates for reserved domains without rolling out a CA. There are a number of web technologies that don't work without a trusted HTTPS origin, and it's such a pain in the ass to add root CAs everywhere.
> As of March 7, 2025, the domain has not been standardized by the Internet Engineering Task Force (IETF), though an Internet-Draft describing the TLD has been submitted.
> Resolved (2024.07.29.06), the Board reserves .INTERNAL from delegation in the DNS root zone permanently to provide for its use in private-use applications.
Too much typing, and Chromium-based browsers don't understand it yet and try to search for mything.internal instead, which is annoying - you have to type out the whole http://mything.internal.
This can be addressed by hijacking an existing TLD for private use, e.g. mything.bb :^)
eh, you can just add search domain via dhcp or static configuration and just type out http://mything/ no need to enter whole domain unless you need todo ssl
mything/ will make the OS resolve various hosts: mything., mything.local (mDNS), mything.whateverdomainyourhomenetworkuses. (which may be what you wanted).
If you want to be sure, use mything./ : the . at the end makes sure no further domains are appended during DNS lookup, and the / makes the browser try to access to resource without Googling it.
*.localhost is reserved for accessing the loopback interface. It is literally the perfect use for it. In fact on many operating systems (apparently not macOS) anything.localhost already resolves to the loopback address.
I recently tried to use the dnsmasq method mentioned at the very end but had some issues with fallthrough, as most of my dns traffic went trough my dev setup then first, which I didn't want. In the end I configured a "real" domain and let it point to 127.0.0.1, because I need arbitrary wildcard subdomains.. but I'm still not very happy with it because it feels like an unecessary dependency.
Chrome and i think Firefox resolve all <name>.localhost domains to localhost per default, so you don't have to add them to the hosts file. I setup a docker proxy on port 80 that resolves all requests from <containername>.localhost to the first exposed port of that container (in order of appearing in the docker compose file) automatically which makes everything smooth without manual steps for docker compose based setups.
It's probably both. Browsers now have built-in DoH so they usually do their own resolving. Only if you disable "secure DNS" (or you use group policies) will you fall back to the system resolver anymore.
Using real domain names lets you experience the web as it is in production. Localhost has a bunch of exceptions (i.e. HTTP URLs are treated as secure, CORS acts funny, etc.). Using domain names disables special handling of localhost URLs that'll help you spot problems before they hit production.
It's `myapp.localhost` (without the port number). It's more useful because it's easier to allocate and remember a unique name than a unique port number.
The comparison is `myapp.localhost` vs `localhost:3000`. This is especially useful when you have web servers permanently running on your computer on ports, not just for momentaneous local development.
Maybe you have a stack of applications that needs to communicate. Seeing db.localhost is a little easier to read that db:3360, but especially if you have multiple web applications. It's easier to read sso.localhost, api.localhost, and www.localhost.
They also show having the webserver to the TLS, that might be helpful.
Note the use of the Caddy webserver (you could also use nginx or whatever), which proxies to the port, so it's just myapp.localhost. I like this because it mirrors our production site. We can have subdomain.myapp.localhost and subdomain.myapp.com so links and everything work properly in both environments (assuming you have an env variable for the base domain)
I pondered the question of local-only domains since long ago, and in consultation with Chris Siebenmann, I determined that the most courteous way was actually to subdomain from my ISP.
That’s right: I invented a fictitious subdomain under one my ISP controlled and I never registered it or deployed public DNS for it. It worked great, for my dumb local purposes.
Thus it was easy to remember, easy to add new entries, and was guaranteed to stay out of the way from any future deployments, as long as my ISP never chose to also use the unique subdomain tag I invented...
We have a separate domain registered, where you can add any wildcard subdomain, so webui.company-test.com and that will resolve to 127.0.0.1. Then we can do pretty much the same.
I'm not entirely sure how I feel about it, but at least it's on a completely separate domain.
Can you expand on this? you redirect *.local.example.com to 127.0.0.1, and then how do you setup the local machine so that eg myservice.local.example.com hits the correct port? I guess you still need a proxy somewhere? or you specify eg myservice.local.example.com:3000 ?
Any subdomain of .localhost works out-of-the-box on Linux, OpenBSD and plenty of other platforms.
Of note, it doesn't work on macOS. I recall having delivered a coding assignment for a job interview long ago, and the reviewer said it didn't work for them, although the code all seemed correct to them.
It turned out on macOS, you need to explicitly add any subdomains of .localhost to /etc/hosts.
I'm still surprised by this; I always thought that localhost was a highly standard thing covered in the RFC long long ago… apparently it isn't, and macOS still doesn't handle this TLD.
$ ping hello.localhost
PING hello.localhost (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.057 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.162 ms
This usually happens because you have a Linux setup that doesn't use systemd-resolved and it also doesn't have myhostname early enough in the list of name resolvers. Not sure how many Linux systems default to this, but if you want this behavior, adjust your NSS configuration, most likely.
You don't need systemd-resolved for .localhost domains to work. It works on systemd-based distros using another resolver as well as non-systemd distros.
I've never seen this not-work on any distro, must be a niche thing.
It's easy to be tricked into thinking macOS supports it, because both Chrome and Curl support it. However, ping does not, nor do more basic tools like Python's request library (and I presume urllib as well).
Rather big caveat IMO. As a side note, your domain doesn't seem to have an AAAA record (which [.]localhost binds to by default on most of my machines, at least).
211 comments
[ 2.8 ms ] story [ 228 ms ] threadThat said, I do use mDNS/Bonjour to resolve .local addresses (which is probably what breaks .local if you're using it as a placeholder for a real domain). Using .local as a imaginary LAN domain is a terrible idea. These days, .internal is reserved for that.
I use it extensively on my LAN with great success, but I have Macs and Linux machines with Avahi. People who don't shouldn't mess with it...
https://en.wikipedia.org/wiki/.local
https://en.wikipedia.org/wiki/.localhost
Practically speaking, HTTPS on LAN is essentially useless, so I don't see the benefits. If anything, the current situation allows the user to apply TOFU to local devices by adding their unsigned certs to the trust store.
The existing exception mechanisms already work for this, all you need to do is click the "continue anyway" button.
Public wifi isn't a thing? Nobody wants to admin the router on a wifi network where there might be untrusted machines running around?
In practice, you probably want an authorized network for management, and an open network with the management interface locked out, just in case there's a vulnerability in the management interface allowing auth bypass (which has happened more often than anyone would like).
I agree on the latter, but that means your IoT devices being accessible through both networks and being able to discriminate which requests are coming from the insecure interface and which are coming from secure admin, which isn't practical for lay users to configure as well. I mean, a router admin screen can handle that but what about other devices?
I know it seems pedantic, but this UI problem is one of many reasons why everything goes through the Cloud instead of our own devices living on our own networks, and I don't like that controlling most IoT devices (except router admin screens) involves going out to the Internet and then back to my own network. It's insecure and stupid and violates basic privacy sensibilities.
Ideally I want end users to be able to buy a consumer device, plug it into their router, assign it a name and admin-user credentials (or notify it about their credential server if they've got one), and it's ready and secure without having to do elaborate network topology stuff or having to install a cert onto literally every LAN client who wants to access its public interface.
* It's reserved so it's not going to be used on the public internet.
* It is shorter than .local or .localhost.
* On QWERTY keyboards "test" is easy to type with one hand.
.local also works fine, of course, if you enable mDNS and don't try to use normal DNS.
At this point a lot of TLD changes are going to step on someone's project or home/business/private network. I think .local is a good name for mDNS. I appreciate why you maybe aren't happy with it, but don't share your concern.
There's no reason .mdns or .mdns.arpa couldn't have just been added to the default domains search list (the list of suffixes tried for non FQDN searches); which given it ISN'T a nice human obvious word to append wouldn't have conflicted with anyone who'd already had a .local at the time, and anyone else in the future who thinks an obvious phrase like .local would not be in use by some other resolver system.
https://weblogs.asp.net/owscott/introducing-testing-domain-l...
It's a neat trick, but it comes with some caveats. For instance, `localhost` often resolves to both 127.0.0.1 and ::1, but `.localhost` is described in RFC2606 as "traditionally been statically defined in host DNS implementations as having an A record pointing to the loop back IP address and is reserved for such use". In other words, your server may be binding to ::1 but your browser may be resolving 127.0.0.1. I'm sure later RFCs rectify the lack of IPv6 addressing, but I wouldn't assume everyone has updated to support those.
Another neat trick to combine with .localhost is using 127.0.0.0/8. There's nothing preventing you from binding server/containers to 127.0.0.2, 127.1.2.3, or 127.254.254.1. Quite useful if you want to run multiple different web servers together.
Of course, in the early internet, the difference between a TLD and a host name weren't quite as clear as they are right now.
I cannot ping xyz.localhost because it doesn't resolve it.
[0] https://datatracker.ietf.org/doc/rfc2606/
I've had nothing but trouble with .local and .localhost. Specifically, .local is intended for other purposes (multicast DNS) and .localhost has a nasty habit of turning into just "localhost" and in some cases, resolvers don't like to allow that to point to anything other than 127.0.0.1.
More recently, I've stuck to following the advice of RFC 6762 and use an actual registered TLD for internal use, and then sub-domain from there. I don't use my "production" TLD, but some other, unrelated TLD. For example, if my company is named FOO and our corporate homepage is at foo.com, I'll have a separate TLD like bar.com that I'll use for app development (and sub-domain as dev.bar.com, qa.bar.com, and maybe otherqa.bar.com as needed for different environments). That helps avoid any weirdness around .localhost, works well in larger dev/qa environments that aren't running on 127.0.0.1, and allows me to do things like have an internal CA for TLS instead of using self-signed certs with all of their UX warts.
For "local network" stuff, I stick to ".internal" because that's now what IANA recommends. But I would distinguish between how I use ".internal" to mean "things on my local network" from "this is where my team deploys our QA environment", because we likely aren't on the same network as where that QA environment is located and my ".internal" might overlap with your ".internal", but the QA environment is shared.
https://www.man7.org/linux/man-pages/man8/libnss_myhostname....
(There are lots of other useful NSS modules, too. I like the libvirt ones. Not sure if there's any good way to use these alongside systemd-resolved.)
The ability to add host entries via an environment variable turned out to be more useful than I'd expected, though mostly for MITM(proxy) and troubleshooting.
1: https://github.com/aib/nss-userhosts
Whenever a host requests a DHCP lease it receives its assigned IP which matches the unbound record, then I can always access it by hostname.
Never needed the entry
[1]: https://en.wikipedia.org/wiki/.internal
https://github.com/nodesocket/godns
The OpenWrt wiki on Homenet suggests the project might be dead: https://openwrt.org/docs/guide-user/network/zeroconfig/hncp_...
Anyone familiar with HNCP? Are there any concerns of conflicts if HNCP becomes "a thing"? I have to say, .home.arpa doesn't exactly roll of the tongue like .internal. Some macOS users seem to have issues with .home.arpa too: https://www.reddit.com/r/MacOS/comments/1bu62do/homearpa_is_...
In my native language (Finnish) it's even worse, or better, depending on personal preference - it translates directly to .mildew.lottery-ticket.
home.arpa is for HNCP.
Use .internal.
If I were going to do a bunch of extra work messing with configs I'd be far more inclined to switch all my personal stuff over to GNS for security and privacy reasons.
> A network-wide zone is appended to all single labels or unqualified zones in order to qualify them. ".home" is the default; [...]
> As of March 7, 2025, the domain has not been standardized by the Internet Engineering Task Force (IETF), though an Internet-Draft describing the TLD has been submitted.
https://www.icann.org/en/board-activities-and-meetings/mater...
> Resolved (2024.07.29.06), the Board reserves .INTERNAL from delegation in the DNS root zone permanently to provide for its use in private-use applications.
This can be addressed by hijacking an existing TLD for private use, e.g. mything.bb :^)
If you want to be sure, use mything./ : the . at the end makes sure no further domains are appended during DNS lookup, and the / makes the browser try to access to resource without Googling it.
That's hardly the only example of annoying MONOBAR behavior.
This problem could have been avoided if we had different widgets for doing different things. Someone should have thought of that.
Ref: https://www.icann.org/en/board-activities-and-meetings/mater...
Each service is then exposed via '<service>.local.<domain>'.
This has been working flawlessly for me for some time.
That's not redirection per se, a word that's needlessly overloaded to the point of confusion. It's a smart use of a reverse proxy.
It would be nice if you all reserved the word "redirect" for something like HTTP 3xx behavior.
EDIT: on linux and don't use launchd, so I'd still the port number
Self sign a certificate and add it to your trusted certificate list.
Or - use https://pinggy.io
They also show having the webserver to the TLS, that might be helpful.
That’s right: I invented a fictitious subdomain under one my ISP controlled and I never registered it or deployed public DNS for it. It worked great, for my dumb local purposes.
Example:
Thus it was easy to remember, easy to add new entries, and was guaranteed to stay out of the way from any future deployments, as long as my ISP never chose to also use the unique subdomain tag I invented...I'm not entirely sure how I feel about it, but at least it's on a completely separate domain.
It works really well and means no setup on our developers machines
Then we just have an entry for local.example.com in our vhosts and bam everything works as expected. No need to mess with /etc/hosts
Of note, it doesn't work on macOS. I recall having delivered a coding assignment for a job interview long ago, and the reviewer said it didn't work for them, although the code all seemed correct to them.
It turned out on macOS, you need to explicitly add any subdomains of .localhost to /etc/hosts.
I'm still surprised by this; I always thought that localhost was a highly standard thing covered in the RFC long long ago… apparently it isn't, and macOS still doesn't handle this TLD.
No, not here.
I've never seen this not-work on any distro, must be a niche thing.
I’m assuming that typo is intentional?
Rather big caveat IMO. As a side note, your domain doesn't seem to have an AAAA record (which [.]localhost binds to by default on most of my machines, at least).