Skip to content

Instantly share code, notes, and snippets.

@Ocramius

Ocramius/Caddyfile

Last active Oct 10, 2020
Embed
What would you like to do?
Example docker + docker-compose + caddy + traefik setup that routes to multiple apps from one exposed HTTP port

Example docker-compose setup that routes to separate hosts while exposing one port

This example runs 4 different docker containers:

  • a traefik reverse proxy
  • 3 caddy instances (simple/modern web server with minimal config)

The 3 applications are completely isolated from the outside network, and are neither accessible nor can access the WAN.

The HTTP routing (and eventual SSL termination) is up to traefik or your reverse proxy of choice.

Running it

Careful: this CLI script will use sudo rights, please audit it before running it!

./run.sh
FROM abiosoft/caddy:0.11.0
ADD ./Caddyfile /etc/Caddyfile
ADD ./app1.html /serve/index.html
<title>app1</title>
FROM abiosoft/caddy:0.11.0
ADD ./Caddyfile /etc/Caddyfile
ADD ./app2.html /serve/index.html
<title>app2</title>
FROM abiosoft/caddy:0.11.0
ADD ./Caddyfile /etc/Caddyfile
ADD ./app3.html /serve/index.html
<title>app3</title>
:80 {
root /serve
}
version: '3.5'
services:
traefik:
image: traefik:1.7
command: --web --docker --docker.domain=app.test --logLevel=DEBUG
depends_on:
# our setup relies on the 3 apps running. Trying to spin up traefik will bring up those too
- "app1"
- "app2"
- "app3"
ports:
# access this with the correct Host header to access the respective container
- "80:80"
# management UI
- "8080:8080"
volumes:
# traefik does its magic by reading information about running containers from the docker socket
- /var/run/docker.sock:/var/run/docker.sock
- /dev/null:/traefik.toml
networks:
outside-world:
internal-network:
# app1, app2 and app3 are Caddy instances listening to port 80 and serving an index.html.
app1:
build:
context: .
dockerfile: app1-Dockerfile
networks:
internal-network:
# the aliases are not required, but are useful if the applications want to internally
# reference each other by host name
aliases:
- "app1.test"
labels:
- "traefik.port=80"
- "traefik.frontend.rule=Host:app1.test"
app2:
build:
context: .
dockerfile: app2-Dockerfile
networks:
internal-network:
aliases:
- "app2.test"
labels:
- "traefik.port=80"
- "traefik.frontend.rule=Host:app2.test"
app3:
build:
context: .
dockerfile: app3-Dockerfile
networks:
internal-network:
aliases:
- "app3.test"
labels:
- "traefik.port=80"
- "traefik.frontend.rule=Host:app3.test"
networks:
# everything that is *only* on "internal network" cannot talk to WAN
internal-network:
internal: true
# add this network to a container to make it talk to the rest of the world
outside-world:
#!/usr/bin/env bash
set -exuo pipefail
IFS=$'\n\t'
docker-compose up -d
curl -H Host:app1.test http://127.0.0.1
curl -H Host:app2.test http://127.0.0.1
curl -H Host:app3.test http://127.0.0.1
@robsonalves

This comment has been minimized.

Copy link

@robsonalves robsonalves commented Jul 25, 2019

Did you passed by this error?

Failed to retrieve information of the docker client and server host: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.21/version: dial unix /var/run/docker.sock: connect: permission denied"

@Ocramius

This comment has been minimized.

Copy link
Owner Author

@Ocramius Ocramius commented Jul 25, 2019

You get that if your user is not part of the docker group.

@DannyBen

This comment has been minimized.

Copy link

@DannyBen DannyBen commented Sep 15, 2019

Very nice, thank you.

@ilyesAj

This comment has been minimized.

Copy link

@ilyesAj ilyesAj commented Oct 31, 2019

Did you passed by this error?

Failed to retrieve information of the docker client and server host: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.21/version: dial unix /var/run/docker.sock: connect: permission denied"

it can also be a problem with SELinux

@sagoyanfisic

This comment has been minimized.

Copy link

@sagoyanfisic sagoyanfisic commented Dec 5, 2019

ERROR: for app1 dictionary update sequence element #0 has length 15; 2 is required
Traceback (most recent call last):
File "bin/docker-compose", line 6, in
File "compose/cli/main.py", line 68, in main
File "compose/cli/main.py", line 121, in perform_command
File "compose/cli/main.py", line 952, in up
File "compose/project.py", line 455, in up
File "compose/parallel.py", line 70, in parallel_execute
ValueError: dictionary update sequence element #0 has length 15; 2 is required
Failed to execute script docker-compose
quatum@quatum-H81M-H:~/Documents/compose$ nano docker-compose.yml

@lrkwz

This comment has been minimized.

Copy link

@lrkwz lrkwz commented Apr 28, 2020

You do not need

sudo bash -c 'echo "127.0.0.1 app1.test" >> /etc/hosts'
sudo bash -c 'echo "127.0.0.1 app2.test" >> /etc/hosts'
sudo bash -c 'echo "127.0.0.1 app3.test" >> /etc/hosts'

as long as you add the "Host" http header

curl -H Host:app1.test http://127.0.0.1
curl -H Host:app2.test http://127.0.0.1
curl -H Host:app3.test http://127.0.0.1
@Ocramius

This comment has been minimized.

Copy link
Owner Author

@Ocramius Ocramius commented Apr 28, 2020

Indeed, didn't think of it 👍

@Ocramius

This comment has been minimized.

Copy link
Owner Author

@Ocramius Ocramius commented Apr 28, 2020

@lrkwz adjusted, thanks!

@pwfraley

This comment has been minimized.

Copy link

@pwfraley pwfraley commented May 27, 2020

Why does Traefic depend on the app1 thru app3? Should it not be the other way around? Traefic can run even without apps and would be reachable, but running the apps without traefic is kind of useless since you would never be able to reach them.
But besides that, very simple example to understand traefic :) Thanx

@Ocramius

This comment has been minimized.

Copy link
Owner Author

@Ocramius Ocramius commented May 27, 2020

Why does Traefic depend on the app1 thru app3?

The system is not reachable until all services are up. It's not a prod-alike setup, obviously, but for dev purposes I'd not want a partial environment to be running, unless I killed services manually.

@edgars

This comment has been minimized.

Copy link

@edgars edgars commented Jun 4, 2020

Sorry, but I did not get the point. If Traefik is not balancing through the app1,app2,app3 via the default port 80, I believe that it is kind far from reality. If you expose an API, and you have to pass an extra header to define where you will execute the endpoint:

curl -H Host:app1.test http://127.0.0.1

Could you please offer a way to load-balancer the apps through a Traefik port, preferentially the 80?

Many thanks in advance,

@Ocramius

This comment has been minimized.

Copy link
Owner Author

@Ocramius Ocramius commented Jun 4, 2020

This is just for serving multiple apps from one entry point: nothing about load balancing in this gist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.