Hosted Service: Sign in Get the Code GitHub Organization
12 min read Manuel Kießling
Docker Infrastructure DevOps MCP Playwright VNC Traefik

Platform Rewrite: Switching from OS processes to Docker containers

Learn how we modernized our MCP-as-a-Service platform with a comprehensive Docker rewrite, replacing fragile OS process management with containerized orchestration.

How we transformed our MCP-as-a-Service platform from fragile OS process management to a robust, containerized architecture that improves reliability and enables future growth.

📑 Read the code

You can find the full changeset for the Docker rewrite on our GitHub repository: See the full changeset →

The Challenge: Architectural Dead End

Our original proof-of-concept architecture relied on managing multiple OS processes directly on the host system:

While this approach worked for initial testing and development, it revealed fundamental architectural limitations that made it unsuitable for serious production use:

Our Solution: Complete Architectural Overhaul

Rather than trying to patch the fundamentally flawed OS process approach, we decided to completely redesign the architecture from the ground up. We replaced the entire system with a Docker-centric, subdomain-based solution that provides proper isolation, reliability, and scalability.

Container Design

Each MCP instance container encapsulates all the necessary components:

Networking Revolution with Traefik

The most significant improvement came from replacing nginx-based routing with Traefik:

Technical Implementation Details

Supervisor Process Orchestration

Inside each container, Supervisord manages the process lifecycle with proper dependencies:

  1. Xvfb (Priority 10) – Virtual display server starts first
  2. Playwright MCP (Priority 20) – Waits for Xvfb, starts MCP server on port 8080
  3. x11vnc (Priority 30) – Waits for Xvfb, starts VNC server on port 5900
  4. websockify (Priority 40) – Waits for x11vnc, proxies VNC to port 6080 for browser access

Traefik Label Configuration

Each container automatically configures its own routing via Docker labels:

# MCP endpoint routing
traefik.http.routers.mcp-{instance}.rule=Host(`mcp-{instance}.mcp-as-a-service.com`)
traefik.http.services.mcp-{instance}.loadbalancer.server.port=8080
traefik.http.middlewares.mcp-{instance}-auth.forwardauth.address=https://app.mcp-as-a-service.com/auth/mcp-bearer-check

# VNC endpoint routing
traefik.http.routers.vnc-{instance}.rule=Host(`vnc-{instance}.mcp-as-a-service.com`)
traefik.http.services.vnc-{instance}.loadbalancer.server.port=6080

ForwardAuth Security

We implemented a custom ForwardAuth endpoint in Symfony that validates MCP bearer tokens:

Production Architecture

Our production deployment uses a hybrid approach that maximizes performance while maintaining reliability:

Internet (80/443) → Traefik Container → {
  app.mcp-as-a-service.com → nginx:8090 (native Symfony webapp)
  mcp-{id}.mcp-as-a-service.com → mcp-instance-container:8080
  vnc-{id}.mcp-as-a-service.com → mcp-instance-container:6080
}

Results and Technical Improvements

Reliability Improvements

Operational Improvements

Developer Experience Improvements

The Docker rewrite has transformed the MCP-as-a-Service platform from a proof-of-concept into a robust, scalable foundation. By recognizing the architectural dead end early and making the decision to completely redesign the system, we’ve created a platform that not only meets our current needs but also provides a solid base for future development.