Caddy fails to parse tls section of Caddyfile in Github Actions

1. The problem I’m having:

I am trying to use Github Actions for some automation, and when I use a working Caddyfile in Github Actions it gives an error saying wrong arguments for tls

In my Caddyfile on Line 11 I commented out the tls section with environment variables and put in the actual paths and when running docker compose up in Github the error goes to the next tls section in the Caddyfile

I have echoed out the environment variables SSL_CERT_PATH and SSL_KEY_PATH by temporarily adding command: bash -c "echo $SSL_CERT_PATH" and command: bash -c "echo $SSL_KEY_PATH" section to the compose.yml and the echo is coming back with /etc/letsencrypt/cert.pem and /etc/letsencrypt/key.pem respectively.

I’d rather not hard-code the SSL cert and key paths as I want to keep them outside the Caddyfile.

Any ideas?

2. Error messages and/or full log output:

caddy  | Error: adapting config using caddyfile: parsing caddyfile tokens for 'tls': wrong argument count or unexpected line ending after 'tls', at /etc/caddy/Caddyfile:18

3. Caddy version:

2.8.4

4. How I installed and ran Caddy:

a. System environment:

Github Actions - Ubuntu latest

b. Command - GitHub Actions workflow file:

name: Docker Compose Action

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
        
      - name: Write key file
        env:
          SSL_CERT_ENCODED64: ${{ secrets.SSL_CERT_ENCODED64 }}
          SSL_KEY_ENCODED64: ${{ secrets.SSL_KEY_ENCODED64 }}
        run: |
          echo $SSL_CERT_ENCODED64 | base64 --decode > ${HOME}/cert.pem
          echo $SSL_KEY_ENCODED64 | base64 --decode > ${HOME}/key.pem
          mkdir -p ${GITHUB_WORKSPACE}/docker_hosts/docker02/proxied_apps/certbot/letsencrypt
          cp ${HOME}/cert.pem ${GITHUB_WORKSPACE}/docker_hosts/docker02/proxied_apps/certbot/letsencrypt/cert.pem
          cp ${HOME}/key.pem ${GITHUB_WORKSPACE}/docker_hosts/docker02/proxied_apps/certbot/letsencrypt/key.pem
      - name: Run docker-compose
        uses: hoverkraft-tech/compose-action@v2.0.1
        with:
          compose-file: "./docker_hosts/docker02/proxied_apps/caddy/compose.yml"
        env:
          CADDY_IMAGE_VERSION: ${{ vars.CADDY_IMAGE_VERSION }}
          CADDY_CLOUDFLARE_HTTPS_PROXY_PORT: ${{ vars.CADDY_CLOUDFLARE_HTTPS_PROXY_PORT }}
          CADDY_HTTPS_PORT: ${{ vars.CADDY_HTTPS_PORT }}
          CADDY_METRICS_PORT: ${{ vars.CADDY_METRICS_PORT }}
          SSL_CERT_PATH: ${{ vars.SSL_CERT_PATH }}
          SSL_KEY_PATH: ${{ vars.SSL_KEY_PATH }}          
          DOMAIN_NAME: ${{ secrets.DOMAIN_NAME }}

c. Service/unit/compose file:

services:
  caddy:
    container_name: caddy
    image: caddy:${CADDY_IMAGE_VERSION}
    environment:
      - DOMAIN_NAME=${DOMAIN_NAME}
      - CADDY_CLOUDFLARE_HTTPS_PROXY_PORT=${CADDY_CLOUDFLARE_HTTPS_PROXY_PORT}
      - CADDY_METRICS_PORT=${CADDY_METRICS_PORT}
    ports:
      - ${CADDY_HTTPS_PORT}:${CADDY_HTTPS_PORT}
      - ${CADDY_METRICS_PORT}:${CADDY_METRICS_PORT}
      - ${CADDY_CLOUDFLARE_HTTPS_PROXY_PORT}:${CADDY_CLOUDFLARE_HTTPS_PROXY_PORT}
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./data:/data
      - ../certbot/letsencrypt:/etc/letsencrypt
    networks:
      - proxy
    restart: unless-stopped

networks:
  proxy:
    driver: bridge
    name: proxy

d. My complete Caddy config:

{
	auto_https off
	servers {
		metrics
	}
	admin :{$CADDY_METRICS_PORT}
}

# Internally Accessible Only Servers
mqtt.{$DOMAIN_NAME} {
	reverse_proxy http://mqtt:18083
	#tls {$SSL_CERT_PATH} {$SSL_KEY_PATH}
	tls /etc/letsencrypt/cert.pem /etc/letsencrypt/key.pem
}

kuma.{$DOMAIN_NAME} {
	reverse_proxy http://kuma:3001
	tls {$SSL_CERT_PATH} {$SSL_KEY_PATH}
}

homer.{$DOMAIN_NAME} {
	reverse_proxy http://homer:8080
	tls {$SSL_CERT_PATH} {$SSL_KEY_PATH}
}

jellyfin.{$DOMAIN_NAME} {
	reverse_proxy http://jellyfin:8096
	tls {$SSL_CERT_PATH} {$SSL_KEY_PATH}
}

paperless.{$DOMAIN_NAME} {
	reverse_proxy http://paperless-ngx-webserver-1:8000
	tls {$SSL_CERT_PATH} {$SSL_KEY_PATH}
}

# Externalliny and Internally Accessible Servers
owncloud.{$DOMAIN_NAME}:2096 {
	log {
		level INFO
		output file /data/logs/caddy.log {
			roll_size 10MB
			roll_keep 10
		}
	}
	reverse_proxy http://owncloud:8080 {
		header_up X-Forwarded-For {http.request.header.Cf-Connecting-IP}
	}
	tls {$SSL_CERT_PATH} {$SSL_KEY_PATH}
}

onlyoffice.{$DOMAIN_NAME}:2096 {
	reverse_proxy http://onlyoffice
	tls {$SSL_CERT_PATH} {$SSL_KEY_PATH}
}

jellyfin.{$DOMAIN_NAME}:2096 {
	reverse_proxy http://jellyfin:8096
	tls {$SSL_CERT_PATH} {$SSL_KEY_PATH}
}

# Uncomment this in addition with the import admin_redir statement allow access to the admin interface only from local networks
(admin_redir) {
	@admin {
		path /admin*
		not remote_ip private_ranges
	}
	redir @admin /
}

vaultwarden.{$DOMAIN_NAME}:2096 {
	log {
		level INFO
		output file /data/logs/caddy.log {
			roll_size 10MB
			roll_keep 10
		}
	}
	tls {$SSL_CERT_PATH} {$SSL_KEY_PATH}
	encode zstd gzip
	import admin_redir
	reverse_proxy http://vaultwarden:80 {
		header_up X-Real-IP {http.request.header.Cf-Connecting-IP}
	}
}

5. Links to relevant resources:

What do you get from running caddy environ in situ?

I can see where you’re injecting the cert/key paths in your workflow file but I don’t see where that actually gets injected inside the container in the Compose file you posted.

1 Like

I’m setting the SSL_CERT_PATH and SSL_KEY_PATH environment variables in this part of the Githubs Action. The complete file is in my original post section 4b

      - name: Run docker-compose
        uses: hoverkraft-tech/compose-action@v2.0.1
        with:
          compose-file: "./docker_hosts/docker02/proxied_apps/caddy/compose.yml"
        env:
          CADDY_IMAGE_VERSION: ${{ vars.CADDY_IMAGE_VERSION }}
          CADDY_CLOUDFLARE_HTTPS_PROXY_PORT: ${{ vars.CADDY_CLOUDFLARE_HTTPS_PROXY_PORT }}
          CADDY_HTTPS_PORT: ${{ vars.CADDY_HTTPS_PORT }}
          CADDY_METRICS_PORT: ${{ vars.CADDY_METRICS_PORT }}
          SSL_CERT_PATH: ${{ vars.SSL_CERT_PATH }}
          SSL_KEY_PATH: ${{ vars.SSL_KEY_PATH }}          
          DOMAIN_NAME: ${{ secrets.DOMAIN_NAME }}

Let me see how I can stop the docker container to get the output of the caddy environ command. As the container just stops when it hits the error from the Caddyfile

Yes, I can see where you put it into the action runner environment, but your actual compose file only seems to have these:

I don’t see SSL_CERT_PATH or SSL_KEY_PATH in the environment stanza of your compose file. Do they need to be added there? I’m not entirely sure because as you said the environment variables got in there somehow and you read them with bash. But I figured I’d ask the question.

You can just set command: caddy environ like you did with bash earlier.

1 Like

Thank you! I can’t believe I missed that! It’s working now in GitHub Actions

Added it to the compose.yml:

    environment:
      - DOMAIN_NAME=${DOMAIN_NAME}
      - CADDY_CLOUDFLARE_HTTPS_PROXY_PORT=${CADDY_CLOUDFLARE_HTTPS_PROXY_PORT}
      - CADDY_METRICS_PORT=${CADDY_METRICS_PORT}
      - SSL_CERT_PATH=${SSL_CERT_PATH}
      - SSL_KEY_PATH=${SSL_KEY_PATH}
1 Like

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