The Port 6000 Mystery¶
May 5th, 2025. After years of development, countless iterations, and exhaustive testing, we finally released EventSourcingDB 1.0. The CI/CD pipeline was green. All integration tests passed. The documentation was polished. We had tested the database on different ports, different operating systems, different deployment scenarios. Everything worked exactly as intended.
We allowed ourselves a moment of relief. A decade of learning, building, failing, and rebuilding had culminated in this release. The product was solid. We were ready.
The First Bug, Hours After Launch¶
That relief lasted exactly a few hours.
Before the day was over, the first bug was reported: "Management UI doesn't load on port 6000."
The feeling was a mix of disbelief and concern. We had tested port configuration extensively – default port 3000, common alternatives like 8080, custom ports. Everything had worked. How could this slip through?
The report was specific: the API worked fine on port 6000. Requests succeeded. Data came back correctly. But the Management UI – the web-based interface for browsing events, running queries, and exploring the database – refused to load. Only on port 6000. Other ports worked without issue.
Our first instinct: user error. Maybe a firewall rule, a misconfiguration, something environmental. But when we tried to reproduce it ourselves, we hit the exact same problem. The API responded perfectly. The UI didn't load in Chrome. No error on the server side. Nothing in the logs. Just silence.
Something was blocking the UI, and it wasn't our code.
The Search for Answers¶
We started debugging the way you always do: methodically, suspecting the obvious first.
Had we accidentally hardcoded a block for port 6000 somewhere? We searched the entire codebase. Nothing.
Was there a routing issue in our web server configuration? We traced every request path. Everything looked correct.
Was it a CORS problem? We checked headers, origins, and policies. All fine.
We fired up the browser's network tools. That's when things got strange: the requests to the UI on port 6000 weren't even leaving the browser. They were being blocked before they hit the network. The browser console showed a terse, cryptic error message – something about the connection being refused for security reasons.
Security reasons? We weren't doing anything unusual. Just serving a web interface over HTTP. Why would the browser care which port we used?
Then someone on the team found it: a buried reference in a forum thread, a link to an old Chromium bug report, and finally, a piece of documentation we'd never thought to look for.
Browsers block certain ports by default.
The Explanation: Bad Port Lists¶
It turns out that all major browsers – Chrome, Firefox, Safari, Edge – maintain a list of ports that they refuse to connect to, regardless of whether the server is listening. These are called "bad ports" or "unsafe ports," and they exist to prevent a class of attacks known as protocol confusion or cross-protocol exploitation.
The idea is simple but clever: many network services run on well-known ports and speak non-HTTP protocols. FTP runs on port 21. SMTP runs on port 25. Telnet runs on port 23. If a malicious website could trick your browser into making an HTTP request to one of these ports on localhost or an internal server, it might be able to send commands that the service would interpret as valid protocol messages – even though they were crafted as HTTP requests.
This could enable attacks like:
- Sending emails via SMTP (port 25) without user consent
- Executing commands via Telnet (port 23) on local machines
- Triggering actions on internal services that trust localhost traffic
To prevent this, browsers outright refuse to connect to a long list of service ports, even if you explicitly request them. You can't override it. You can't disable it with a flag in production environments. The browser just says no.
And on that list, sitting quietly between others, are ports 6000 through 6063.
Why Port 6000? The X11 Connection¶
Port 6000 isn't random. It's the default port for the X Window System (X11) – the graphical server that powers most Unix and Linux desktops. X11 has been around since the mid-1980s and still runs on millions of systems today.
X11 works over the network: a client application sends drawing commands to the X server, which renders the interface. By default, the first X display (:0) listens on port 6000. Additional displays use 6001, 6002, and so on, up to 6063.
Historically, X11 servers were often configured to accept network connections without strong authentication. If an attacker could trick a browser into making requests to port 6000 on a local or internal machine, they might be able to send malicious X11 protocol commands – potentially capturing keystrokes, screenshots, or injecting input.
The risk was significant enough that browser vendors decided to block the entire range. Chrome, Firefox, Safari, and others all treat 6000-6063 as unsafe.
That decision was made years ago, buried in browser source code and specification documents. It's a sensible security measure. But it's invisible until you stumble into it.
The Full List of Blocked Ports¶
Port 6000 isn't alone. Browsers block dozens of other ports associated with various network services. Here are some notable examples:
- 21 – FTP
- 22 – SSH
- 23 – Telnet
- 25, 587 – SMTP (email)
- 110, 995 – POP3 (email)
- 143, 993 – IMAP (email)
- 6000 – X11
- 6665-6669 – IRC
The complete list is maintained in browser source code and varies slightly between implementations. For the official specification, see the WHATWG Fetch specification.
For EventSourcingDB running on port 6000, the result was clear: the API worked because tools like curl, Postman, or backend HTTP clients don't enforce these restrictions. But the browser-based Management UI was dead in the water.
Why Didn't Testing Catch This?¶
This is the question that haunted us.
We had tested port configuration. We had run the database on multiple ports during development. We had integration tests, end-to-end tests, manual testing sessions. How did port 6000 slip through?
The answer is uncomfortable but honest: we tested many ports, but not the blocked ones. We used common development ports: 3000, 8080, 8000, 5000. We tested custom high-numbered ports. But we never thought to test ports in the danger zones – the ones browsers explicitly reject.
Why would we? From a server perspective, there's no difference between port 6000 and port 6001 or port 5999. The operating system doesn't care. The HTTP protocol doesn't care. Our code doesn't care. The port is just a number in a configuration file.
But the browser cares. And we never thought to check.
It's a perfect edge case: invisible until you encounter it, obvious in hindsight, and nearly impossible to anticipate without prior knowledge. Our server-side tests ran perfectly – curl and automated HTTP clients connected without issue. The problem only appeared when a real user opened a real browser and tried to access the UI.
This is a humbling reminder: no matter how thorough your testing, production users will find scenarios you never considered. They use tools, environments, and configurations you didn't plan for. And sometimes, the thing that breaks isn't your code at all – it's a security feature in a completely different layer of the stack.
What We Learned¶
We've since implemented a solution. Starting with the next release of EventSourcingDB, the server will detect when it's started with the Management UI enabled on a browser-blocked port and issue a clear warning at startup. The warning explains that while the API will function normally, the UI won't be accessible in browsers – and suggests using alternative ports like 3000, 4000, 8080, or 8443 instead.
We've also updated the documentation to include information about browser-blocked ports in both the Getting Started guide and the Common Issues section, so future users can avoid this pitfall entirely.
What we learned from this is simple but profound: complexity has layers you can't always see.
EventSourcingDB is a database. We control the server, the API, the storage engine, the consistency guarantees. But we don't control the browser. We don't control the operating system's firewall. We don't control the user's network policies. And any of those layers can introduce constraints we never anticipated.
The port 6000 issue isn't a bug in EventSourcingDB. It's a reminder that software doesn't run in isolation. It runs in an ecosystem of tools, protocols, security policies, and historical decisions made decades ago by people trying to solve different problems.
The best we can do is stay humble, listen to our users, and keep learning.
The Value of Real-World Feedback¶
This bug was reported by a real user, within hours of our 1.0 release. That user didn't know about browser port blocking. Neither did we, at least not in this context. But by trying to use EventSourcingDB in their own environment, they surfaced something valuable: a gap in our documentation, a potential pitfall for others, and a lesson in the hidden constraints of web architecture.
That's the beauty of releasing software into the world. You can test exhaustively, plan carefully, and build with rigor – but you can't simulate the creativity and diversity of real usage. Every bug report, every edge case, every unexpected failure is a gift. It's a chance to improve, to clarify, and to make the product more robust.
So to the user who reported the port 6000 issue: thank you. You made EventSourcingDB better.
A Milestone Worth Celebrating¶
Speaking of community support: as we publish this post, EventSourcingDB has just reached 10,000 downloads on Docker Hub. This milestone means a lot to us. Every download represents someone willing to try what we've built, to trust it with their data, to invest time in learning event sourcing. Thank you to everyone who's been part of this journey. If you'd like to support the project, consider giving us a star on Docker Hub – it helps others discover EventSourcingDB and motivates us to keep improving.
And to everyone else using EventSourcingDB: if you encounter something unexpected, please let us know. Reach out via hello@thenativeweb.io or start a discussion in the community. Your feedback shapes what we build and how we communicate it.
If you're new to EventSourcingDB and want to explore, start with the Getting Started guide. And if you're setting up EventSourcingDB for the first time: maybe avoid port 6000.