localhost:8080 is port 8080 on your own computer, the conventional "alternative HTTP" port, and the default for Apache Tomcat, Jenkins, Spring Boot, Jetty, Vue CLI and webpack-dev-server. Because 80 needs root on most systems, 8080 became the go-to unprivileged web port, so lots of Docker images listen on it too. If the browser shows ERR_CONNECTION_REFUSED, nothing is listening on 8080 right now.
What runs on port 8080
| Tool | Default on 8080? | Start command |
|---|---|---|
| Spring Boot | Yes (server.port) | ./mvnw spring-boot:run or ./gradlew bootRun |
| Apache Tomcat | Yes (HTTP connector) | bin/startup.sh |
| Jenkins | Yes | java -jar jenkins.war or the Docker image |
| Jetty | Yes | java -jar start.jar |
| Vue CLI / webpack-dev-server | Yes | npm run serve |
http-server (npm) | Yes | npx http-server |
| Docker images (Keycloak, Adminer, Traefik dashboard and others) | Inside the container | docker run -p 8080:8080 ... |
Many Go and Java tutorials also hard-code :8080. Two apps that both want 8080 is one of the most common local conflicts, which is why the next port people reach for is 8081.
Fix "localhost:8080 refused to connect"
- Confirm the server started. Spring Boot logs
Tomcat started on port 8080; Jenkins logsJenkins is fully up and running. If you don't see that line, read the stack trace above it. - Check whether it's still starting. Jenkins and large Spring apps can take 20 to 60 seconds before the port opens. Refreshing too early looks exactly like a refused connection.
- Docker port mapping.
docker psshould show0.0.0.0:8080->8080/tcp. No mapping means the port is only open inside the container. The app also has to bind0.0.0.0, not127.0.0.1, inside the container. - Context path. Tomcat serves each WAR under its own path, so your app may be at
http://localhost:8080/myapp/while/shows the Tomcat page or a 404.
Find and free a busy port 8080
Web server failed to start. Port 8080 was already in use. (Spring Boot) or java.net.BindException: Address already in use means another process owns the port.
# macOS / Linux
lsof -i :8080
kill -9 $(lsof -ti :8080)
# a container is often the culprit
docker ps --filter "publish=8080"
# Windows
netstat -ano | findstr :8080
taskkill /PID <pid> /F
To move your app instead:
- Spring Boot:
server.port=8081inapplication.properties, or--server.port=8081 - Tomcat: change
<Connector port="8080" ...>inconf/server.xml - Jenkins:
java -jar jenkins.war --httpPort=8081 - Vue CLI:
npm run serve -- --port 8081 - Docker: keep the container port, change the host side:
-p 8081:8080
Open localhost:8080 from another device
Spring Boot and Tomcat listen on all interfaces by default, so http://YOUR-LAN-IP:8080 usually works straight away from a phone on the same Wi-Fi. If it doesn't, the OS firewall is blocking the port (on Windows, allow Java through Windows Defender Firewall). Dev servers like Vue CLI need --host 0.0.0.0. Find your LAN IP with ipconfig getifaddr en0 (macOS), hostname -I (Linux) or ipconfig (Windows).
Share localhost:8080 publicly
To show the app to someone outside your network, run a tunnel next to it:
relay connect --name my-app http://localhost:8080
The relay CLI prints a public HTTPS URL that forwards to port 8080. Use the same --name and the URL stays the same after restarts.
The classic 8080 case is Jenkins on a laptop or office server that needs GitHub or GitLab push webhooks. You don't have to expose the whole Jenkins UI for that. Forward only the webhook route:
relay forward --bucket jenkins http://localhost:8080/github-webhook/
Point the repository webhook at the bucket's public URL and each push is delivered to Jenkins, logged and replayable. The Jenkins webhooks guide walks through GitHub, Bitbucket, GitLab and Gitea, and securing Jenkins covers what to lock down before any of it is reachable.
