Use one single configuration file for prod and dev environments?

1. Caddy version (caddy version):

Caddy 2.4.6 through docker (image: caddy:alpine)

2. How I run Caddy:

I use Caddy in a docker-compose file as a reverse proxy.

a. System environment:

Docker

b. Command:

docker-compose up

c. Service/unit/compose file:

docker-compose.yaml

version: '3.3'

services:
  caddy:
    image: caddy:alpine
    ports:
      - "9000:9000"
    volumes:
      - $PWD/caddy/Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config

  db:
    image: postgis/postgis:13-3.2-alpine
    environment:
      - "POSTGRES_PASSWORD=${POSTGRES_PASSWORD}"
    volumes:
      - dbdata:/var/lib/postgresql/data
      - "./db/init-scripts:/docker-entrypoint-initdb.d"
    ports:
      - "5436:5432"

  back:
    build:
      context: .
    depends_on:
      - db

volumes:
  dbdata:
  caddy_data:
  caddy_config:

docker-compose.dev.yaml

version: '3.3'

services:
  caddy:
    image: caddy:alpine
    ports:
      - "9000:9000"
    volumes:
      - $PWD/caddy/Caddyfile.dev:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - back
      - node

  node:
    image: node:17-alpine3.13
    working_dir: /frontend
#    tty: true
    command: >
      sh -c "npm ci && npm run serve-dev"
    volumes:
      - ./frontend:/frontend
      - ./frontend/node_modules:/frontend/node_modules
    ports:
      - "8000:8000"

  pgadmin:
    image: dpage/pgadmin4
    ports:
      - "8081:80"
    volumes:
      - "./db/servers.json:/pgadmin4/servers.json"
    environment:
      - "PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL}"
      - "PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD}"
    logging:
      driver: none

volumes:
  dbdata:
  caddy_data:
  caddy_config:

d. My complete Caddyfile or JSON config:

:9000 {
	handle * {
		reverse_proxy back:8000
	}

    log {
        output stdout
        level INFO
    }
}

Caddyfile.dev:

:9000 {
    handle /static/frontend/* {
		reverse_proxy node:8000
    }

	handle * {
		reverse_proxy back:8000
	}

    log {
        output stdout
        level INFO
    }
}

3. The problem I’m having:

This is my first time using Caddy. I switched from NGinx mainly because I want my containers to be as small as possible and I had the feeling that NGinX was way too complex for what I wanted to do.
Also, I hear a lot of people around me using Caddy and it was the proper opportunity for me to learn using it.

Basically what I’m trying to achieve is the following:

I have a DJango app which requires Javascript files compiled with Webpack.
For the production environment, this JS is compiled during the making of the container, using a multi stage build: Dockerfile · improve_docker_containers · champs-libres / EGERIEC / egeriec-app · GitLab

I would like to also provide a development environment in a docker-compose.dev.yaml file so I can enable live-reloading and hot reloading of the JS file.

The “back” service is the django app, the “node” service is the NodeJS running webpack in server mode (serving JS file in HTTP).

The issue is that I would like to keep the Caddy configuration very simple and working for both use cases.

Basically, what I’m trying to do is:

When a request comes in Caddy:

  1. Check if the file is available on the first reverse_proxy server “node” (if the reverse_proxy can be resolved), if it’s there, use it and skip the next options
  2. Check if the file is available on the second reverse_proxy server “back”.

I tried many options and I end up using 2 config files:

Is there a way to configure Caddy so it only uses one single config file for both use cases?

When I run the app using:

docker-compose up

I get this issue in the log:

caddy_1  | {"level":"error","ts":1648900115.9236927,"logger":"http.log.error.log0","msg":"dial tcp: lookup node on 127.0.0.11:53: no such host","request":{"remote_addr":"172.21.0.1:34312","proto":"HTTP/1.1","method":"GET","host":"localh
ost:9000","uri":"/static/main.bundle.js","headers":{"Accept":["*/*"],"User-Agent":["curl/7.81.0"]}},"duration":0.004499837,"status":502,"err_id":"tq7b3gf47","err_trace":"reverseproxy.statusError (reverseproxy.go:886)"}

And when I run docker with:

docker-compose up -f docker-compose.yaml -f docker-compose.dev.yaml up

It works fine.

Find the repository here: Files · improve_docker_containers · champs-libres / EGERIEC / egeriec-app · GitLab

Thanks.

You can use import for snippets, and environment variables to do it.

For example:

(frontend) {
	handle /static/frontend/* {
		reverse_proxy node:8000
	}
}

:9000 {
	{$CADDY_EXTRA_DIRECTIVES}

	handle {
		reverse_proxy back:8000
	}

	log
}

Then in your docker-compose config and/or in a .env file, you can put this:

CADDY_EXTRA_DIRECTIVES="import frontend"

And you may leave that environment variable empty if you don’t want the frontend handler to be loaded in the config.

Read about env in docker-compose: Environment variables in Compose | Docker Documentation

See the Caddy docs for snippets and environment variables

3 Likes

Amazing, thanks for you amazing support and piece of software !!!

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.