Exposing Local Docker Services Through Pangolin: Solving DNS Resolution in Containerized Reverse Proxy Setups

Setting up secure, publicly accessible services from a local development environment can be challenging, especially when dealing with multiple layers of reverse proxies, SSL certificates, and container networking. This post walks through a common scenario many developers face and provides a clean solution for exposing local HTTPS services through Pangolin tunnel service.

The Setup: Local HTTPS with Real Certificates

The goal was straightforward: run multiple Docker Compose projects on a local Linux server, make them accessible via HTTPS with real domain names locally, and then expose selected services to the internet through Pangolin.

Here’s the initial architecture:

Local Environment:

  • Multiple Docker Compose projects running various services
  • Caddy reverse proxy providing HTTPS termination
  • Real SSL certificates via Cloudflare DNS challenge
  • Domain names added to /etc/hosts for local resolution

Public Access:

  • Pangolin installed via Docker on a VPS
  • Newt agent connecting the local server to Pangolin

This setup worked perfectly for local access. Services were available at https://my-service.example.com locally with valid SSL certificates.

The Challenge: DNS Resolution in Pangolin

The problem arose when trying to expose these services through Pangolin. Initially, when services used HTTP with IP addresses and specific ports, Pangolin resources were configured like:

Target: http://192.168.1.100:3000

After implementing HTTPS with domain names, the natural approach was to update Pangolin resources to:

Target: https://my-service.example.com:443

However, Pangolin couldn’t resolve the domain names because they only existed in local /etc/hosts files, not in public DNS.

The Solution: Docker Network Integration

The breakthrough came from rethinking the network architecture. Instead of trying to make Pangolin resolve external domain names, the solution was to put the target containers in the same Docker network as newt.

Implementation

  1. Create a shared Docker network or use newt’s existing network
  2. Connect target service containers to this shared network
  3. Configure Pangolin resources to target containers directly by name

With this approach, Pangolin resources can be configured as:

Target: https://my-service-container:8443

Why This Works

This solution works because:

  • Direct container communication: newt and target containers are on the same Docker network
  • DNS resolution: Docker’s internal DNS resolves container names automatically
  • Bypasses Caddy: Traffic goes directly to the service container, avoiding the reverse proxy layer
  • Maintains HTTPS: Services can still use HTTPS on their internal ports

Network Configuration Example

# docker-compose.yml for your service
services:
  my-service:
    image: my-app:latest
    networks:
      - pangolin-network
    ports:
      - "8443:8443"  # HTTPS port for the service

networks:
  pangolin-network:
    external: true  # Connect to newt's network

Benefits of This Approach

  1. Simplified routing: Direct container-to-container communication
  2. No DNS hacks: No need for /etc/hosts manipulation in containers
  3. Maintains security: HTTPS can still be used between containers
  4. Scalable: Easy to add new services to the same network
  5. Clean separation: Local reverse proxy (Caddy) and public tunnel (Pangolin) serve different purposes

Conclusion

When working with containerized applications and tunnel services like Pangolin, understanding Docker networking is crucial. Rather than fighting DNS resolution issues, leveraging Docker’s built-in networking capabilities provides a cleaner, more maintainable solution.

The key insight is that not every layer needs to go through your reverse proxy. By putting target containers on the same network as your tunnel agent, you can create direct, secure connections while maintaining the benefits of your local HTTPS setup for development and testing.

This approach allows you to maintain the best of both worlds: a sophisticated local development environment with real SSL certificates and clean, direct public access through your tunnel service.