Home

Published

- 4 min read

Quick guide for Caddy | Reverse Proxy

Networking Reverse-Proxy Websites Hosting
Quick guide for Caddy | Reverse Proxy

Introduction

Caddy is the easiest way to expose resources to the internet. It runs with Docker and gets you a SSL certificate without lifting a finger. To follow along, you should have a domain name.

Installation

First, make sure you have docker installed on your system. If not, follow the steps here: docs.docker.com/engine/install/ubuntu/#install-using-the-repository.

Now that we got that out of the way, let’s make a new directory for Caddy and make the Docker Compose file:

   cd ~
mkdir caddy
cd caddy
sudo nano docker-compose.yml

Expose a Docker Container

Let’s say you have a local docker container that has a web UI and you want to expose it to the internet.

In the docker-compose.yml, paste the following using Ctrl+Shift+V:

   services:
  caddy:
    image: caddy:alpine
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /home/your_user/your_static_website_files:/mySite
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    networks:
      -caddy_network # Internal Docker network

volumes:
  caddy_data:
  caddy_config:
  
networks:
  caddy_network:
    external: true

Now, make a file named Caddyfile:

   sudo nano Caddyfile

In your Caddyfile, paste the following using Ctrl+Shift+V:

   example.com {
        reverse_proxy your-container-name:51821
}

Also, create at least one Docker network for both the caddy container and your other container to share:

   docker network create caddy_network

Don’t forget to edit the docker-compose file of the container you want to open uo to the internet to add it to this new network. It’s docker-compose should be edited to look someshat like this:

   services:
  your-container-name:
    ...
    networks:
      -caddy_network
      
networks:
  caddy_network:
    external: true

Now, while you’re in the caddy directory, run sudo docker compose up -d. Every time you make changes, you will have to either run sudo docker compose down and then sudo docker compose up -d or sudo docker compose restart caddy in order for them to take effect.

You should also create a A-record in your domain registrar’s website to point your domain to your server’s IP address. If you want this for your main site and not a subdomain, use @ for the host field. Put your server’s IP in the value field.

Serve Static Website

By default, visiting the root domain serves you index.html, so make sure to name your landing page accordingly.

In your docker-compose.yml, paste the following using Ctrl+Shift+V:

   services:
  caddy:
    image: caddy:alpine
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /home/your_user/your_static_website_files:/mySite
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config

volumes:
  caddy_data:
  caddy_config:

In your Caddyfile, paste the following using Ctrl+Shift+V. Change /blog/ to the directory where your static website files live in your server.

   blog.example.com {
    handle {
        root * /blog/
        file_server
    }
}

Handle Certain Paths Differently

If you want to host completely different files in a certain path, or point an entirely different container in said path, you can use handle_path.

Example where example.com/images points to /a-really/long/path/in-your-server:

   blog.example.com {
    handle_path /images* {
        root * /a-really/long/path/in-your-server
        file_server
    }
    handle {
        root * /blog/
        file_server
    }
}

Use Subdomains

If you want to use subdomains(e.g. blog.example.com), just make a A-record through your subdomain registrar’s page and use the subdomain part for the value field(e.g. for blog.example.com, use blog) and put your server’s public IP address on the Value field. Then, edit your Caddyfile so that it knows about your subdomain:

   blog.example.com {
        reverse_proxy your-container-name:51821
}

If you want to have both example.com and blog.example.com on the same server, your Caddyfile may look somewhat like this:

   example.com {
        reverse_proxy your-container2-name:51823
}


blog.example.com {
        reverse_proxy your-container-name:51821
}

Handling Errors

This Caddyfile redirects your users to the appropriate page when the servers returns an error code. It assumes that every possible error page exists in your server, so you should have a 404.html, a 403.html, a 503.html and so on for every error that may occur.

   blog.example.com {
    handle {
        root * /blog/
        file_server
    }
    handle_errors {
        rewrite * /{err.status_code}.html
        file_server
    }
}

Final Thoughts

With all that knowledge, you should be able to expose docker containers and static websites to the internet, without the pain of setting up certificates. Mapping domains, subdomains or url paths to different containers or file directories and handling server errors requires just a few lines of code, all thanks to Caddy, with SSL being the default!