localhost:8000: Django, Python, Laravel and FastAPI dev port

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

ToolDefault on 8000?Start command
DjangoYes (127.0.0.1:8000)python manage.py runserver
Python static serverYespython -m http.server
LaravelYesphp artisan serve
uvicorn / FastAPIYesuvicorn main:app --reload or fastapi dev
GatsbyYesgatsby develop
MkDocsYesmkdocs serve
PHP built-in serverBy conventionphp -S localhost:8000

Flask uses localhost:5000 and Jupyter uses localhost:8888.

Fix "localhost:8000 refused to connect"

  1. 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 .env value is usually shown just above.
  2. Is it bound to the right address? Django, uvicorn and Laravel bind to 127.0.0.1 by default. That's fine from your own browser, but not from Docker, WSL or another machine (see below).
  3. Docker. Run the server on 0.0.0.0 inside the container (runserver 0.0.0.0:8000, uvicorn main:app --host 0.0.0.0) and publish it with -p 8000:8000.
  4. 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.

Frequently asked questions

What is localhost:8000?

localhost:8000 is port 8000 on your own machine. It is the default for Django's runserver, Python's built-in python -m http.server, Laravel's php artisan serve, uvicorn and the FastAPI CLI, Gatsby's develop server and MkDocs.

Why does localhost:8000 refuse to connect?

No process is listening on port 8000. The dev server may not be running, may have exited on an error, or may be bound to a different port. In Docker, the server must listen on 0.0.0.0 and the port must be published with -p 8000:8000.

How do I run Django on a different port?

Pass the address to runserver, for example python manage.py runserver 8001, or python manage.py runserver 0.0.0.0:8001 to also listen on all interfaces.

Why does Django say DisallowedHost when I open it through a tunnel?

Django only serves hostnames listed in ALLOWED_HOSTS. Add the tunnel hostname to ALLOWED_HOSTS, and for form posts over HTTPS also add https:// plus that hostname to CSRF_TRUSTED_ORIGINS.