Caddy in Docker On Private Network

1. The problem I’m having:

Full disclosure. Brand new to Caddy - quite new to docker. 40+ years programmer and DBA.

This is a problem involving Caddy but possibly not caused by it. Hoping someone here might offer advice at least.

Asked for help at the NextCloud forums but was told “outside of our scope - go ask the Caddy people” so here I am

We are currently evaluating a product called NextCloud to see if we can adopt it and migrate away from some other products. Wanting to use Docker containers as much as possible, I followed a tutorial here to install the components (NextCloud, Nginx, Redis, Caddy and Mariadb and in five separate containers and everything went (mostly) to plan.

Unfortunately when I started up the containers and tried to access the site I realised that it was not going to work. My browser returns an SSL_ERROR_INTERNAL_ERROR_ALERT. When I look in the Caddy docker log I can see that it is trying to automatically get a cert from acme.zerossl.com which is failing because the machine is on a private network and is not DNS addressable from the outside world. (The reason for this is that this instance of NextCloud will be internal to employees. When they are on the road they reach our internal network via a CloudFlare tunnel and a Warp client).

I read in the docs that Caddy will not try to get an automatic certificate if there is I used an IP address rather than a FQDN so I tried to substitute the internal IP address of 192.168.0.156 for the previous “nc.pfs.lan” but still cannot connect.

I’ve included the full yaml file I am using plus the output of the relevant docker log command.

Grateful for any and all suggestions (well almost any).

Rgds

Nigel.

$ cat docker-compose.yaml
version: "3.8"
services:

  caddy:
    image: lucaslorentz/caddy-docker-proxy:ci-alpine
    container_name: reverse-proxy
    ports:
      - 80:80
      - 443:443
    environment:
      - CADDY_INGRESS_NETWORKS=nextcloud_network
    networks:
      - nextcloud_network
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - caddy_data:/data
    restart: unless-stopped

  web:
    image: nginx:alpine
    container_name: nextcloud-web
    networks:
      - nextcloud_network
    links:
      - nextcloud
    labels:
      caddy: 192.168.0.156
      caddy.reverse_proxy: "{{upstreams}}"
      caddy.header: /*
      caddy.header.Strict-Transport-Security: '"max-age=15552000;"'
      caddy.rewrite_0: /.well-known/carddav /remote.php/dav
      caddy.rewrite_1: /.well-known/caldav /remote.php/dav
      caddy.rewrite_2: /.well-known/webfinger /index.php/.well-known/webfinger
      caddy.rewrite_3: /.well-known/nodeinfo /index.php/.well-known/nodeinfo
    volumes:
      - nextcloud_data:/data:z,ro
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    restart: unless-stopped

  db:
    image: mariadb:10.11
    container_name: mariadb-database
    command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
    networks:
      - nextcloud_network
    volumes:
      - db_data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD
      - MYSQL_USER
      - MYSQL_PASSWORD
      - MYSQL_DATABASE
    restart: unless-stopped

  redis:
    image: redis:alpine
    container_name: redis-dbcache
    networks:
      - nextcloud_network
    restart: unless-stopped

  nextcloud:
    image: nextcloud:stable-fpm
    container_name: nextcloud-app
    networks:
      - nextcloud_network
    volumes:
      - nextcloud_data:/data:z
      - ./php-fpm-www.conf:/usr/local/etc/php-fpm.d/www.conf:ro
    environment:
      - MYSQL_USER
      - MYSQL_PASSWORD
      - MYSQL_DATABASE
      - MYSQL_HOST
      - REDIS_HOST
      - OVERWRITEPROTOCOL
      - OVERWRITEHOST
      - TRUSTED_PROXIES
      - APACHE_DISABLE_REWRITE_IP
    restart: unless-stopped
    depends_on:
      - caddy
      - db
      - redis

  cron:
    image: nextcloud:stable-fpm
    container_name: nextcloud-cron
    networks:
      - nextcloud_network
    volumes:
      - nextcloud_data:/data:z
    entrypoint: /cron.sh
    restart: unless-stopped
    depends_on:
      - db
      - redis

networks:
  nextcloud_network:
    external: true

volumes:
  caddy_data: {}
  db_data: {}
  nextcloud_data: {}

2. Error messages and/or full log output:

$ docker logs reverse-proxy
{"level":"info","ts":1687400511.9819803,"logger":"docker-proxy","msg":"Running caddy proxy server"}
{"level":"info","ts":1687400511.9832118,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1687400511.9836187,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1687400511.983723,"logger":"docker-proxy","msg":"Running caddy proxy controller"}
{"level":"info","ts":1687400511.9890149,"logger":"docker-proxy","msg":"Start","CaddyfilePath":"","LabelPrefix":"caddy","PollingInterval":30,"ProcessCaddyfile":true,"ProxyServiceTasks":true,"IngressNetworks":"[nextcloud_network]","DockerSockets":[""],"DockerCertsPath":[""],"DockerAPIsVersion":[""]}
{"level":"info","ts":1687400511.990484,"logger":"docker-proxy","msg":"Connecting to docker events","DockerSocket":""}
{"level":"info","ts":1687400511.9989831,"logger":"docker-proxy","msg":"IngressNetworksMap","ingres":"map[3547cffe8599f928f017fd6d2ae2ddf75cf92efa6d97d8145cd50ca9fd00078f:true nextcloud_network:true]"}
{"level":"info","ts":1687400512.0153003,"logger":"docker-proxy","msg":"Swarm is available","new":false}
{"level":"info","ts":1687400512.0169148,"logger":"docker-proxy","msg":"New Caddyfile","caddyfile":"# Empty caddyfile"}
{"level":"warn","ts":1687400512.0171936,"logger":"docker-proxy","msg":"Caddyfile to json warning","warn":"[Caddyfile:1: Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies]"}
{"level":"info","ts":1687400512.017205,"logger":"docker-proxy","msg":"New Config JSON","json":"{}"}
{"level":"info","ts":1687400512.0172515,"logger":"docker-proxy","msg":"Sending configuration to","server":"localhost"}
{"level":"info","ts":1687400512.018118,"logger":"admin.api","msg":"received request","method":"POST","host":"localhost:2019","uri":"/load","remote_ip":"127.0.0.1","remote_port":"55118","headers":{"Accept-Encoding":["gzip"],"Content-Length":["41"],"Content-Type":["application/json"],"User-Agent":["Go-http-client/1.1"]}}
{"level":"info","ts":1687400512.0181642,"msg":"config is unchanged"}
{"level":"info","ts":1687400512.018171,"logger":"admin.api","msg":"load complete"}
{"level":"info","ts":1687400512.018248,"logger":"docker-proxy","msg":"Successfully configured","server":"localhost"}
{"level":"info","ts":1687400512.9820335,"logger":"docker-proxy","msg":"New Caddyfile","caddyfile":"192.168.0.156 {\n\theader /* {\n\t\tStrict-Transport-Security max-age=15552000;\n\t}\n\treverse_proxy 172.18.0.7\n\trewrite /.well-known/caldav /remote.php/dav\n\trewrite /.well-known/carddav /remote.php/dav\n\trewrite /.well-known/nodeinfo /index.php/.well-known/nodeinfo\n\trewrite /.well-known/webfinger /index.php/.well-known/webfinger\n}\n"}
{"level":"info","ts":1687400512.9829779,"logger":"docker-proxy","msg":"New Config JSON","json":"{\"apps\":{\"http\":{\"servers\":{\"srv0\":{\"listen\":[\":443\"],\"routes\":[{\"match\":[{\"host\":[\"192.168.0.156\"]}],\"handle\":[{\"handler\":\"subroute\",\"routes\":[{\"handle\":[{\"handler\":\"headers\",\"response\":{\"set\":{\"Strict-Transport-Security\":[\"max-age=15552000;\"]}}}],\"match\":[{\"path\":[\"/*\"]}]},{\"group\":\"group0\",\"handle\":[{\"handler\":\"rewrite\",\"uri\":\"/index.php/.well-known/webfinger\"}],\"match\":[{\"path\":[\"/.well-known/webfinger\"]}]},{\"group\":\"group0\",\"handle\":[{\"handler\":\"rewrite\",\"uri\":\"/index.php/.well-known/nodeinfo\"}],\"match\":[{\"path\":[\"/.well-known/nodeinfo\"]}]},{\"group\":\"group0\",\"handle\":[{\"handler\":\"rewrite\",\"uri\":\"/remote.php/dav\"}],\"match\":[{\"path\":[\"/.well-known/carddav\"]}]},{\"group\":\"group0\",\"handle\":[{\"handler\":\"rewrite\",\"uri\":\"/remote.php/dav\"}],\"match\":[{\"path\":[\"/.well-known/caldav\"]}]},{\"handle\":[{\"handler\":\"reverse_proxy\",\"upstreams\":[{\"dial\":\"172.18.0.7:80\"}]}]}]}],\"terminal\":true}]}}}}}"}
{"level":"info","ts":1687400512.9830692,"logger":"docker-proxy","msg":"Sending configuration to","server":"localhost"}
{"level":"info","ts":1687400512.9833546,"logger":"admin.api","msg":"received request","method":"POST","host":"localhost:2019","uri":"/load","remote_ip":"127.0.0.1","remote_port":"55118","headers":{"Accept-Encoding":["gzip"],"Content-Length":["936"],"Content-Type":["application/json"],"User-Agent":["Go-http-client/1.1"]}}
{"level":"info","ts":1687400512.9841971,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1687400512.984468,"logger":"http","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
{"level":"info","ts":1687400512.9846375,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1687400512.9847274,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc0000fe7e0"}
{"level":"info","ts":1687400512.9870853,"logger":"tls","msg":"cleaning storage unit","description":"FileStorage:/data/caddy"}
{"level":"info","ts":1687400512.9886067,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"warn","ts":1687400513.0205412,"logger":"pki.ca.local","msg":"installing root certificate (you might be prompted for password)","path":"storage:pki/authorities/local/root.crt"}
{"level":"info","ts":1687400513.0208957,"msg":"warning: \"certutil\" is not available, install \"certutil\" with \"apt install libnss3-tools\" or \"yum install nss-tools\" and try again"}
{"level":"info","ts":1687400513.0209532,"msg":"define JAVA_HOME environment variable to use the Java trust"}
{"level":"info","ts":1687400513.1081877,"msg":"certificate installed properly in linux trusts"}
{"level":"info","ts":1687400513.1084201,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":1687400513.1085315,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details."}
{"level":"info","ts":1687400513.1086173,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"info","ts":1687400513.1086614,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":1687400513.1086671,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["192.168.0.156"]}
{"level":"warn","ts":1687400513.1090505,"logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [192.168.0.156]: no OCSP server specified in certificate","identifiers":["192.168.0.156"]}
{"level":"info","ts":1687400513.1092398,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1687400513.1092494,"logger":"admin.api","msg":"load complete"}
{"level":"info","ts":1687400513.1095586,"logger":"docker-proxy","msg":"Successfully configured","server":"localhost"}
{"level":"info","ts":1687400513.1300268,"logger":"admin","msg":"stopped previous server","address":"localhost:2019"}

3. Caddy version:

$ docker-compose exec caddy caddy version

v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=

4. How I installed and ran Caddy:

a. System environment:

Via yaml file and docker-compose up

b. Command:

docker-compose up -d

c. Service/unit/compose file:

d. My complete Caddy config:

All in previous yaml file

5. Links to relevant resources:

The only way you’d be able to get a publicly trusted certificate if your server isn’t publicly accessible is by using the ACME DNS challenge.

Thanks.

I actually do not particularly want a certificate as this is internal use only. I had hoped it would be a simple exercise.

Rgds

Nigel.

If you’re fine with HTTP only, just use :80 as your site address.

Or use tls internal to have Caddy issue a certificate using its internal CA. See the docs for how to grab Caddy’s root CA cert so you can install it on your machines to establish trust: Keep Caddy Running — Caddy Documentation

1 Like

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