Published
- 4 min read
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!