dokku / dokku-letsencrypt

Automatic Let's Encrypt TLS Certificate installation for dokku
https://blog.semicolonsoftware.de/securing-dokku-with-lets-encrypt-tls-certificates/
MIT License
1.09k stars 92 forks source link

Wildcard SSL and Non-wildcard SSL for the same Dokku app #327

Closed elamje closed 8 months ago

elamje commented 8 months ago

Description of problem

For subdomain wildcarding, I must use dokku letsencrypt:set --global dns-provider-CLOUDFLARE_EMAIL and set the api key. This works great since I control the domain I need this on. However, for my business clients, I need to set up their websites to point to my same Dokku app.

I can easily add their domain to my app, but when I need to add SSL, using this plugin, it tries to retrieve SSL certs via Cloudflare DNS authentication instead of standard HTTP auth.

How reproducible

Steps to Reproduce

1. 2. 3.

Actual Results

2024/03/04 15:06:33 Could not obtain certificates:
        error: one or more domains had a problem:
[blog.myclient.dev] [blog.myclient.dev] acme: error presenting token: cloudflare: failed to find zone myclient.dev.: zone could not be found
-----> Certificate retrieval failed!
-----> Disabling ACME proxy for listings...
 !     Failed to setup letsencrypt
 !     Check log output for further information on failure

Expected Results

  1. Use Cloudflare DNS Auth to set up my wildcarded subdomain
  2. Use HTTP DNS Auth to set up blog.myclient.dev (non-wildcarded, client-owned) subdomain

It seems that this plugin has assumed that each app will EITHER use DNS auth OR HTTP auth for SSL validation.

Environment Information

dokku report listings output

-----> uname: Linux listings-app 5.15.0-76-generic #83-Ubuntu SMP Thu Jun 15 19:16:32 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
-----> memory: 
                      total        used        free      shared  buff/cache   available
       Mem:             957         398          72          10         486         367
       Swap:              0           0           0
-----> docker version: 
       Client: Docker Engine - Community
        Version:           24.0.4
        API version:       1.43
        Go version:        go1.20.5
        Git commit:        3713ee1
        Built:             Fri Jul  7 14:50:55 2023
        OS/Arch:           linux/amd64
        Context:           default

       Server: Docker Engine - Community
        Engine:
         Version:          24.0.4
         API version:      1.43 (minimum version 1.12)
         Go version:       go1.20.5
         Git commit:       4ffc614
         Built:            Fri Jul  7 14:50:55 2023
         OS/Arch:          linux/amd64
         Experimental:     false
        containerd:
         Version:          1.6.21
         GitCommit:        3dce8eb055cbb6872793272b4f20ed16117344f8
        runc:
         Version:          1.1.7
         GitCommit:        v1.1.7-0-g860f061
        docker-init:
         Version:          0.19.0
         GitCommit:        de40ad0
-----> docker daemon info: 
       Client: Docker Engine - Community
        Version:    24.0.4
        Context:    default
        Debug Mode: true
        Plugins:
         buildx: Docker Buildx (Docker Inc.)
           Version:  v0.11.1
           Path:     /usr/libexec/docker/cli-plugins/docker-buildx
         compose: Docker Compose (Docker Inc.)
           Version:  v2.19.1
           Path:     /usr/libexec/docker/cli-plugins/docker-compose

       Server:
        Containers: 1
         Running: 1
         Paused: 0
         Stopped: 0
        Images: 8
        Server Version: 24.0.4
        Storage Driver: overlay2
         Backing Filesystem: extfs
         Supports d_type: true
         Using metacopy: false
         Native Overlay Diff: true
         userxattr: false
        Logging Driver: json-file
        Cgroup Driver: systemd
        Cgroup Version: 2
        Plugins:
         Volume: local
         Network: bridge host ipvlan macvlan null overlay
         Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
        Swarm: inactive
        Runtimes: io.containerd.runc.v2 runc
        Default Runtime: runc
        Init Binary: docker-init
        containerd version: 3dce8eb055cbb6872793272b4f20ed16117344f8
        runc version: v1.1.7-0-g860f061
        init version: de40ad0
        Security Options:
         apparmor
         seccomp
          Profile: builtin
         cgroupns
        Kernel Version: 5.15.0-76-generic
        Operating System: Ubuntu 22.04.2 LTS
        OSType: linux
        Architecture: x86_64
        CPUs: 1
        Total Memory: 957.4MiB
        Name: listings-app
        ID: 765b0c87-e779-4052-aa3d-ea80d33b6383
        Docker Root Dir: /var/lib/docker
        Debug Mode: false
         File Descriptors: 29
         Goroutines: 39
         System Time: 2024-03-04T15:24:12.511353154Z
         EventsListeners: 0
        Experimental: false
        Insecure Registries:
         127.0.0.0/8
        Live Restore Enabled: false

-----> git version: git version 2.34.1
-----> sigil version: 0.9.0build+bc921b7
-----> herokuish version: 
       herokuish: v0.6.0
       buildpacks:
         heroku-buildpack-multi     v1.2.0
         heroku-buildpack-ruby      v254
         heroku-buildpack-nodejs    v213
         heroku-buildpack-clojure   v90
         heroku-buildpack-python    v232
         heroku-buildpack-java      v72
         heroku-buildpack-gradle    v39
         heroku-buildpack-scala     v96
         heroku-buildpack-play      v26
         heroku-buildpack-php       v234
         heroku-buildpack-go        v174
         heroku-buildpack-nginx     v23
         buildpack-null             v3
-----> dokku version: dokku version 0.30.9
-----> plugn version: plugn: 0.12.0build+3a27594
-----> dokku plugins: 
         00_dokku-standard    0.30.9 enabled    dokku core standard plugin
         20_events            0.30.9 enabled    dokku core events logging plugin
         app-json             0.30.9 enabled    dokku core app-json plugin
         apps                 0.30.9 enabled    dokku core apps plugin
         builder              0.30.9 enabled    dokku core builder plugin
         builder-dockerfile   0.30.9 enabled    dokku core builder-dockerfile plugin
         builder-herokuish    0.30.9 enabled    dokku core builder-herokuish plugin
         builder-lambda       0.30.9 enabled    dokku core builder-lambda plugin
         builder-null         0.30.9 enabled    dokku core builder-null plugin
         builder-pack         0.30.9 enabled    dokku core builder-pack plugin
         buildpacks           0.30.9 enabled    dokku core buildpacks plugin
         caddy-vhosts         0.30.9 enabled    dokku core caddy-vhosts plugin
         certs                0.30.9 enabled    dokku core certificate management plugin
         checks               0.30.9 enabled    dokku core checks plugin
         common               0.30.9 enabled    dokku core common plugin
         config               0.30.9 enabled    dokku core config plugin
         cron                 0.30.9 enabled    dokku core cron plugin
         docker-options       0.30.9 enabled    dokku core docker-options plugin
         domains              0.30.9 enabled    dokku core domains plugin
         enter                0.30.9 enabled    dokku core enter plugin
         git                  0.30.9 enabled    dokku core git plugin
         haproxy-vhosts       0.30.9 enabled    dokku core haproxy-vhosts plugin
         letsencrypt          0.20.1 enabled    Automated installation of let's encrypt TLS certificates
         logs                 0.30.9 enabled    dokku core logs plugin
         network              0.30.9 enabled    dokku core network plugin
         nginx-vhosts         0.30.9 enabled    dokku core nginx-vhosts plugin
         plugin               0.30.9 enabled    dokku core plugin plugin
         proxy                0.30.9 enabled    dokku core proxy plugin
         ps                   0.30.9 enabled    dokku core ps plugin
         registry             0.30.9 enabled    dokku core registry plugin
         repo                 0.30.9 enabled    dokku core repo plugin
         resource             0.30.9 enabled    dokku core resource plugin
         run                  0.30.9 enabled    dokku core run plugin
         scheduler            0.30.9 enabled    dokku core scheduler plugin
         scheduler-docker-local 0.30.9 enabled    dokku core scheduler-docker-local plugin
         scheduler-null       0.30.9 enabled    dokku core scheduler-null plugin
         shell                0.30.9 enabled    dokku core shell plugin
         ssh-keys             0.30.9 enabled    dokku core ssh-keys plugin
         storage              0.30.9 enabled    dokku core storage plugin
         trace                0.30.9 enabled    dokku core trace plugin
         traefik-vhosts       0.30.9 enabled    dokku core traefik-vhosts plugin
=====> listings app-json information
       App json computed selected:    app.json
       App json global selected:      app.json
       App json selected:             
=====> listings app information
       App created at:                1690058171
       App deploy source:             git-push
       App deploy source metadata:    7710b69498f1a1b1106021170fcabb1ff1b7c12b
       App dir:                       /home/dokku/listings
       App locked:                    false
=====> listings builder information
       Builder build dir:             
       Builder computed build dir:    
       Builder computed selected:     
       Builder global build dir:      
       Builder global selected:       
       Builder selected:              
=====> listings builder-dockerfile information
       Builder dockerfile computed dockerfile path: Dockerfile               
       Builder dockerfile global dockerfile path: Dockerfile               
       Builder dockerfile dockerfile path:                          
=====> listings builder-herokuish information
       Builder herokuish computed allowed: true                     
       Builder herokuish global allowed: true                     
       Builder herokuish allowed:                              
=====> listings builder-lambda information
       Builder lambda computed lambdayml path: lambda.yml               
       Builder lambda global lambdayml path: lambda.yml               
       Builder lambda lambdayml path:                          
=====> listings builder-pack information
       Builder pack computed projecttoml path: project.toml             
       Builder pack global projecttoml path: project.toml             
       Builder pack projecttoml path:                          
=====> listings buildpacks information
       Buildpacks computed stack:     gliderlabs/herokuish:latest-20
       Buildpacks global stack:       
       Buildpacks list:               
       Buildpacks stack:              
=====> listings caddy information
       Caddy image:                   lucaslorentz/caddy-docker-proxy:2.7
       Caddy letsencrypt email:                                
       Caddy letsencrypt server:      https://acme-v02.api.letsencrypt.org/directory
       Caddy log level:               ERROR                    
       Caddy polling interval:        5s                       
       Caddy tls internal:            false                    
=====> listings ssl information
       Ssl dir:                       /home/dokku/listings/tls 
       Ssl enabled:                   true                     
       Ssl hostnames:                 *.blog.xxx.com blog.xxx.com
       Ssl expires at:                Jun  1 07:05:17 2024 GMT 
       Ssl issuer:                    C = US, O = Let's Encrypt, CN = R3
       Ssl starts at:                 Mar  3 07:05:18 2024 GMT 
       Ssl subject:                   subject=CN = *.blog.xxx.com
       Ssl verified:                  verified by a certificate authority
=====> listings checks information
       Checks disabled list:          none                     
       Checks skipped list:           none                     
       Checks computed wait to retire: 60                       
       Checks global wait to retire:  60                       
       Checks wait to retire:                                  
=====> listings cron information
       Cron task count:               0
=====> listings docker options information
       Docker options build:                                   
       Docker options deploy:         --restart=on-failure:10 -v /var/lib/dokku/data/storage/listings:/storage 
       Docker options run:            -v /var/lib/dokku/data/storage/listings:/storage 
=====> listings domains information
       Domains app enabled:           true                     
       Domains app vhosts:            *.blog.xxx.com blog.xxx.com blog.myclient.dev
       Domains global enabled:        true                     
       Domains global vhosts:         listings.xxx.com      
=====> listings git information
       Git deploy branch:             main                     
       Git global deploy branch:      master                   
       Git keep git dir:              false                    
       Git rev env var:               GIT_REV                  
       Git sha:                                                
       Git source image:                                       
       Git last updated at:           1709447629               
=====> listings haproxy information
       Haproxy image:                 byjg/easy-haproxy:4.3.0  
       Haproxy letsencrypt email:                              
       Haproxy letsencrypt server:    https://acme-v02.api.letsencrypt.org/directory
       Haproxy log level:             ERROR                    
=====> listings letsencrypt information
       Letsencrypt active:            true                     
       Letsencrypt autorenew:         true                     
       Letsencrypt computed dns provider: cloudflare               
       Letsencrypt global dns provider: cloudflare               
       Letsencrypt dns provider:                               
       Letsencrypt computed email:    xxx@gmail.com         
       Letsencrypt global email:                               
       Letsencrypt email:             xxx@gmail.com         
       Letsencrypt expiration:        1717225517               
       Letsencrypt computed graceperiod: 2592000                  
       Letsencrypt global graceperiod:                          
       Letsencrypt graceperiod:                                
       Letsencrypt computed lego docker args:                          
       Letsencrypt global lego docker args:                          
       Letsencrypt lego docker args:                           
       Letsencrypt computed server:   https://acme-v02.api.letsencrypt.org/directory
       Letsencrypt global server:                              
       Letsencrypt server:                                     
=====> listings logs information
       Logs computed max size:        10m
       Logs global max size:          10m
       Logs global vector sink:       
       Logs max size:                 
       Logs vector sink:              
=====> listings network information
       Network attach post create:           
       Network attach post deploy:           
       Network bind all interfaces:          false
       Network computed attach post create:  
       Network computed attach post deploy:  
       Network computed bind all interfaces: false
       Network computed initial network:     
       Network computed tld:                 
       Network global attach post create:    
       Network global attach post deploy:    
       Network global bind all interfaces:   false
       Network global initial network:       
       Network global tld:                   
       Network initial network:              
       Network static web listener:          
       Network tld:                          
       Network web listeners:                172.17.0.2:5000
=====> listings nginx information
       Nginx access log format:                                
       Nginx access log path:         /var/log/nginx/listings-access.log
       Nginx bind address ipv4:                                
       Nginx bind address ipv6:       ::                       
       Nginx client max body size:    100m                     
       Nginx disable custom config:   false                    
       Nginx error log path:          /var/log/nginx/listings-error.log
       Nginx global hsts:             true                     
       Nginx computed hsts:           true                     
       Nginx hsts:                                             
       Nginx hsts include subdomains: true                     
       Nginx hsts max age:            15724800                 
       Nginx hsts preload:            false                    
       Nginx computed nginx conf sigil path: nginx.conf.sigil         
       Nginx global nginx conf sigil path: nginx.conf.sigil         
       Nginx nginx conf sigil path:                            
       Nginx proxy buffer size:       4096                     
       Nginx proxy buffering:         on                       
       Nginx proxy buffers:           8 4096                   
       Nginx proxy busy buffers size: 8192                     
       Nginx proxy read timeout:      60s                      
       Nginx last visited at:         1709565602               
       Nginx x forwarded for value:   $remote_addr             
       Nginx x forwarded port value:  $server_port             
       Nginx x forwarded proto value: $scheme                  
       Nginx x forwarded ssl:                                  
=====> listings proxy information
       Proxy enabled:                 true
       Proxy port map:                http:80:5000 https:443:5000
       Proxy type:                    nginx
=====> listings ps information
       Deployed:                      true
       Processes:                     1
       Ps can scale:                  true
       Ps computed procfile path:     Procfile
       Ps global procfile path:       Procfile
       Ps procfile path:              
       Ps restart policy:             on-failure:10
       Restore:                       true
       Running:                       true
       Status web 1:                  running (CID: c922c8c41ce)
=====> listings registry information
       Registry computed image repo:      dokku/listings
       Registry computed push on release: false
       Registry computed server:          
       Registry global push on release:   
       Registry global server:            
       Registry image repo:               
       Registry push on release:          
       Registry server:                   
       Registry tag version:              
=====> listings resource information
=====> listings scheduler information
       Scheduler computed selected:   docker-local
       Scheduler global selected:     docker-local
       Scheduler selected:            
=====> listings scheduler-docker-local information
       Scheduler docker local disable chown:                          
       Scheduler docker local init process: true                     
       Scheduler docker local parallel schedule count:                          
=====> listings storage information
       Storage build mounts:                                   
       Storage deploy mounts:         -v /var/lib/dokku/data/storage/listings:/storage 
       Storage run mounts:            -v /var/lib/dokku/data/storage/listings:/storage 
=====> listings traefik information
       Traefik api enabled:           false                    
       Traefik api vhost:             traefik.dokku.me         
       Traefik basic auth password:                            
       Traefik basic auth username:                            
       Traefik dashboard enabled:     false                    
       Traefik image:                 traefik:v2.8             
       Traefik letsencrypt email:                              
       Traefik letsencrypt server:    https://acme-v02.api.letsencrypt.org/directory
       Traefik log level:             ERROR                    
       Traefik priority:                        

How (deb/make) and where (AWS, VirtualBox, physical, etc.) was Dokku installed?:

Digital Ocean Droplet

josegonzalez commented 8 months ago

This isn't possible due to how the plugin works. If you set a dns provider, then goacme/lego (what we use under the hood) will use that to retrieve a cert for every requested domain. Dokku itself only uses 1 certificate per app when using the letsencrypt plugin + the default nginx router, so we wouldn't be able to accommodate different modes depending on whether the dns is possible to use for a given domain or not.

That said, Dokku's openresty plugin is probably more suited to what you want. It doesn't do dns-based certificate retrieval, but does just-in-time retrieval of certificates for any domain, meaning you don't have to run an extra command to get a cert.

If - for business reasons - you still want to use this app + a different certificate depending on the hostname being requested, consider sponsoring the work. I'm always happy to sit down with users to figure out how Dokku can better enable their workflows while improving the Dokku ecosystem.