What Is Localhost? A Complete Guide to 127.0.0.1, Loopback, and Local Development
If you have ever typed http://localhost:3000 into a browser, seen 127.0.0.1 in a config file, or wondered why your dev server only works on your own machine, this guide is for you. Localhost is one of the most fundamental concepts in networking and software development. Understanding it fully, including the difference between localhost, 127.0.0.1, and 0.0.0.0, how ports work, what the hosts file does, why Docker changes everything, and how to share your localhost with the outside world, will make you a noticeably better developer.
What Is Localhost? (Quick Answer)
One-Paragraph Definition
Localhost is a hostname that refers to the computer you are currently using. When a program connects to localhost, the connection never leaves the machine. It loops back to the same device through a special virtual network interface called the loopback interface. The IP address 127.0.0.1 is the standard IPv4 address for localhost. The IPv6 equivalent is ::1. Both always point to your own computer, on any operating system, in any country, without requiring an internet connection.
How the Loopback Interface Works
To understand localhost, you need to understand the loopback interface. When you send data to a normal IP address, it travels through your network interface card (NIC), across a cable or Wi-Fi, and through routers and switches until it reaches its destination. Loopback is different: it is a purely virtual, software-only interface that exists in your operating system's networking stack.
When your operating system sees a packet addressed to any address in the 127.0.0.0/8 block, it intercepts that packet before it ever reaches the physical network hardware. The packet is immediately delivered back to the same machine, creating a loop. This is where the name loopback comes from.
Your application sends a request to 127.0.0.1:3000
For example, your browser requests http://localhost:3000. The OS resolves "localhost" to 127.0.0.1 and begins routing the packet.
The OS intercepts the packet at the network layer
The TCP/IP stack recognizes that 127.0.0.1 is in the reserved loopback range. The packet is diverted before it ever touches the network card.
The packet is delivered to the listening process on the same machine
The OS sends the packet to whichever process is listening on port 3000. If your dev server is running there, it receives the request and sends back a response through the same loopback path.
The response returns through the loopback and your browser renders the page
The entire round trip happens entirely within your OS. No network hardware is involved, which is why loopback latency is typically under 1 millisecond.
Because loopback never touches physical network hardware, it works whether your Wi-Fi is off, your Ethernet cable is unplugged, or you are on a plane with no connectivity. Your dev server on localhost:3000 is always reachable from the same machine regardless of network status.
localhost vs 127.0.0.1 vs 0.0.0.0: What Is the Difference?
These three addresses appear constantly in development and configuration files, but they are not the same thing. Mixing them up causes subtle bugs that are difficult to diagnose.
| Address | Type | Resolves To | Accessible From | Use Case |
|---|---|---|---|---|
localhost |
Hostname | 127.0.0.1 or ::1 (via hosts file) |
Same machine only | Readable config, dev servers |
127.0.0.1 |
IPv4 loopback IP | Itself (no DNS lookup) | Same machine only | Explicit loopback, faster (no DNS) |
::1 |
IPv6 loopback IP | Itself (no DNS lookup) | Same machine only | IPv6 environments |
0.0.0.0 |
Wildcard address | All network interfaces | Any device on the network (and internet if port is open) | Expose service to other machines |
localhost is a hostname, not an IP address
When you type localhost, your OS does a name lookup. It first checks the local hosts file (/etc/hosts on macOS/Linux, C:\Windows\System32\drivers\etc\hosts on Windows). The hosts file typically contains this line:
127.0.0.1 localhost
::1 localhost
The OS finds this entry and resolves localhost to 127.0.0.1 (or ::1 for IPv6-first systems). This is slightly slower than using 127.0.0.1 directly because it involves a file lookup, but the difference is negligible in practice.
On modern Linux systems and some macOS configurations, localhost resolves to ::1 (IPv6) rather than 127.0.0.1 (IPv4). If your server is only listening on 127.0.0.1 and your client connects via localhost which resolves to ::1, the connection will fail. This is a common source of confusing "connection refused" errors. Test with ping -4 localhost (force IPv4) and ping -6 localhost (force IPv6) to see which is being used. You can also use 127.0.0.1 directly to bypass this ambiguity.
0.0.0.0 is completely different
When a server binds to 0.0.0.0, it listens on all network interfaces simultaneously: loopback (127.0.0.1), your local Wi-Fi or Ethernet IP (e.g., 192.168.1.50), and any other interfaces. This means other devices on your network (and potentially the internet, if your firewall allows it) can reach the service.
# These are NOT equivalent:
python -m http.server --bind 127.0.0.1 8000 # Only your machine can connect
python -m http.server --bind 0.0.0.0 8000 # Anyone on your network can connect
python -m http.server 8000 # Usually defaults to 0.0.0.0
The Full Loopback Range: 127.0.0.0/8
Most developers only ever use 127.0.0.1, but the entire 127.0.0.0/8 block is reserved for loopback. This is a Class A network containing over 16 million addresses, from 127.0.0.1 to 127.255.255.254. Every single one of them loops back to your own machine.
This has a practical use: you can run multiple services that each need their own dedicated IP address on the same machine, without using a full virtual machine. For example:
# Bind different services to different loopback IPs:
nginx listening on 127.0.0.1:80
apache listening on 127.0.0.2:80
another web server on 127.0.0.3:80
# All three are on the same machine but with distinct IPs
# Useful for SSL certificate testing, virtual host configs, etc.
Understanding Ports with Localhost
Localhost alone is not enough to reach a specific service. You also need a port number. A port is a 16-bit number (0-65535) that identifies a specific process or service on a machine. When you type http://localhost:3000, you are connecting to the process listening on port 3000 on the loopback interface.
| Port | Service | Typical localhost URL |
|---|---|---|
| 3000 | Node.js / React dev server | http://localhost:3000 |
| 4200 | Angular dev server | http://localhost:4200 |
| 5173 | Vite dev server | http://localhost:5173 |
| 8000 | Django / Python HTTP server | http://localhost:8000 |
| 8080 | Spring Boot / generic HTTP | http://localhost:8080 |
| 8123 | Home Assistant | http://localhost:8123 |
| 3306 | MySQL | Connection string: 127.0.0.1:3306 |
| 5432 | PostgreSQL | Connection string: 127.0.0.1:5432 |
| 6379 | Redis | Connection string: 127.0.0.1:6379 |
| 27017 | MongoDB | Connection string: 127.0.0.1:27017 |
| 11434 | Ollama (local LLM) | http://localhost:11434 |
Ports 0-1023 are "well-known ports" reserved for system services (HTTP on 80, HTTPS on 443, SSH on 22, etc.) and require elevated privileges to bind on most operating systems. Ports 1024-49151 are "registered ports" commonly used by applications. Ports 49152-65535 are "dynamic ports" used for ephemeral client connections. Development servers typically use ports in the 3000-9999 range.
The Hosts File: Where localhost Gets Defined
The hosts file is a plain text file on every operating system that maps hostnames to IP addresses. It is checked before any DNS query is made. The entry 127.0.0.1 localhost in this file is what makes the name "localhost" work.
Hosts File Locations
| OS | Path | Edit Command |
|---|---|---|
| Linux | /etc/hosts | sudo nano /etc/hosts |
| macOS | /etc/hosts | sudo nano /etc/hosts |
| Windows | C:\Windows\System32\drivers\etc\hosts | Open Notepad as Administrator |
The default hosts file content related to localhost looks like this:
127.0.0.1 localhost
127.0.0.1 localhost.localdomain
::1 localhost
::1 localhost.localdomain
You can add your own entries to create custom local hostnames for development:
# Add custom local domains for development:
127.0.0.1 myapp.local
127.0.0.1 api.myapp.local
127.0.0.1 admin.myapp.local
After saving the hosts file, http://myapp.local in your browser will resolve to your local machine. This is useful for testing multi-domain setups, cookie behavior across subdomains, and SSL certificate configurations that require real-looking domain names.
Your OS and browser cache DNS lookups. After editing the hosts file, flush the cache to see the changes immediately:
# macOS:
sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder
# Linux (systemd-resolved):
sudo systemd-resolve --flush-caches
# Windows:
ipconfig /flushdns
Common Localhost Errors and How to Fix Them
❌ "This site can't be reached" / "localhost refused to connect" (ERR_CONNECTION_REFUSED)
This means nothing is listening on the port you requested. Either your server is not running, it crashed on startup, or it is listening on a different port. Check your terminal for server output and verify the port with:
# macOS / Linux: find what is listening on port 3000
lsof -i :3000
# Windows:
netstat -ano | findstr :3000
If nothing appears, your server is not running. Start it again.
❌ "Port already in use" / EADDRINUSE
Another process is already listening on the port you tried to use. Either stop the other process or change your server's port.
# macOS / Linux: find and kill the process on port 3000
lsof -ti:3000 | xargs kill -9
# Windows: find PID using the port, then kill it
netstat -ano | findstr :3000
taskkill /PID [PID] /F
❌ localhost resolves to ::1 instead of 127.0.0.1
On IPv6-first systems, localhost may resolve to the IPv6 loopback address ::1. If your server only binds to 127.0.0.1, connections via localhost will fail. Either use 127.0.0.1 directly, configure your server to also bind to ::1, or update your hosts file to prioritize IPv4.
❌ CORS errors when frontend calls backend on localhost
Browsers treat localhost:3000 and localhost:8000 as different origins, even though they are on the same machine. This is correct CORS behavior. Your backend needs to include the frontend's origin in its CORS allow list. For development, allow http://localhost:3000 in your server's CORS configuration.
❌ Mixed content warnings (HTTP localhost behind HTTPS)
Modern browsers block HTTP requests from HTTPS pages. If your production site runs on HTTPS and calls an API on http://localhost, the browser will block it. Use a self-signed certificate for your local API server, or configure a local HTTPS proxy like mkcert to generate a trusted local certificate.
localhost in Different Contexts
Inside Docker Containers
Docker containers have their own isolated network stack. Inside a container, localhost and 127.0.0.1 refer to the container itself, not to your host machine. This is one of the most common sources of confusion for developers moving to containerized development.
| What you want to reach | From inside a container, use... |
|---|---|
| A service inside the same container | localhost or 127.0.0.1 |
| Your host machine (Mac/Windows Docker Desktop) | host.docker.internal |
| Your host machine (Linux Docker) | 172.17.0.1 (default Docker bridge gateway) |
| Another container in the same Docker Compose network | The service name (e.g., db, redis) |
# Wrong: this connects to 127.0.0.1 INSIDE the container, not the host
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
# Right: connect to host machine's PostgreSQL from inside a container (Mac/Windows)
DATABASE_URL=postgresql://user:pass@host.docker.internal:5432/mydb
# Right: connect to a Compose service named "db"
DATABASE_URL=postgresql://user:pass@db:5432/mydb
Inside Kubernetes Pods
In Kubernetes, each Pod has its own network namespace. localhost inside a Pod refers to the Pod itself. Containers within the same Pod share the network namespace and can reach each other via localhost and different ports. To reach a different Pod or a Service, use the Kubernetes DNS name (e.g., my-service.my-namespace.svc.cluster.local).
In Database Connection Strings
When a database (MySQL, PostgreSQL, Redis, MongoDB) runs on the same machine as your application, you connect to it via 127.0.0.1 or localhost. Some databases (notably MySQL) treat these differently: connecting to localhost on Linux uses a Unix domain socket (a faster IPC mechanism), while connecting to 127.0.0.1 uses TCP even if the server is local.
# MySQL: these may behave differently on Linux
mysql -h localhost # Uses Unix socket: /var/run/mysqld/mysqld.sock
mysql -h 127.0.0.1 # Uses TCP connection on port 3306
# PostgreSQL: similar behavior
psql -h localhost # May use Unix socket
psql -h 127.0.0.1 # Forces TCP
IPv4 Loopback (127.0.0.1) vs IPv6 Loopback (::1)
127.0.0.1 (IPv4)
- Universal compatibility, every tool supports it
- No DNS lookup required (direct IP)
- Unambiguous: always IPv4
- Easier to type and remember
- No issues with IPv4/IPv6 dual-stack ambiguity
::1 (IPv6)
- Some modern systems prefer IPv6 by default
- Required when testing IPv6-specific behavior
- Used when localhost resolves to IPv6 first
- May cause issues if server only binds IPv4
For most day-to-day development, use 127.0.0.1 explicitly when you need to guarantee IPv4 behavior, or localhost when readability matters and you are confident about your system's resolution order. You can check which version your system uses:
# Check which IP localhost resolves to on your machine:
ping localhost
# Force IPv4:
ping -4 localhost
# Force IPv6:
ping -6 localhost
# Check your /etc/hosts to see how localhost is defined:
cat /etc/hosts | grep localhost # macOS / Linux
type C:\Windows\System32\drivers\etc\hosts | findstr localhost # Windows
Security Implications of Localhost
🔒 Services on localhost are NOT automatically private on shared machines
If multiple users share a machine (a server with SSH access, a university lab computer), any of those users can connect to services running on localhost. A database running on 127.0.0.1:5432 without a password is accessible to all local users. Always add authentication to services, even local ones, on any shared system.
🌐 Localhost does NOT mean internet-private
If your dev server binds to 0.0.0.0 instead of 127.0.0.1, it is accessible to anyone on your local network. Many frameworks default to 0.0.0.0 for development convenience. Always check what IP your dev server binds to, especially when working in coffee shops or shared offices.
🍪 Browser security treats localhost as a secure context
Modern browsers grant localhost special "secure context" status, which means web APIs that require HTTPS (like camera access, service workers, and Web Crypto) work on http://localhost without a certificate. This is a deliberate browser design decision to make local development easier. 127.0.0.1 also receives this treatment in most browsers.
🚫 SSRF and localhost in cloud environments
Server-Side Request Forgery (SSRF) attacks exploit application features that make outbound requests by tricking them into requesting localhost or internal cloud metadata endpoints (like http://169.254.169.254 on AWS). If your application accepts user-supplied URLs and fetches them, sanitize and validate these inputs to prevent attackers from reading your instance metadata or internal services.
When You Need to Expose Localhost to the Internet
Localhost is intentionally private. But there are many legitimate scenarios where you need to share what is running on localhost with someone outside your machine:
How to Expose Localhost to the Internet with Localtonet
Localtonet is a tunneling service that creates an encrypted connection from your local machine to a public HTTPS (or TCP/UDP) endpoint. When someone accesses the public URL, the request travels through the tunnel and is handled by your localhost server. No port forwarding required, no static IP needed, and it works behind NAT and CGNAT.
Expose Your Localhost in 3 Steps
Install Localtonet and authenticate
# macOS:
brew tap localtonet/tap && brew install localtonet
# Linux:
curl -fsSL https://localtonet.com/install.sh | sh
# Authenticate (copy your token from localtonet.com/usertoken):
localtonet --authtoken YOUR_TOKEN_HERE
Create a tunnel in the dashboard
Go to localtonet.com/tunnel/http for web servers, or localtonet.com/tunnel/tcpudp for TCP/UDP services. Enter IP 127.0.0.1 and the port your localhost service uses. Click Create, then Start.
Share the public URL
The dashboard shows a public URL like https://myapp.localto.net. Anyone can open this URL and reach your localhost server. The tunnel works as long as Localtonet is running and your server is listening.
| Use Case | Local Address | Tunnel Type |
|---|---|---|
| React / Vue / Next.js dev server | 127.0.0.1:3000 | HTTP |
| Django / FastAPI backend | 127.0.0.1:8000 | HTTP |
| Home Assistant | 127.0.0.1:8123 | HTTP |
| MySQL database | 127.0.0.1:3306 | TCP |
| Remote ADB debugging | 127.0.0.1:5555 | TCP |
| Game server | 127.0.0.1:27015 | UDP or TCP-UDP |
| Local LLM (Ollama) | 127.0.0.1:11434 | HTTP |
Frequently Asked Questions
What is localhost?
Localhost is a hostname that refers to the computer you are currently using. When any program connects to localhost, the connection never leaves the machine. It uses a virtual loopback interface built into every operating system's networking stack. Localhost always resolves to the IP address 127.0.0.1 (IPv4) or ::1 (IPv6). It is most commonly used by developers to run and test web servers, databases, and APIs on their own machines before deploying to the internet.
What is the difference between localhost and 127.0.0.1?
localhost is a hostname that gets resolved to an IP address via the hosts file. 127.0.0.1 is the IPv4 loopback IP address itself. In most cases they reach the same destination, but they differ in one important way: using localhost involves a name lookup (checked in the hosts file), while 127.0.0.1 is used directly with no lookup. On IPv6-first systems, localhost may resolve to ::1 instead of 127.0.0.1, which can cause connection failures if the server only listens on IPv4.
Why does localhost work without an internet connection?
Localhost uses the loopback interface, which is a virtual network interface that exists entirely in software within your operating system. No physical network hardware (Wi-Fi card, Ethernet port) is involved. Traffic sent to 127.0.0.1 is intercepted by the OS before it reaches any hardware and delivered directly to the destination process. This is why localhost always works, even when your internet and Wi-Fi are completely off.
What does "localhost refused to connect" mean?
"Localhost refused to connect" (or ERR_CONNECTION_REFUSED) means that nothing is listening on the port you tried to connect to. The loopback interface is working correctly, but no process is accepting connections on that specific port. The most common causes are: your server is not running or crashed on startup, the server is listening on a different port than you specified, or the server is binding to 127.0.0.1 but your browser is connecting via ::1 (IPv6). Check your terminal for server output and verify the correct port.
What is the difference between localhost and 0.0.0.0?
localhost (and 127.0.0.1) only accepts connections from the same machine. 0.0.0.0 is a wildcard address that tells a server to listen on all available network interfaces simultaneously, including the loopback interface, your Wi-Fi IP, your Ethernet IP, and any others. A server bound to 0.0.0.0 is reachable from other devices on your local network (and potentially the internet if no firewall blocks it). A server bound to 127.0.0.1 is only reachable from the same machine.
How can I access localhost from another device or share it with someone?
There are two main approaches. For devices on the same local network, bind your server to 0.0.0.0 and share your machine's local IP address (e.g., 192.168.1.50:3000). For access from anywhere over the internet (webhook testing, client demos, remote access), use a tunnel service like Localtonet. Localtonet creates a public HTTPS URL that forwards traffic to your localhost server without requiring port forwarding, a static IP, or any router configuration.
Why does localhost mean something different inside Docker?
Each Docker container has its own isolated network namespace with its own loopback interface. Inside a container, localhost and 127.0.0.1 refer to the container itself, not to the host machine running Docker. To reach your host machine from inside a container, use host.docker.internal on Docker Desktop (Mac/Windows) or the Docker bridge gateway IP 172.17.0.1 on Linux. To reach another container in the same Docker Compose network, use the service name defined in your docker-compose.yml.
Ready to Share Your Localhost with the World?
Localtonet creates a secure public HTTPS URL for any localhost port in minutes. No port forwarding. No static IP. Works on any network. Free to start.
Expose Your Localhost Free →