π A practical guide for developers building their first distributed system
When building microservices for the first time, most developers focus on features,
scaling, or breaking the monolith β but almost nobody talks about security architecture.
And thatβs exactly where things can go wrong.
While developing my own distributed system, I discovered that several internal APIs β
and even the PostgreSQL database β were accidentally exposed to the public. π¬
So I implemented a simple, production-ready pattern:
API Gateway + Docker Private Networks.
This post will show you exactly how (and why) I did it, and how you can use the same approach in your own projects.
π₯ The Real Problem: Microservices Accidentally Exposing Everything
Hereβs how many beginner systems accidentally look:
- Each service is exposed on its own port
- The client talks to everything directly
- The database (!) may also be exposed
- No central control or routing
This creates security issues, debugging complexity, and a messy architecture.
π§© Part 1 β The API Gateway: Your Single Entry Point
Why the API Gateway is critical
How it works
- The client sends a single request to the Gateway.
- The Gateway decides which service should handle it.
- It forwards the request inside the private Docker network.
- Internal URLs are never exposed to the outside world.
A Gateway is not just a fancy router β it becomes the front door to your entire system.
Why it's so important:
- One place for authentication
- One place for routing
- Internal services remain hidden
- Cleaner code and better control
Instead of:
http://localhost:3000/orders
http://localhost:4000/reports
Your client only calls:
http://gateway/api/orders
The Gateway forwards the request internally.
Your services never need to be exposed again.
π§± Part 2 β Docker Private Networks (The Physical Security Layer)
How Docker networks protect your system
Why this matters
Without a private network, Docker exposes containers to the host machine.
With it:
β Only the Gateway is reachable
β All internal traffic stays inside the network
β Databases cannot be accessed directly
Putting services into a private Docker network prevents the outside world
from reaching anything except what you explicitly expose.
Most developers don't realize that Docker exposes containers publicly unless configured otherwise.
The solution?
Put all internal services in a private network.
This prevents the outside world from reaching anything except what you explicitly expose.
What this gives you:
- Internal-only communication
- Zero accidental port exposure
- Database fully isolated
- Clean, professional architecture
Even if someone bypasses the Gateway (rare),
they still can't access Service A, B, or the Database β because they're not on a public network.
π‘οΈ Combining the Two: A Simple, Solid Security Pattern
How the full architecture works together
When you combine:
β Logical Security (API Gateway)
β Physical Security (Private Network)
You get a microservices architecture that's both simple and robust β without Kubernetes, service mesh, or any heavy DevOps tooling.
The architecture becomes:
Client
β
API Gateway
β
Private Docker Network
βββ Service A
βββ Service B
βββ Database
Only the Gateway is public.
Everything else is safely tucked away behind it.
π§ͺ Minimal Docker Compose Example (Copy/Paste Ready
Hereβs the minimal setup I used β clean, simple, and production-friendly:
services:
api-gateway:
build: ./gateway
ports:
- "8080:8080"
networks:
- public_net
- private_net
service-a:
build: ./service-a
expose:
- "3000"
networks:
- private_net
service-b:
build: ./service-b
expose:
- "4000"
networks:
- private_net
internal-db:
image: postgres:16
expose:
- "5432"
environment:
POSTGRES_PASSWORD: password
networks:
- private_net
networks:
public_net:
private_net:
Key takeaways
- Only the Gateway has ports β public
- Internal services use expose β private
- Everything sits inside private_net
- Clean, secure architecture with minimal configuration
π― What I Learned
Implementing this pattern gave me:
β Zero accidental exposure of internal services
β A secure, predictable entry point
β Faster debugging
β Easier onboarding for teammates
β A scalable foundation for future services
β Professional-level architecture with beginner-friendly tools
β¨ Final Thoughts
This architecture may look simple β and thatβs exactly why it works.
You donβt need Kubernetes, a service mesh, or complex DevOps setups
to build a secure and scalable distributed system.
Start with:
β One API Gateway
β One private Docker network
This foundation will naturally support your system as it grows.
Simple. Clean. Secure. Effective.




Top comments (0)