Skip to content

Local reverse proxy for Docker containers powered by Caddy.

License

Notifications You must be signed in to change notification settings

luisaveiro/docker-reverse-proxy

Repository files navigation

#StandWithUkraine


programming

Local reverse proxy for Docker containers powered by Caddy.

AboutDisclaimerGetting StartedDownloadHow To UseFAQUseful Tips

ChangelogContributingSecurity VulnerabilitiesCreditsSponsorLicense

About

This repository offers a simple approach to having Caddy Server as a local reverse proxy for your Docker containers. Caddy Server is the first and only web server to use HTTPS automatically with no extra configuration or separate tooling required.

Why would you need a local reverse proxy?
With a hosts file, you can only map hostnames to IP addresses. Hosts file does not support mapping ports with IP addresses. You are unable to map multiple containers to hostnames.

As a developer, you might be working on multiple Docker-based projects. We have all experienced the Docker container port binding failure message - Bind for 0.0.0.0:80 failed: port is already allocated.

Or you are working on a multi-tenant application that requires tenants to log in on their subdomain. Developing locally can be challenging with this requirement.

Having a reverse proxy you can assign domains or subdomains to your Docker containers without the need to worry about port binding failures or develop locally with a multi-tenant subdomain application.

Disclaimer

Important

Docker Reverse Proxy is not affiliated with Stack Holdings GmbH or Docker, Inc and is not an official product from either company.

"Caddy" is a registered trademark of Stack Holdings GmbH. "Docker" is a registered trademark of Docker, Inc.

Docker Reverse Proxy has been developed to run Caddy in a local Docker environment. If you wish to use Caddy on your system, you can follow the follow the Installation Guide.

Getting Started

You will need to make sure your system meets the following prerequisites:

  • Docker Engine >= 20.10.00

This repository utilizes Docker to run Caddy. So, before using Docker Reverse Proxy, make sure you have Docker installed on your system.

Download

You can clone the latest version of Docker Reverse Proxy repository for macOS, Linux and Windows.

# Clone this repository.
$ git clone [email protected]:luisaveiro/docker-reverse-proxy.git --branch main --single-branch

How To Use

There are a few steps you need to follow before you can have Caddy set up and running as a reverse proxy for your Docker containers. I have outline the steps you would need to take to get started.

1. Update your hosts file

You will need to modify your /etc/hosts file to include the hostnames entries. The hostname is the domain or subdomain you wish to direct traffic for a Docker container.

The structure of the hostname entry must be your loopback IP Address (127.0.0.1) and domain/subdomain. For example:

127.0.0.1 domain.local

Note

The hosts file does not support wildcard (*) for domains or subdomains. You will need to have an entry for each domain and subdomain you wish to use for the reverse proxy in your hosts file.

2. Create a Caddyfile

Once you have added your domain/subdomain entry to your hosts file, you will need to create a Caddyfile. The Caddyfile is a convenient Caddy configuration format for humans.

Docker Reverse Proxy includes a Caddyfile.example file in the config directory to help you get started. You can run the following command in the terminal to create your Caddyfile file.

# Create Caddyfile from Caddyfile.example.
$ cp config/Caddyfile.example config/Caddyfile

3. Add your site blocks to your Caddyfile

Caddy supports various configurations, you can follow the Caddy Documentation to learn more about the various configurations supported by Caddyfile.

This readme will focus on the Caddyfile reverse proxy configuration (with minimum configuration). You will need to create a site block in the Caddyfile to match the domain entry of your hosts file.

The Caddyfile.example file has an example of the structure of the site block.

# HTTP site block
<hostname>:80 {
  reverse_proxy <container-name>:<port>
}

# HTTPS site block
<hostname>:443 {
  tls internal
  reverse_proxy <container-name>:<port>
}

Let's cover the the Caddyfile's structure:

  • Site block
    The site block defines the Caddy configuration for a given site address. You can identify a site block by the curly braces.

  • Site address
    The site address is the domain/subdomain entry which matches your hostname in your hosts file. Unlike your hosts file, Caddyfile supports port mapping.

  • Directive
    A directive is the Caddy instruction. Caddy has a variety of directives. This is readme will focus on the reverse_proxy directive.

  • Argument
    The reverse_proxy argument is the upstream which Caddy will proxy. In our use case the upstream will be the Docker container name and the exposed port.

  • TLS (HTTPS only)
    The TLS directive is to configure HTTPS for the site block. By using the internal option, we are using Caddy's internal, locally-trusted CA to produce certificates for the site.

Below is an example of a configured site block:

# Personal website
website.local:80 {
  reverse_proxy website_app:8080
}

# Personal website using HTTPS
website.local:443 {
  tls internal
  reverse_proxy website_app:8080
}

4. Start Caddy Docker container

After you have configured your Caddyfile, you can start Caddy Docker container. Docker Reverse Proxy includes a compose.yaml file with Caddy pre-configured. You can run the following command:

# Start Caddy Docker container
$ docker compose up

# Or start Caddy Docker container detached mode
$ docker compose up -d

Docker will create the Caddy container which is called docker-reverse-proxy. The container will be attached to a network called reverse_proxy.

If you want to change the container name, network name or volume names, you can create a DotEnv file and override the Docker Compose variables. Below is an example of the DotEnv variables.

#--------------------------------------------------------------------------
# Docker env
#--------------------------------------------------------------------------

# The project name. | default: reverse_proxy
APP_NAME="reverse_proxy"

#--------------------------------------------------------------------------
# Container env
#--------------------------------------------------------------------------

# The Caddy Server Docker container name. | default: reverse_proxy
CONTAINER_NAME="${APP_NAME}"

#--------------------------------------------------------------------------
# Network env
#--------------------------------------------------------------------------

# Map the Admin API port to the host port. | default: 2019
ADMIN_API_PORT=2019

# The Docker network for the containers. | default: reverse_proxy
NETWORK_NAME="reverse_proxy"

#--------------------------------------------------------------------------
# Volume env
#--------------------------------------------------------------------------

# The app container data volume. | default: reverse_proxy_data
CONTAINER_VOLUME_DATA_NAME="${CONTAINER_NAME}_data"

# The app container config volume. | default: reverse_proxy_config
CONTAINER_VOLUME_CONFIG_NAME="${CONTAINER_NAME}_config"

Docker Reverse Proxy includes a .env.example file to get you started. You can run the following command in the terminal to create your DotEnv file.

# Create .env from .env.example.
$ cp .env.example .env

5. Trusting Caddy certificate authority (CA)

If you are not planning to use HTTPS for local development, you can skip this step.

Caddy generates its own certificate authority (CA) and uses it to sign certificates. After Caddy's root CA is created, you will need to add the certificate to your local trust store. I have outline the steps you would need to take.

Important

Please ensure you have the latest update of the Caddy Docker image.

Caddy container will create and mount a folder called certificate-authority. In this folder you will see certificate and key files. You will be installing the root.crt in your local trust store.

Open the "Keychain Access" app and drag and drop the certificate into the "login" keychain. Open the certificate (it should be called something like "Caddy Local Authority") and configure it to "Always Trust", as shown below.

Trust Caddy Local Authority certificate
Trust Caddy Local Authority certificate.

Tip

Firefox has its own local trust store. You will be required to complete one additional step.

In Firefox, type 'about:config' in the address bar. If prompted, accept any warnings. Set "security.enterprise_roots.enabled" as true.

Firefox settings
Firefox settings for local trust store.

6. Attach Docker containers to Caddy network

Once Caddy container is up and running, you will need to configure your Docker containers by attaching the reverse_proxy network to your container(s), assign a name to the container and expose the port that Caddy will proxy.

I have outlined the necessary configuration below both for Docker Compose and Docker CLI approach.

Docker Compose

In your Docker Compose file you need to define reverse_proxy as an external network. For each services you want to access via Caddy reverse proxy, you will need to add reverse_proxy as an attached network and define your exposed port.

Below I have provided an example of a Docker Compose file configured to match the example site block in the Caddyfile.

Caddyfile
# Personal website
website.local:80 {
  reverse_proxy website_app:8080
}
Docker Compose
version: '3.9'

services:
  website:
    # Container name should be the same as in the Caddyfile.
    container_name: website_app
    image: nginx:alpine
    restart: unless-stopped
    # Expose the mapped port that Caddy will proxy.
    expose:
      - 8080
    # Add reverse_proxy as attached network.
    networks:
      - reverse_proxy
    volumes:
      - ./src:/usr/share/nginx/html

networks:
  # Add reverse_proxy as an external network.
  reverse_proxy:
    external: true

Docker CLI

If you don't use Docker Compose, I have included an example of Docker CLI to start a container with the necessary configurations.

$ docker run --rm --name=website_app --expose 8080 --network=reverse_proxy nginx:alpine

FAQ

Q: Can I configure Caddy via the REST API?
A: Yes, You can access Caddy administration endpoints via HTTP by connect to http://localhost:2019. You can change the the API port in the DotEnv file.

#--------------------------------------------------------------------------
# Network env
#--------------------------------------------------------------------------

# Map the Admin API port to the host port. | default: 2019
ADMIN_API_PORT=2019

Q: If I change the Caddyfile, do I need to restart the Docker container?
A: Yes, You will need to restart Caddy to allow the reverse proxy to reload changes in your configuration. There are two commands you can use to restart Caddy.

According to the Caddy Docker Hub page, Caddy comes with a caddy reload command. You can run the following command to reload Caddy configuration:

$ docker exec -w /etc/caddy docker-reverse-proxy caddy reload

The working directory is set to /etc/caddy so Caddy can find your Caddyfile without additional arguments.

Alternatively, you can restart the Docker container by using the following command.

$ docker-compose restart

Useful Tips

VSCode Caddyfile Syntax is an extension for VSCode that adds syntax highlighting for Caddyfiles.

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

I encourage you to contribute to Docker Reverse Proxy! Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

Please check out the contributing to Docker Reverse Proxy guide for guidelines about how to proceed.

Security Vulnerabilities

Trying to report a possible security vulnerability in Docker Reverse Proxy? Please check out our security policy for guidelines about how to proceed.

Credits

The illustration used in the project is from unDraw (created by Katerina Limpitsouni). All product names, logos, brands, trademarks and registered trademarks are property of their respective owners.

Sponsor

Do you like this project? Support it by donating.

Code Review

License

The MIT License (MIT). Please see License File for more information.


GitHubLinkedInTwitter