How to create cert & credentials for Docker install?

I’ve searched all over, a few times, and can’t seem to find what I’m looking for. I could probably install cloudflared directly in my Debian host, outside docker, and do this, but I’m wondering why I can’t get it done from Docker. Probably my Docker ignorance.

How do I generate the cert & credentials file from the cli? The following gives me permission error.

sudo docker run -v /docker-services/cloudflared/config/:/home/nonroot/.cloudflared/ cloudflare/cloudflared:latest tunnel login

If there is a complete tutorial somewhere that I missed, I would appreciate any links, pointers, advice, etc.

I would recommend using a tunnel via the dashboard. It will give a single token that you need to connect, and you make all changes on the dashboard, so way easier to configure.

I’m trying to build a small homelab at home mostly for smarthome applications. Trying to use Caddy as my proxy, I’m attempting to follow the guide: “Caddy + Cloudflare tunnel”, on the Caddy wiki. And failing at many points along the way.

Trimming it down to essentials, and using a token instead as you recommend, I’m running

docker-services/caddy/docker-compose.yml

version: "3.7"

services:
  caddy:
    image: caddy-docker-proxy--mysmarthome_network:latest
    build:
      context: ./builder
      args:
        CADDY_VERSION: "2.5.2"
    ports:
      - "80:80"
      - "443:443"
    networks:
      - proxy
    env_file: .env
    environment:
      - CADDY_INGRESS_NETWORKS=proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /docker-services/caddy/data:/data
      - /docker-services/caddy/config:/config
      - /docker-services/caddy/logs:/var/log/caddy
    deploy:
      labels:
        caddy.debug:
        caddy.log.output: file /var/log/caddy/caddy.log
        caddy.acme_dns: "cloudflare {env.CF_API_TOKEN}"
        caddy.email: "{env.EMAIL}"
      placement:
        constraints:
          - node.role == manager
      replicas: 1
      restart_policy:
        condition: any

networks:
  proxy:
    external: true

/docker-services/cloudflared/docker-compose.yml

version: '3.7'

services:

  cloudflared:
    image: "cloudflare/cloudflared:latest"
    command: /usr/local/bin/cloudflared tunnel --no-autoupdate run
    env_file:
      - .env
    volumes:
      - /docker-services/cloudflared/config:/etc/cloudflared
    networks:
      - proxy
    extra_hosts:
      - "host.docker.internal:host-gateway"
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.role == manager]

networks:
  proxy:
    external: true

where the .env file defines TUNNEL_TOKEN

/docker-services/cloudflared/config/config.yml

ingress:
  - hostname: "cf-ssh.mysmarthome.network"
    service: ssh://host.docker.internal:222
  - hostname: "mysmarthome.network"
    service: https://caddy:443
    originRequest:
      originServerName: "mysmarthome.network"
  - hostname: "*.mysmarthome.network"
    service: https://caddy:443
    originRequest:
      originServerName: "mysmarthome.network"
  - service: http_status:404

cloudflared logs seem to indicate success?

2022-08-25T21:19:37Z INF Connection 0bd76c74-e1ce-445c-ab02-da9b80302ac3 registered connIndex=0 ip=198.41.200.233 location=ATL
2022-08-25T21:19:37Z INF Connection e482d83e-3fc3-463d-876d-e2d039d2669a registered connIndex=1 ip=198.41.192.7 location=ATL
2022-08-25T21:19:38Z INF Connection cd989e8c-119a-4519-8fd9-14d52b9c5a50 registered connIndex=2 ip=198.41.200.33 location=ATL
2022-08-25T21:19:39Z INF Connection f0812ec8-fada-479f-86ea-c5c4f8970897 registered connIndex=3 ip=198.41.192.67 location=ATL

Cloudflare dashboard shows connection is INACTIVE

I have a Public Hostname for the tunnel configured as

Subdomain: (blank)
Domain: mysmarthome.network
Path: (blank)
Service: HTTPS :// 443

And the dashboard seems to have created the correct DNS entry.

Why does it show inactive? I tried creating a wikijs container and the cname dns entry for it, but I can’t connect. Where am I going wrong?

I would not mount the config inside the cloudflared container, as it isn’t needed, and I’m not sure of the priory of config vs tunnel token.

Ok. I eliminated the config mount. No config. In fact, I cut just about everything out of docker-compose and it still fails. But the single line command works:

docker run cloudflare/cloudflared:latest tunnel --token xxxx

Maybe it isn’t getting the token. An example used TUNNEL_TOKEN to pass it in. Is that not correct? How do I pass the token to docker compose in an environment variable without embedding it directly in my compose file?

Why does cloudflared not connect when run in docker-compose? If I use the command given in the dashboard:

docker run cloudflare/cloudflared:latest tunnel --no-autoupdate run --token xxxyyyzzz

It seems to run fine and the Dashboard shows an active connection.

Here are logs of successful run:

2022-08-26T17:29:11Z INF Starting tunnel tunnelID=491a104e-5299-4998-a4fa-054a3bd00a32
2022-08-26T17:29:11Z INF Cannot determine default configuration path. No file [config.yml config.yaml] in [~/.cloudflared ~/.cloudflare-warp ~/cloudflare-warp /etc/cloudflared /usr/local/etc/cloudflared]
2022-08-26T17:29:11Z INF Version 2022.8.2
2022-08-26T17:29:11Z INF GOOS: linux, GOVersion: go1.19, GoArch: amd64
2022-08-26T17:29:11Z INF Settings: map[no-autoupdate:true token:*****]
2022-08-26T17:29:11Z INF Generated Connector ID: 60415ff1-fc6a-447e-914a-537ef3f95033
2022-08-26T17:29:11Z INF Will be fetching remotely managed configuration from Cloudflare API. Defaulting to protocol: quic
2022-08-26T17:29:11Z INF Initial protocol quic
2022-08-26T17:29:11Z INF Starting metrics server on 127.0.0.1:40867/metrics
2022/08/26 17:29:11 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size for details.
2022-08-26T17:29:11Z INF Connection 31293c33-eb56-429f-b8f5-81461d621847 registered connIndex=0 ip=198.41.200.63 location=ATL
2022-08-26T17:29:11Z INF Updated to new configuration config="{\"ingress\":[{\"hostname\":\"mysmarthome.network\",\"originRequest\":{},\"service\":\"https://443\"},{\"hostname\":\"wiki.mysmarthome.network\",\"originRequest\":{},\"service\":\"https://443\"},{\"service\":\"http_status:404\"}],\"warp-routing\":{\"enabled\":false}}" version=6
2022-08-26T17:29:11Z INF Connection 2d832a84-04c0-469d-93b7-9f50beb0e55d registered connIndex=1 ip=198.41.192.47 location=ATL
2022-08-26T17:29:13Z INF Connection 9127f2da-c08a-49fa-ba67-6a7c49f49fb6 registered connIndex=2 ip=198.41.200.43 location=ATL
2022-08-26T17:29:13Z INF Connection 4028b5b8-b15f-4b91-9112-367cc5492474 registered connIndex=3 ip=198.41.192.107 location=ATL

If I run the following docker-compose.yml it runs but the Dashboard shows Inactive

---
version: '3.7'

services:
  cloudflared:
    image: "cloudflare/cloudflared:latest"
    command: /usr/local/bin/cloudflared tunnel --no-autoupdate run --token xxxyyyzzz
    networks:
      - proxy
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.role == manager]
      restart_policy:
        condition: any

networks:
  proxy:
    external: true

Here are the logs:

2022-08-26T17:20:42Z INF Thank you for trying Cloudflare Tunnel. Doing so, without a Cloudflare account, is a quick way to experiment and try it out. However, be aware that these account-less Tunnels have no uptime guarantee. If you intend to use Tunnels in production you should use a pre-created named tunnel by following: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps
2022-08-26T17:20:42Z INF Requesting new quick Tunnel on trycloudflare.com...
2022-08-26T17:20:44Z INF +--------------------------------------------------------------------------------------------+
2022-08-26T17:20:44Z INF |  Your quick Tunnel has been created! Visit it at (it may take some time to be reachable):  |
2022-08-26T17:20:44Z INF |  https://detection-seeing-ebooks-colors.trycloudflare.com                                  |
2022-08-26T17:20:44Z INF +--------------------------------------------------------------------------------------------+
2022-08-26T17:20:44Z INF Cannot determine default configuration path. No file [config.yml config.yaml] in [~/.cloudflared ~/.cloudflare-warp ~/cloudflare-warp /etc/cloudflared /usr/local/etc/cloudflared]
2022-08-26T17:20:44Z INF Version 2022.8.2
2022-08-26T17:20:44Z INF GOOS: linux, GOVersion: go1.19, GoArch: amd64
2022-08-26T17:20:44Z INF Settings: map[no-autoupdate:true protocol:quic]
2022-08-26T17:20:44Z INF Generated Connector ID: 038e10ce-cfa3-4e9f-9ef5-3e276f70051b
2022-08-26T17:20:44Z INF Initial protocol quic
2022-08-26T17:20:44Z INF Starting metrics server on 127.0.0.1:37445/metrics
2022/08/26 17:20:44 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size for details.
2022-08-26T17:20:44Z ERR Failed to serve quic connection error="Unauthorized: Failed to get tunnel" connIndex=0 ip=198.41.200.73
2022-08-26T17:20:44Z ERR Register tunnel error from server side error="Unauthorized: Failed to get tunnel" connIndex=0 ip=198.41.200.73
2022-08-26T17:20:44Z INF Retrying connection in up to 2s seconds connIndex=0 ip=198.41.200.73
2022-08-26T17:20:46Z ERR Failed to serve quic connection error="Unauthorized: Failed to get tunnel" connIndex=0 ip=198.41.200.73
2022-08-26T17:20:46Z ERR Register tunnel error from server side error="Unauthorized: Failed to get tunnel" connIndex=0 ip=198.41.200.73
2022-08-26T17:20:46Z INF Retrying connection in up to 4s seconds connIndex=0 ip=198.41.200.73
2022-08-26T17:20:50Z INF Connection a54b6f6d-c930-46ed-b437-5bf8ae3d84f7 registered connIndex=0 ip=198.41.200.73 location=ATL
2022-08-26T17:20:51Z INF Connection 7f6b592a-de35-4fb3-8a19-3503179685ef registered connIndex=1 ip=198.41.192.107 location=ATL
2022-08-26T17:20:52Z INF Connection 2d5589a8-f764-4217-969a-03782a666b1c registered connIndex=2 ip=198.41.200.113 location=ATL
2022-08-26T17:20:53Z INF Connection 4612fd84-bed3-4783-92b6-28673925178a registered connIndex=3 ip=198.41.192.227 location=ATL

OK. Seems to be several flavors of cloudflared containers. For some reason I assumed they would all be more similar than not.

Some are run like:

docker run <org>/cloudflared tunnel <command>

Others are run as:

docker run <org>/cloudflared cloudflared tunnel <command>

Some will allow command line creation of tunnels. Actually, they may all do so, but they give errors when writing the cert.pem and .json files that I have not figured out. Why? And why does Cloudflare’s own container produce this error???

These do work:

docker run -v ${PWD}/config:/home/cloudflared/.cloudflared crazymax/cloudflared tunnel login

docker run -v ${PWD}/config:/root/.cloudflared msnelling/cloudflared cloudflared tunnel login

I could not get Cloudflare/cloudflared or visibilityspots/cloudflared containers to run like this. They produce write errors when creating the files.

And again when creating the tunnel (noting that msnelling/cloudflared writes tunnel credentials to a different directory that the cert):

docker run -v ${PWD}/config:/etc/cloudflared msnelling/cloudflared cloudflared tunnel create <tunnel-name>

docker run -v ${PWD}/config:/home/cloudflared/.cloudflared crazymax/cloudflared tunnel create <tunnel-name>

So there are variations on whether you need to include the command name (cloudflared) as the first argument or not, the internal directories where files are written to, and whether they can write to a mapped path.

I guess I’ll use either the crazymax or the msnelling container since I prefer to create my config locally, on the commandline: it’s easier to document and reproduce.