To create a custom image using Compose files, don’t specify the image tag and instead use the build object, pointing at a Dockerfile.

compose.yaml example:

services:
  caddy:
    container_name: caddy
    build:
      context: .
      dockerfile: Dockerfile
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./config:/etc/caddy
    mem_limit: 50m

Dockerfile example (placed in the same directory as the above compose file):

FROM caddy:builder-alpine AS builder
RUN xcaddy build --with github.com/mholt/caddy-ratelimit
FROM caddy:latest
COPY --from=builder /usr/bin/caddy /usr/bin/caddy

Then, start the compose stack as normal: sudo docker compose up -d. The image will be built on the spot and then the container started.

System resources

If you’re running this on a resource-constrained environment, you may want to clean up docker’s resources after building custom images in this manner.