localhost:8000 is port 8000 on your own computer, and it's the default for Django's runserver, Python's python -m http.server, Laravel's php artisan serve, uvicorn and FastAPI. Gatsby and MkDocs use it too. Opening http://localhost:8000 connects to whichever of these is running. ERR_CONNECTION_REFUSED means none of them is.
What runs on port 8000
| Tool | Default on 8000? | Start command |
|---|---|---|
| Django | Yes (127.0.0.1:8000) | python manage.py runserver |
| Python static server | Yes | python -m http.server |
| Laravel | Yes | php artisan serve |
| uvicorn / FastAPI | Yes | uvicorn main:app --reload or fastapi dev |
| Gatsby | Yes | gatsby develop |
| MkDocs | Yes | mkdocs serve |
| PHP built-in server | By convention | php -S localhost:8000 |
Flask uses localhost:5000 and Jupyter uses localhost:8888.
Fix "localhost:8000 refused to connect"
- Is the server running? Django prints
Starting development server at http://127.0.0.1:8000/. If the command exited, a migration error, import error or missing.envvalue is usually shown just above. - Is it bound to the right address? Django, uvicorn and Laravel bind to
127.0.0.1by default. That's fine from your own browser, but not from Docker, WSL or another machine (see below). - Docker. Run the server on
0.0.0.0inside the container (runserver 0.0.0.0:8000,uvicorn main:app --host 0.0.0.0) and publish it with-p 8000:8000. - Got a page but a 400? Django returns Bad Request (400) when the hostname isn't in
ALLOWED_HOSTS. That's a config problem, not a connection one.
Find and free a busy port 8000
Error: That port is already in use. (Django) or [Errno 48] Address already in use (Python on macOS) means an old server is still running, often a runserver whose autoreloader child survived.
# macOS / Linux
lsof -i :8000
kill -9 $(lsof -ti :8000)
# Windows
netstat -ano | findstr :8000
taskkill /PID <pid> /F
Or pick another port:
python manage.py runserver 8001
python -m http.server 8001
php artisan serve --port=8001
uvicorn main:app --port 8001
Open localhost:8000 from another device
Listen on all interfaces, then use your LAN IP from the other device:
python manage.py runserver 0.0.0.0:8000
uvicorn main:app --host 0.0.0.0 --port 8000
php artisan serve --host=0.0.0.0
python -m http.server 8000 --bind 0.0.0.0
For Django, add the IP to ALLOWED_HOSTS (with DEBUG = True and an empty list, only localhost names are allowed). Find the IP with ipconfig getifaddr en0 (macOS), hostname -I (Linux) or ipconfig (Windows), then open http://192.168.x.x:8000.
Share localhost:8000 and receive webhooks
Port 8000 is where a lot of webhook handlers get written: a Django view for Stripe events, a Laravel route for Shopify, a FastAPI endpoint for GitHub. The provider needs a public URL, and localhost isn't one.
To receive webhooks, forward them to the handler route:
relay forward --bucket my-api http://localhost:8000/webhooks/stripe/
Webhook Relay gives the bucket a permanent public URL. Paste that into the provider dashboard, and every webhook is delivered to your local route and logged so you can replay it after fixing a bug. Remember to exempt the webhook view from CSRF (@csrf_exempt) and verify the webhook signature instead. Laravel needs the route excluded from CSRF verification too.
To share the whole app with someone, use a tunnel:
relay connect --name my-django-app http://localhost:8000
For Django, add the tunnel hostname to ALLOWED_HOSTS and https://<hostname> to CSRF_TRUSTED_ORIGINS, or logins and form posts fail with a 403 CSRF error.
