1. Caddy version:
caddy:2.6-builder-alpine
2. How I installed, and run Caddy:
The docker compose build work fine from localhost
a. System environment:
Docker achitecture with
- api php via php-fpm
- front angular with 2 environments:
- public: localhost:4201
- backend: localhost:4202
b. Command:
I just start my docker environment.
docker compose up -d
c. Service/unit/compose file:
docker-compose.yml
services:
php:
build:
context: .
target: app_php
args:
SYMFONY_VERSION: ${SYMFONY_VERSION:-5.4}
STABILITY: ${STABILITY:-stable}
restart: unless-stopped
volumes:
- php_socket:/var/run/php
healthcheck:
interval: 10s
timeout: 3s
retries: 3
start_period: 30s
environment:
DATABASE_URL: mysql://glsr:glsr@mariadb:3306/glsr?serverVersion=mariadb-10.2.44
links:
- mariadb
client:
build:
context: .
target: app_node
tty: true
working_dir: '/glsr/client'
user: '1000:1000'
command: yarn run start
volumes:
- './:/glsr'
caddy:
build:
context: .
target: app_caddy
depends_on:
- php
- client
environment:
SERVER_NAME: ${SERVER_NAME:-localhost, caddy:80}
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
Dockerfile
#syntax=docker/dockerfile:1.4
# The different stages of this Dockerfile are meant to be built into separate images
# https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage
# https://docs.docker.com/compose/compose-file/#target
# Builder images
FROM composer/composer:2-bin AS composer
FROM mlocati/php-extension-installer:latest AS php_extension_installer
FROM node:14.15 AS app_node
RUN yarn global add @angular/cli@11.0.5
COPY --link ./client ./client
# Build Caddy with the Mercure and Vulcain modules
FROM caddy:2.6-builder-alpine AS app_caddy_builder
RUN xcaddy build \
--with github.com/dunglas/mercure \
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain \
--with github.com/dunglas/vulcain/caddy
# Prod image
FROM php:7.4-fpm-alpine AS app_php
# Allow to use development versions of Symfony
ARG STABILITY="stable"
ENV STABILITY ${STABILITY}
# Allow to select Symfony version
ARG SYMFONY_VERSION=""
ENV SYMFONY_VERSION ${SYMFONY_VERSION}
ENV APP_ENV=prod
# Allow to select workdir
ARG WORKDIR='/glsr'
ENV WORKDIR=${WORKDIR}
WORKDIR ${WORKDIR}
# php extensions installer: https://github.com/mlocati/docker-php-extension-installer
COPY --from=php_extension_installer --link /usr/bin/install-php-extensions /usr/local/bin/
# persistent / runtime deps
RUN apk add --no-cache \
acl \
fcgi \
file \
gettext \
git \
libmemcached-dev \
;
RUN set -eux; \
install-php-extensions \
pdo \
pdo_mysql \
memcached \
intl \
zip \
apcu \
opcache \
;
###> recipes ###
###< recipes ###
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY --link docker/php/conf.d/app.ini $PHP_INI_DIR/conf.d/
COPY --link docker/php/conf.d/app.prod.ini $PHP_INI_DIR/conf.d/
COPY --link docker/php/php-fpm.d/zz-docker.conf /usr/local/etc/php-fpm.d/zz-docker.conf
RUN mkdir -p /var/run/php
COPY --link docker/php/docker-healthcheck.sh /usr/local/bin/docker-healthcheck
RUN chmod +x /usr/local/bin/docker-healthcheck
HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD ["docker-healthcheck"]
COPY --link docker/php/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
RUN chmod +x /usr/local/bin/docker-entrypoint
ENTRYPOINT ["docker-entrypoint"]
CMD ["php-fpm"]
# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
ENV COMPOSER_ALLOW_SUPERUSER=1
ENV PATH="${PATH}:/root/.composer/vendor/bin"
COPY --from=composer --link /composer /usr/bin/composer
# prevent the reinstallation of vendors at every changes in the source code
COPY --link ./server/composer.* ./server/symfony.* ./
RUN set -eux; \
if [ -f composer.json ]; then \
composer install --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress; \
composer clear-cache; \
fi
# copy sources
COPY --link ./server ./
RUN rm -Rf docker/
RUN set -eux; \
mkdir -p var/cache var/log; \
chown -R www-data:www-data var; \
if [ -f composer.json ]; then \
composer dump-autoload --classmap-authoritative --no-dev; \
composer dump-env prod; \
composer run-script --no-dev post-install-cmd; \
chmod +x bin/console; sync; \
fi
# Dev image
FROM app_php AS app_php_dev
# Allow to select workdir
ARG WORKDIR='/glsr'
ENV WORKDIR=${WORKDIR}
ENV APP_ENV=dev XDEBUG_MODE=off
VOLUME ${WORKDIR}/var/
RUN rm "$PHP_INI_DIR/conf.d/app.prod.ini"; \
mv "$PHP_INI_DIR/php.ini" "$PHP_INI_DIR/php.ini-production"; \
mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
COPY --link docker/php/conf.d/app.dev.ini $PHP_INI_DIR/conf.d/
RUN set -eux; \
install-php-extensions xdebug
RUN rm -f .env.local.php
# Caddy image
FROM caddy:2.6-alpine AS app_caddy
# Allow to select workdir
ARG WORKDIR='/glsr'
ENV WORKDIR=${WORKDIR}
WORKDIR ${WORKDIR}
COPY --from=app_caddy_builder --link /usr/bin/caddy /usr/bin/caddy
COPY --from=app_php --link /glsr/public ${WORKDIR}/public
COPY --from=app_node --link ./client ${WORKDIR}/client
COPY --link docker/caddy/Caddyfile /etc/caddy/Caddyfile
d. My complete Caddy config:
{
# Debug
{$CADDY_DEBUG}
}
{$SERVER_NAME}
log
route {
handle_path /backend/* {
reverse_proxy localhost:4202
}
handle /api/* {
reverse_proxy php_fastcgi unix//var/run/php/php-fpm.sock
}
handle {
reverse_proxy localhost:4201
}
encode zstd gzip
file_server
}
3. The problem I’m having:
I’d trying turn my Nginx config:
server {
listen 80;
server_name localhost;
set $projectroot '/glsr';
set $clientroot 'glsr/client/dist';
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
client_max_body_size 32M;
## Don't log robots.txt requests.
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location /api {
root $projectroot/server/public;
rewrite ^/api/(.*)$ /index.php/$1 break;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $projectroot/server/public/$fastcgi_script_name;
fastcgi_param HTTPS off;
fastcgi_pass php:9000;
}
location /backend {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_pass http://client:4202/backend;
proxy_redirect off;
}
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_pass http://client:4201;
proxy_redirect off;
}
## For the symfony debug bar _profiler
location ~ ^/index\.php(/|$) {
fastcgi_pass php:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $projectroot/server/public/$fastcgi_script_name;
fastcgi_param HTTPS off;
}
}
to Caddy (see up the config)
4. Error messages and/or full log output:
When I try https://localhost
on my browser:
{"level":"error","ts":1675704738.674929,"logger":"http.log.error","msg":"dial tcp 0.0.0.0:4201: connect: connection refused","request":{"remote_ip":"172.20.0.1","remote_port":"42644","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/","headers":{"Sec-Fetch-Site":["none"],"Sec-Fetch-User":["?1"],"Te":["trailers"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"],"Cookie":[],"Upgrade-Insecure-Requests":["1"],"Sec-Fetch-Dest":["document"],"Sec-Fetch-Mode":["navigate"],"User-Agent":["Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0"],"Accept-Language":["fr-FR,en-US;q=0.7,en;q=0.3"],"Accept-Encoding":["gzip, deflate, br"],"Dnt":["1"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"localhost"}},"duration":0.001224846,"status":502,"err_id":"uh9dn5igr","err_trace":"reverseproxy.statusError (reverseproxy.go:1272)"}
{"level":"error","ts":1675704738.6749487,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"172.20.0.1","remote_port":"42644","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/","headers":{"Dnt":["1"],"User-Agent":["Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0"],"Accept-Language":["fr-FR,en-US;q=0.7,en;q=0.3"],"Accept-Encoding":["gzip, deflate, br"],"Sec-Fetch-Dest":["document"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-Site":["none"],"Sec-Fetch-User":["?1"],"Te":["trailers"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"],"Cookie":[],"Upgrade-Insecure-Requests":["1"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"localhost"}},"user_id":"","duration":0.001224846,"size":0,"status":502,"resp_headers":{"Server":["Caddy"],"Alt-Svc":["h3=\":443\"; ma=2592000"]}}
5. What I already tried:
I begin with the default symfony config:
route {
root /api/* /glsr/public
php_fastcgi unix//var/run/php/php-fpm.sock
reverse_proxy / localhost:4201
reverse_proxy /backend/* localhost:4202
encode zstd gzip
file_server
}
This work without errors, but only api routes works. Nothings happens on the other urls.
6. Links to relevant resources:
From my search:
Using Caddy as a reverse proxy with multiple subdirectories and rewrites
Use Symfony with docker (and Caddy )