I have a fairly complicated setup and a few "gotcha's" to note.
Notes: Updated for multi-site setup w/ script to call via CRON
Setup:
- Wordpress site w/ Apache & MariaDB setup to serve over port 8575 redirecting to 80 in the container (just one example site)
- NGinX does all my front end termination (listens on port 80 & 443)
- I wanted to run Certbot not in another container "stack" so to speak, but isolated
I "skipped" nginx when configuring webroot and directly mapped the webroot of my website ON THE HOST to the CertBot Container (see config)- I don't actually serve my "real" webapp webroot, just a folder that nginx directly serves purley for certbot, installed in the "default" webserver so no further configuration is required when setting up new websites (no more extra locations)
- I don't want certbot to start a webserver, just use nginx already configured, but may need to look into renewal/restart hacks once I get to 90days.
Gotchas:
- I had NGinX setup to serve over SSL already, but it won't start without certs existing, so I pointed it to other (incorrect) certs I had lying around to get it running
I could not get certificate validation via CertBot when serving "/.well-known" over https- I had to make a special "location" block in nginx for certbot
to allow http because I have an automatic redirect for the rest of my domain to https I had to add $request_uri to the special location block mentioned above or it didn't work- I tried having the "live" folder under "/opt/certbot/" where I store the container files and symlink to "/opt/nginx" but nginx didn't like the symlinks, so I set the working dir to directly "/opt/nginx/ssl/" where I already have mapped inside nginx to serve "ssl"
- Originally without the tag "–staging" i was quickly blocked during testing for going over the rate limit (5 failures/hour), use this tag until it works as expected!
ToDo:
Renewal Testing/Automation
Dir Structure:
:/opt/certbot# tree -a . ├── certbot_logs └── setup ├── certbot.sh ├── docker-compose.yaml ├── ENV #I just copy this to each dir when doing setup and rename .env ├── freesoftwareservers.com │ ├── docker-compose.yaml -> ../docker-compose.yaml │ └── .env └── ytit.ca ├── docker-compose.yaml -> ../docker-compose.yaml └── .env
Docker-Compose:
WD=/opt/certbot mkdir -p $WD/{setup,certbot_logs} cd $WD/setup cat << 'EOF' >docker-compose.yaml version: '3.7' services: certbot: container_name: certbot hostname: certbot image: certbot/certbot volumes: - type: bind source: /opt/certbot/certbot_logs target: /var/log/letsencrypt - type: bind source: /opt/nginx/ssl target: /etc/letsencrypt - type: bind source: /opt/nginx/html/acme target: /var/www/html/ environment: - 'TZ=${TZ}' command: certonly --webroot -w /var/www/html ${DOMAINS} --non-interactive --agree-tos --register-unsafely-without-email ${STAGING} EOF chmod +x docker-compose.yaml cd $WD/setup
Variables: (Note, "/opt/example/example_html" is configured as the webroot for apache/website" & just comment out "staging" when ready)
Haven't figured out yet how I would script this with multiple sites, cross that bridge when I get there. Possibly run certbot multiple times inside each website stack or perhaps with NGinX and just add multiple entries manually for each domain.
cat << 'EOF'>.env DOMAINS=-d example.com STAGING=--staging TZ=America/Whitehorse EOF chmod +x .env
NginX: (Note make sure to switch to correct SSL once it's working, then you should be able to auto-renew without issues)
server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html/; index index.html; } server { listen 443 default_server; listen [::]:443 default_server; ssl_certificate /etc/ssl/fake/fake.crt; ssl_certificate_key /etc/ssl/fake/fake.key; location /.well-known/acme-challenge/ { root /var/www/html/acme; allow all; } root /var/www/html/; index index.html; }
Bash Script:
#!/bin/bash STAGING=no if [ $STAGING = "yes" ]; then echo "STAGING = yes" declare -a arr=("freesoftwareservers.com" ) for i in "${arr[@]}" do docker rm certbot DOCKERCOMPOSE=/usr/bin/docker-compose PROJNAME=certbot PROJDIR=/opt/certbot/setup/"$i" $DOCKERCOMPOSE --project-name $PROJNAME --project-directory $PROJDIR -f $PROJDIR/docker-compose.yaml up done fi if [ $STAGING = "no" ]; then echo "STAGING = no" declare -a arr=("ytit.ca" "freesoftwareservers.com" ) for i in "${arr[@]}" do docker rm certbot DOCKERCOMPOSE=/usr/bin/docker-compose PROJNAME=certbot PROJDIR=/opt/certbot/setup/"$i" $DOCKERCOMPOSE --project-name $PROJNAME --project-directory $PROJDIR -f $PROJDIR/docker-compose.yaml up done fi
Cron:
0 4 * * * root /opt/certbot/setup/certbot.sh