Muhammad SharjeelSenior Software Engineer

Islamabad · --:--:--


Using Docker & NGINX to Build a Suite of Microservices

Explore how to use Docker and NGINX to containerize and orchestrate a scalable microservices suite. Includes setup tips, architecture advice, and real-world tradeoffs.

Modern applications are increasingly being built using a microservices architecture, where independent services communicate through APIs. This makes them more scalable, maintainable, and deployable. But managing those services locally and in production can be a nightmare without proper tooling.

This is where Docker and NGINX step in. Docker helps you containerize each service, while NGINX can be used as a reverse proxy to route incoming requests appropriately. Together, they provide a lightweight and flexible setup for building your own service-based architecture.

Setting Up the Project

Let’s say you’re building two separate microservices: service-a and service-b. Each runs independently, and we use NGINX to unify them under one domain.

Project Structure

├── service-a/
│   ├── Dockerfile
│   └── ...
├── service-b/
│   ├── Dockerfile
│   └── ...
├── nginx.conf
└── docker-compose.yml

docker-compose.yml

This is your orchestration file, which defines how containers are built and networked.

version: '3.8'

    services:
      service-a:
        build: ./service-a
        ports:
          - "3001:3000"
      
      service-b:
        build: ./service-b
        ports:
          - "3002:3000"

      nginx:
        image: nginx:latest
        ports:
          - "80:80"
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf
        depends_on:
          - service-a
          - service-b

nginx.conf

This file tells NGINX how to route requests to each service:

http {
      server {
        listen 80;

        location /service-a/ {
          proxy_pass http://service-a:3000/;
        }

        location /service-b/ {
          proxy_pass http://service-b:3000/;
        }
      }
    }

Now, when you access localhost/service-a or localhost/service-b, your requests will be routed to the correct container.

Advantages of This Setup

  • Isolation: Each service runs in its own container, with its own dependencies and runtime environment.
  • Portability: You can ship your app across dev, staging, and production with consistent behavior.
  • Scalability: Spin up more instances of a single service without affecting others.
  • Ease of Local Testing: Easily test how services interact with each other using just a few Docker commands.

Challenges and Caveats

While this setup is powerful, it comes with some tradeoffs:

  • Configuration Complexity: Managing NGINX config and inter-container networking can get tricky as the number of services increases.
  • Monitoring Overhead: You’ll need tools like Prometheus, Grafana, or ELK Stack to monitor logs, health, and performance.
  • Cold Start Time: Spinning up several containers might slow down your local dev environment, depending on your machine.

Optimizing the Workflow

To keep things manageable as your suite grows:

  • Use a .env file to store shared port values, secrets, and environment modes.
  • Implement health checks in your docker-compose.yml so services don’t start until dependencies are ready.
  • Consider using a service mesh like Istio or Traefik if you plan to move into Kubernetes later.

Real-World Use Cases

This architecture is a great foundation for any of the following:

  • A dashboard + backend API combo (separate front-end and API containers)
  • Auth, billing, and notification services, each in their own container
  • A lightweight CMS, analytics engine, and user-facing app running side-by-side

Conclusion

Combining Docker and NGINX gives you a clean, developer-friendly way to build, test, and deploy microservice-based applications. It takes some configuration work upfront, but the benefits in maintainability and scalability are well worth it.

If you're building projects that need to grow modularly, learning this workflow early can save you countless headaches down the line.

esc
HomeThe hero, the system map and selected workPageWorkAll 6 projects, each with a glimpse of its interfacePageAboutExperience, how I work and the stack I usePageWriting12 posts on engineering, AI and designPageGet in touchContact me by email or hire me on UpworkSection
Alara CodeTurns a client brief into a complete, human-approved software delivery pack.ProjectPolyXIdentity, tenancy and access platform shared by every product in the company.ProjectPolyX SDKTypeScript auth SDK on npm that puts the platform behind one typed client.ProjectAlara SpaceMulti-tenant team wiki that AI agents can read and write through MCP.ProjectAlara PlanProject tracker with AI meeting minutes, support intake and an MCP server.ProjectODINOmni-channel customer engagement platform on a microservices backend.Project
A portfolio that builds itself while you scrollThis site starts as a blank canvas and a swarm of cursors draws it in front of you. Here is why I wanted that, what it is made of, and everything that went wrong on the way.8 min readUnslopping AI output with nothing but a skillYou do not need a better model to get rid of the purple gradients. You need your taste written down as a skill the agent loads before it touches the screen.2 min readAI Assistant Coding vs Vibe CodingAs AI becomes ubiquitous in software development, a dangerous pattern is emerging: developers blindly accepting AI suggestions without understanding the code. This 'vibe coding' approach undermines the fundamentals of being a developer. Here's why understanding code matters more than shipping it, and how to use AI as a proper assistant.8 min readHosting Multiple Domains on One Server with Docker, NGINX & SSL (DevOps for Developers)As a full-stack developer, I recently had to deploy multiple backend services on one server, each with its own domain and SSL certificate. Here's how I combined Docker, NGINX, and Certbot to build a scalable, production-grade setup — without needing a dedicated DevOps engineer.3 min readTaming CORS in a Microservices Monorepo: From Async Validation to a Unified ConfigCORS errors can be frustrating, especially in a microservices monorepo setup. This blog dives into what CORS really is, why it matters, and how I solved the CORS challenge using a shared JSON config file — establishing a single source of truth for all services.4 min readDebugging Tips for Frontend Developers (React + Next.js)Effective debugging is one of the most valuable skills for frontend developers. Here's a practical guide to debugging with logs, using the debugger keyword, troubleshooting APIs, and improving performance — with a special focus on React and Next.js.3 min readIs the ‘AI Developer’ a Threat to Jobs – or a Marketing Stunt?AI dev tools are booming — but are they replacing developers or just reshaping workflows? Here's the balanced view.3 min readUsing Docker & NGINX to Build a Suite of MicroservicesExplore how to use Docker and NGINX to containerize and orchestrate a scalable microservices suite. Includes setup tips, architecture advice, and real-world tradeoffs.3 min readGetting Started with Next.js: Structure, Tips & DeploymentA developer-friendly introduction to Next.js — learn how to scaffold projects, understand folder structure, configure features, and deploy to Vercel seamlessly.3 min readGrid Systems: The Foundation of Great UI DesignWant cleaner, more balanced layouts? A grid system brings structure, rhythm, and clarity to your UI — and Tailwind makes it easier than ever to implement.2 min readUsing Generative AI to Speed Up Creative and Dev WorkflowsFrom ChatGPT to v0.dev — here's how generative AI helps streamline UI design, prototyping, coding, and problem-solving in modern workflows.3 min readWhat Is Accessible Design and Why It MattersAccessibility isn’t a nice-to-have. It’s a necessity. Here's why accessible design matters — and how to get it right in your UI and frontend code.3 min read
GitHubgithub.com/isharjeelddNew tabLinkedInlinkedin.com/in/muhammad-sharjeel-254a48108New tabUpworkHire me for freelance workNew tab