How can I use different ports?

1. The problem I’m having:

Hi there I am brand new to this and trying to get Caddy running on localhost for my Symfony app inside docker. The problem is that default ports, 80/443 are in use by another container I have and that cannot change. I have a docker-compose.override.yml file and tried adding custom ports for caddy

    ports:
      - "801:80"
      - "4431:443"

but did not work. If I stop my other container and run this one I can see a whole lot of ports it uses, so is there a way to limit it to not use the 80/443 and just the new ones?

2. Error messages and/or full log output:

Error response from daemon: driver failed programming external connectivity on endpoint test-caddy-1 (aca330fef2a18351c2163bfcbb372dd8c970eab154b1ad835eaf49f3a32dd79b): Bind for 0.0.0.0:443 failed: port is already allocated

3. Caddy version:

v2.7.4 h1:J8nisjdOxnYHXlorUKXY75Gr6iBfudfoGhrJ8t7/flI=

4. How I installed and ran Caddy:

Via Dockerfile:

ADD --chmod=500 https://caddyserver.com/api/download?os=linux&arch=$TARGETARCH&p=github.com/dunglas/mercure/caddy&p=github.com/dunglas/vulcain/caddy /usr/bin/caddy

a. System environment:

OS X 13.5.2, M1 Pro chip

b. Command:

docker compose up -d

c. Service/unit/compose file:

docker-compose.yml

version: "3.4"

services:
  php:
    image: ${IMAGES_PREFIX:-}app-php
    restart: unless-stopped
    volumes:
      - php_socket:/var/run/php
    healthcheck:
      interval: 10s
      timeout: 3s
      retries: 3
      start_period: 30s
    environment:
      TRUSTED_PROXIES: ${TRUSTED_PROXIES:-127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16}
      TRUSTED_HOSTS: ^${SERVER_NAME:-example\.com|localhost}|caddy$$
      # The two next lines can be removed after initial installation
      SYMFONY_VERSION: ${SYMFONY_VERSION:-}
      STABILITY: ${STABILITY:-stable}
      # Run "composer require symfony/orm-pack" to install and configure Doctrine ORM
      DATABASE_URL: postgresql://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:-!ChangeMe!}@database:5432/${POSTGRES_DB:-app}?serverVersion=${POSTGRES_VERSION:-15}&charset=${POSTGRES_CHARSET:-utf8}
      # Run "composer require symfony/mercure-bundle" to install and configure the Mercure integration
      MERCURE_URL: ${CADDY_MERCURE_URL:-http://caddy/.well-known/mercure}
      MERCURE_PUBLIC_URL: https://${SERVER_NAME:-localhost}/.well-known/mercure
      MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}

  caddy:
    image: ${IMAGES_PREFIX:-}app-caddy
    depends_on:
      - php
    environment:
      SERVER_NAME: ${SERVER_NAME:-localhost}, caddy:80
      MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
      MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
    restart: unless-stopped
    volumes:
      - php_socket:/var/run/php
      - caddy_data:/data
      - caddy_config:/config
    ports:
      # HTTP
      - target: 80
        published: ${HTTP_PORT:-80}
        protocol: tcp
      # HTTPS
      - target: 443
        published: ${HTTPS_PORT:-443}
        protocol: tcp
      # HTTP/3
      - target: 443
        published: ${HTTP3_PORT:-443}
        protocol: udp

# Mercure is installed as a Caddy module, prevent the Flex recipe from installing another service
###> symfony/mercure-bundle ###
###< symfony/mercure-bundle ###

###> doctrine/doctrine-bundle ###
  database:
    image: postgres:${POSTGRES_VERSION:-15}-alpine
    environment:
      POSTGRES_DB: ${POSTGRES_DB:-app}
      # You should definitely change the password in production
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!}
      POSTGRES_USER: ${POSTGRES_USER:-app}
    volumes:
      - database_data:/var/lib/postgresql/data:rw
      # You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data!
      # - ./docker/db/data:/var/lib/postgresql/data:rw
###< doctrine/doctrine-bundle ###

volumes:
  php_socket:
  caddy_data:
  caddy_config:
###> symfony/mercure-bundle ###
###< symfony/mercure-bundle ###

###> doctrine/doctrine-bundle ###
  database_data:
###< doctrine/doctrine-bundle ###

docker-compose.override.yml

version: "3.4"

# Development environment override
services:
  php:
    build:
      context: .
      target: php_dev
    volumes:
      - ./:/srv/app
      - ./docker/php/conf.d/app.dev.ini:/usr/local/etc/php/conf.d/app.dev.ini:ro
      # If you develop on Mac or Windows you can remove the vendor/ directory
      #  from the bind-mount for better performance by enabling the next line:
      #- /srv/app/vendor
    environment:
      # See https://xdebug.org/docs/all_settings#mode
      XDEBUG_MODE: "${XDEBUG_MODE:-off}"
    extra_hosts:
      # Ensure that host.docker.internal is correctly defined on Linux
      - host.docker.internal:host-gateway

  caddy:
    command: [ "caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile", "--watch" ]
    build:
      context: .
      target: caddy_base
    volumes:
      - ./public:/srv/app/public:ro
      - ./docker/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
    environment:
      MERCURE_EXTRA_DIRECTIVES: demo
    ports:
      - "801:80"
      - "4431:443"

###> symfony/mercure-bundle ###
###< symfony/mercure-bundle ###

###> doctrine/doctrine-bundle ###
  database:
    ports:
      - "5432"
###< doctrine/doctrine-bundle ###

d. My complete Caddy config:

{
    # Debug
    {$CADDY_DEBUG}
}

{$SERVER_NAME}

{$CADDY_EXTRA_CONFIG}

log

route {
    root * /srv/app/public
    mercure {
        # Transport to use (default to Bolt)
        transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
        # Publisher JWT key
        publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
        # Subscriber JWT key
        subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
        # Allow anonymous subscribers (double-check that it's what you want)
        anonymous
        # Enable the subscription API (double-check that it's what you want)
        subscriptions
        # Extra directives
        {$MERCURE_EXTRA_DIRECTIVES}
    }
    vulcain
    php_fastcgi unix//var/run/php/php-fpm.sock
    encode zstd gzip
    file_server
}

Typically you would have Caddy own ports 80/443 and have it proxy to any other apps that you want to serve.

You’ll need to restructure your Caddyfile to have multiple site blocks. See Caddyfile Concepts — Caddy Documentation

Thanks, but is this saying that the caddyfile would control all the sites? Or am I not following you…?

I have two separate docker containers running, and the other one is not caddy powered and needs the 80/443 ports, I need JUST the one caddy/docker container to use different ports…

If you don’t use ports 80/443 then ACME issuers won’t be able to reach Caddy to solve the ACME HTTP or ACME TLS-ALPN challenges, so Caddy won’t be able to automate cert issuance.

Yes, I’m saying you should make Caddy be the server that binds to ports 80 and 443, and you can use the reverse_proxy directive to route requests to your other container.

That way you get cert automation for all your domains (handled by Caddy).

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