Compare commits

...

62 Commits

Author SHA1 Message Date
7e70255067
Update dependency go to v1.24.2
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 4m42s
Test Pull Request / Notify (pull_request) Successful in 3s
Build Image / Validate Image (push) Successful in 2m46s
Build Image / Publish Image (push) Successful in 4m37s
Build Image / Notify (push) Successful in 2s
2025-04-09 05:00:12 +00:00
ef4cbce8d2
Update dependency apprise to v1.9.3
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 4m43s
Test Pull Request / Notify (pull_request) Successful in 2s
Build Image / Validate Image (push) Successful in 1m40s
Build Image / Publish Image (push) Successful in 4m7s
Build Image / Notify (push) Successful in 2s
2025-04-06 20:00:11 +00:00
db2dcbdf4b
Checkout repo before running build stage of validate image action (#49) [skip-ci]
Some checks failed
Build Image / Publish Image (push) Has been cancelled
Build Image / Notify (push) Has been cancelled
Build Image / Validate Image (push) Has been cancelled
Reviewed-on: #49
2025-03-22 08:56:22 +00:00
d765616d7c
Update certbot to v3.3.0
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 4m9s
Test Pull Request / Notify (pull_request) Successful in 4s
Build Image / Validate Image (push) Successful in 2m23s
Build Image / Publish Image (push) Successful in 4m24s
Build Image / Notify (push) Successful in 5s
2025-03-18 17:00:11 +00:00
23c2a2a07c
Update dependency go to v1.24.1
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 5m37s
Test Pull Request / Notify (pull_request) Successful in 3s
Build Image / Validate Image (push) Successful in 2m22s
Build Image / Publish Image (push) Successful in 4m0s
Build Image / Notify (push) Successful in 8s
2025-03-13 08:00:19 +00:00
47bc7c9657
Update alpine Docker tag to v3.21.3
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 38m8s
Test Pull Request / Notify (pull_request) Successful in 3s
Build Image / Validate Image (push) Successful in 2m38s
Build Image / Publish Image (push) Successful in 6m17s
Build Image / Notify (push) Successful in 3s
2025-02-21 20:00:10 +00:00
30d95c69cd
Update certbot to v3.2.0
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 4m18s
Test Pull Request / Notify (pull_request) Successful in 3s
Build Image / Publish Image (push) Has been skipped
Build Image / Notify (push) Has been skipped
Build Image / Validate Image (push) Successful in 1m40s
2025-02-18 22:00:12 +00:00
a09b5471bf
Update alpine Docker tag to v3.21.2
All checks were successful
Test Pull Request / Build Image (pull_request) Successful in 3m11s
Test Pull Request / Notify (pull_request) Successful in 3s
renovate/stability-days Updates have met minimum release age requirement
Build Image / Validate Image (push) Successful in 2m30s
Build Image / Publish Image (push) Successful in 3m42s
Build Image / Notify (push) Successful in 3s
Build Tagged Release Image / Build Image (push) Successful in 4m3s
Build Tagged Release Image / Create Release (push) Successful in 38s
Build Tagged Release Image / Notify (push) Successful in 2s
2025-01-15 13:00:11 +00:00
659f5c4054
Update dependency apprise to v1.9.2
Some checks are pending
renovate/stability-days Updates have not met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 5m21s
Test Pull Request / Notify (pull_request) Successful in 2s
Build Image / Validate Image (push) Successful in 2m28s
Build Image / Publish Image (push) Successful in 3m49s
Build Image / Notify (push) Successful in 2s
2025-01-15 12:00:14 +00:00
c52e0667eb
Fix formatting in Dockerfile (#43) [skip ci]
Reviewed-on: #43
2025-01-15 11:43:54 +00:00
b05b79fffb
Update certbot to v3 (major) (#42)
All checks were successful
Build Image / Validate Image (push) Successful in 2m35s
Build Image / Publish Image (push) Successful in 4m16s
Build Image / Notify (push) Successful in 3s
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [certbot](https://github.com/certbot/certbot) | major | `==2.11.0` -> `==3.1.0` |
| [certbot-dns-cloudflare](https://github.com/certbot/certbot) | major | `==2.11.0` -> `==3.1.0` |

---

### Release Notes

<details>
<summary>certbot/certbot (certbot)</summary>

### [`v3.1.0`](https://github.com/certbot/certbot/releases/tag/v3.1.0): Certbot 3.1.0

[Compare Source](https://github.com/certbot/certbot/compare/v3.0.1...v3.1.0)

##### Added

-

##### Changed

-   Python 3.8 support was removed.
-   certbot-dns-rfc2136's minimum required version of dnspython is now 2.6.1.
-   Updated our Docker images to be based on Alpine Linux 3.20.
-   Our runtime dependency on setuptools has been dropped from all Certbot
    components.
-   Certbot's packages no longer depend on library importlib_resources.

##### Fixed

-   Included an OpenSSL library that was missing in our Certbot snap fixing
    crashes affecting 32-bit ARM users.

More details about these changes can be found on our GitHub repo.

### [`v3.0.1`](https://github.com/certbot/certbot/releases/tag/v3.0.1): Certbot 3.0.1

[Compare Source](https://github.com/certbot/certbot/compare/v3.0.0...v3.0.1)

##### Fixed

-   Removed a CryptographyDeprecationWarning that was being displayed to users
    when checking OCSP status.

More details about these changes can be found on our GitHub repo.

### [`v3.0.0`](https://github.com/certbot/certbot/releases/tag/v3.0.0): Certbot 3.0.0

[Compare Source](https://github.com/certbot/certbot/compare/v2.11.0...v3.0.0)

##### Added

-

##### Changed

-   The update_symlinks command was removed.
-   The `csr_dir` and `key_dir` attributes on
    `certbot.configuration.NamespaceConfig` were removed.
-   The `--manual-public-ip-logging-ok` command line flag was removed.
-   The `--dns-route53-propagation-seconds` command line flag was removed.
-   The `certbot_dns_route53.authenticator` module has been removed. This should
    not affect any users of the plugin and instead would only affect developers
    trying to develop on top of the old code.
-   Support for Python 3.8 was deprecated and will be removed in our next planned
    release.

##### Fixed

-

More details about these changes can be found on our GitHub repo.

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS40Mi4xIiwidXBkYXRlZEluVmVyIjoiMzkuNDIuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119-->

Reviewed-on: #42
Co-authored-by: Renovate Bot <renovate@mrmeeb.stream>
Co-committed-by: Renovate Bot <renovate@mrmeeb.stream>
2025-01-15 11:06:00 +00:00
2ed23e1021
Update alpine Docker tag to v3.21.1
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 4m21s
Test Pull Request / Notify (pull_request) Successful in 4s
Build Image / Validate Image (push) Successful in 2m24s
Build Image / Publish Image (push) Successful in 4m57s
Build Image / Notify (push) Successful in 3s
2025-01-14 06:00:10 +00:00
4c2ddbfe98
Update dependency apprise to v1.9.1
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 4m26s
Test Pull Request / Notify (pull_request) Successful in 4s
Build Image / Validate Image (push) Successful in 2m41s
Build Image / Publish Image (push) Successful in 4m24s
Build Image / Notify (push) Successful in 3s
2024-12-25 02:00:10 +00:00
e73fca921f
Update alpine Docker tag to v3.21.0
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 4m2s
Test Pull Request / Notify (pull_request) Successful in 3s
Build Image / Validate Image (push) Successful in 1m58s
Build Image / Publish Image (push) Successful in 4m50s
Build Image / Notify (push) Successful in 4s
2024-12-13 02:00:12 +00:00
7935535c55
Update dependency just-containers/s6-overlay to v3.2.0.2
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 3m34s
Test Pull Request / Notify (pull_request) Successful in 3s
Build Image / Validate Image (push) Successful in 2m25s
Build Image / Publish Image (push) Successful in 4m3s
Build Image / Notify (push) Successful in 3s
2024-10-18 00:00:12 +00:00
f49865a3c8
Update dependency apprise to v1.9.0
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 3m27s
Test Pull Request / Notify (pull_request) Successful in 3s
Build Image / Validate Image (push) Successful in 1m44s
Build Image / Publish Image (push) Successful in 3m47s
Build Image / Notify (push) Successful in 2s
2024-09-14 19:00:11 +00:00
e3bb7aa9bb
Update alpine Docker tag to v3.20.3
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 5m28s
Test Pull Request / Notify (pull_request) Successful in 3s
Build Image / Validate Image (push) Successful in 2m35s
Build Image / Publish Image (push) Successful in 6m11s
Build Image / Notify (push) Successful in 5s
2024-09-13 23:01:11 +00:00
9e12fde518
Update dependency apprise to v1.8.1
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Test Pull Request / Build Image (pull_request) Successful in 4m46s
Test Pull Request / Notify (pull_request) Successful in 3s
Build Image / Validate Image (push) Successful in 1m38s
Build Image / Publish Image (push) Successful in 5m22s
Build Image / Notify (push) Successful in 3s
2024-08-03 20:00:11 +00:00
7e3360f187
Update alpine Docker tag to v3.20.2
All checks were successful
Test Pull Request / Build Image (pull_request) Successful in 4m48s
Test Pull Request / Notify (pull_request) Successful in 2s
Build Image / Validate Image (push) Successful in 2m3s
Build Image / Publish Image (push) Successful in 5m12s
Build Image / Notify (push) Successful in 2s
2024-07-22 22:00:12 +00:00
9b848e7edb
Delay Renovate from picking up new releases by 7 days (#31) [skip ci]
When Renovate acts too quickly, weirdness can occur, especially when more core packages like Alpine are updated - things haven't had time to propogate if we start updating less than an hour after the release. Waiting 7 days should give plenty of time for other maintainers to update their packages and for things to distribute.

Reviewed-on: #31
2024-06-22 15:37:03 +00:00
4ca8981d0c
Update alpine Docker tag to v3.20.1
All checks were successful
Test Pull Request / Build Image (pull_request) Successful in 4m49s
Test Pull Request / Notify (pull_request) Successful in 4s
Build Image / Validate Image (push) Successful in 2m27s
Build Image / Publish Image (push) Successful in 4m57s
Build Image / Notify (push) Successful in 3s
2024-06-20 19:00:12 +00:00
f6d067b561
Fix s6-overlay format error (#29)
All checks were successful
Build Image / Validate Image (push) Successful in 2m29s
Build Image / Publish Image (push) Successful in 4m58s
Build Image / Notify (push) Successful in 3s
Build Tagged Release Image / Build Image (push) Successful in 4m46s
Build Tagged Release Image / Create Release (push) Successful in 19s
Build Tagged Release Image / Notify (push) Successful in 2s
Add missing shebangs that cause `S6 warning: unable to spawn ./finish: Exec format error` when `ONESHOT=true`. Fixes #28

Also brings the method for killing a container via service exit inline with s6's documented method

Reviewed-on: #29
2024-06-15 15:55:18 +00:00
2962b45496
Update dependency just-containers/s6-overlay to v3.2.0.0
All checks were successful
Test Pull Request / Build Image (pull_request) Successful in 4m23s
Test Pull Request / Notify (pull_request) Successful in 4s
Build Image / Validate Image (push) Successful in 1m40s
Build Image / Publish Image (push) Successful in 4m58s
Build Image / Notify (push) Successful in 3s
2024-06-07 15:00:12 +00:00
535a33506b
Update certbot to v2.11.0
All checks were successful
Test Pull Request / Build Image (pull_request) Successful in 4m37s
Test Pull Request / Notify (pull_request) Successful in 3s
Build Image / Validate Image (push) Successful in 2m32s
Build Image / Publish Image (push) Successful in 4m53s
Build Image / Notify (push) Successful in 3s
2024-06-06 08:00:17 +00:00
c187e05fad Add logrotate (#25)
All checks were successful
Build Image / Validate Image (push) Successful in 36s
Build Tagged Release Image / Build Image (push) Successful in 5m14s
Build Image / Publish Image (push) Successful in 4m57s
Build Image / Notify (push) Successful in 2s
Build Tagged Release Image / Create Release (push) Successful in 52s
Build Tagged Release Image / Notify (push) Successful in 2s
Adds logrotate, running every day at 00:00.

Rotates `letsencrypt.log`, keeping 10 versions.
Rotates `renew.log` at 100 megabytes

Closes #10

Reviewed-on: #25
Co-authored-by: MrMeeb <mrmeeb@noreply.git.mrmeeb.stream>
Co-committed-by: MrMeeb <mrmeeb@noreply.git.mrmeeb.stream>
2024-06-04 17:52:46 +00:00
d4dd1c57c1 Add renewal notifications (#24)
Closes #9

Reviewed-on: #24
Co-authored-by: MrMeeb <mrmeeb@noreply.git.mrmeeb.stream>
Co-committed-by: MrMeeb <mrmeeb@noreply.git.mrmeeb.stream>
2024-06-04 17:52:26 +00:00
aa4bbc765d Move to Feature Branch Workflow [skip ci] (#23)
Change branch method for [Feature Branch](https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow) workflow. Gitflow workflow is overkill for my needs.

Reviewed-on: #23
Co-authored-by: MrMeeb <mrmeeb@noreply.git.mrmeeb.stream>
Co-committed-by: MrMeeb <mrmeeb@noreply.git.mrmeeb.stream>
2024-06-04 17:51:56 +00:00
b810f98831 Merge pull request 'Update alpine Docker tag to v3.20.0' (#19) from renovate/alpine-3.x into master
Reviewed-on: #19
2024-05-29 17:01:13 +00:00
b25bb57772 Add setuptools for certbot dependencies 2024-05-29 16:35:00 +00:00
9e06b48edb Update alpine Docker tag to v3.20.0 2024-05-27 22:46:33 +00:00
ef9cebf093 Revert c12eb0b381ba146398e8e7dc63c67e07b2fb4455 (#18)
Reviewed-on: #18
2024-05-27 22:30:03 +00:00
4983cfb5ef revert c12eb0b381ba146398e8e7dc63c67e07b2fb4455
revert Update alpine Docker tag to v3.20.0
2024-05-27 22:24:29 +00:00
3c2d85b994 Update certbot to v2.10.0 2024-05-27 22:12:33 +00:00
63c85278a9 Update alpine Docker tag to v3.20.0 2024-05-27 22:07:58 +00:00
ce992d4859 Fix incorrect reference to default branch (#17)
Reviewed-on: #17
2024-05-27 22:01:48 +00:00
f8d17978e3 Fix incorrect reference to default branch 2024-05-27 20:53:20 +00:00
08d4bf5d6d Update base renovate branch 2024-05-27 15:57:57 +00:00
b1ff81c726 Merge pull request 'Add automations and bump base versions' (#11) from develop into master
Reviewed-on: #11
2024-05-12 11:40:44 +00:00
76ee09a143 Correct build-main workflow 2024-05-12 11:33:34 +00:00
f83d27e411 Merge branch 'automation' into develop 2024-05-12 11:30:13 +00:00
93ed0281a1 Correct workflow dependency graph 2024-05-12 11:22:16 +00:00
ff6dcbccd1 Add gitea actions 2024-05-12 11:00:57 +00:00
a82028cde5 Remove Drone build badges 2024-05-12 10:58:19 +00:00
c213e9214c Add gitea actions 2024-05-12 10:57:43 +00:00
a259156875 Change release formatting 2024-05-12 09:25:01 +00:00
9906cf6c0a Update goreleaser syntax 2024-05-12 09:24:53 +00:00
8ba971571c Rebase to Alpine 3.19.1 2024-05-12 09:22:25 +00:00
ef7fff219d Update S6 to 3.1.6.2 2024-05-12 09:22:08 +00:00
15a0cb3a16 Version control for Certbot packages 2024-05-12 09:21:44 +00:00
6a2cca0af6 Enable Renovate 2024-05-12 09:21:23 +00:00
c678de2009 Update README.md [CI SKIP] 2024-01-13 17:30:08 +00:00
ec6623c839 Update README.md [CI SKIP] 2024-01-13 17:28:19 +00:00
1ea5213bb9 Merge pull request '1.1.2' (#7) from develop into master
Some checks reported errors
continuous-integration/drone/tag Build was killed
Reviewed-on: #7
2023-08-02 11:54:14 +00:00
c16e730a19 add ONE_SHOT so container exits after run 2023-07-17 17:49:02 +00:00
58ede5f1b6 fix build issues due to cython 3.0.0 release 2023-07-17 17:19:30 +00:00
def9460540 Merge pull request '1.1.1' (#6) from develop into master
Some checks reported errors
continuous-integration/drone/tag Build was killed
Reviewed-on: #6
2023-07-16 18:07:08 +00:00
3e37a8c4ed further small tweak to log formatting 2023-07-16 17:39:48 +00:00
3dbf0983f6 Merge pull request '1.1.0' (#5) from develop into master
Some checks failed
continuous-integration/drone/tag Build is failing
Reviewed-on: #5
2023-07-16 17:08:41 +00:00
8587dcc8c2 tweak log formatting 2023-07-16 16:45:36 +00:00
e69f607bf8 add multi-certificate support 2023-07-16 15:37:12 +00:00
f9aaaaa624 enable tracking of env vars between runs 2023-07-15 16:04:45 +00:00
3e3b548538 add standalone and webroot methods 2023-07-09 21:53:06 +00:00
22 changed files with 1299 additions and 275 deletions

View File

@ -1,176 +0,0 @@
kind: pipeline
type: docker
name: build-release-images
trigger:
event:
exclude:
- pull_request
ref:
- refs/tags/**
platform:
os: linux
arch: amd64
steps:
- name: get-tags
image: docker:git
commands:
- git fetch --tags
depends_on:
- clone
- name: make-tags
image: node
commands:
- echo -n "${DRONE_TAG}, latest" > .tags
depends_on:
- get-tags
- name: build-gitea
image: thegeeklab/drone-docker-buildx
privileged: true
settings:
provenance: false
registry: git.mrmeeb.stream
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: git.mrmeeb.stream/mrmeeb/certbot-cron
platforms:
- linux/arm64
- linux/amd64
depends_on:
- make-tags
- name: release-gitea
image: goreleaser/goreleaser
environment:
GITEA_TOKEN:
from_secret: gitea_token
commands:
- goreleaser release -f .goreleaser-gitea.yaml
depends_on:
- build-gitea
- name: notify
image: plugins/slack
when:
status:
- success
- failure
settings:
webhook:
from_secret: slack_webhook
depends_on:
- release-gitea
---
kind: pipeline
type: docker
name: build-main-images
trigger:
event:
exclude:
- pull_request
ref:
- refs/heads/master
platform:
os: linux
arch: amd64
steps:
- name: make-tags
image: node
commands:
- echo -n "${DRONE_COMMIT_SHA:0:8}, latest" > .tags
when:
ref:
- refs/heads/master
depends_on:
- clone
- name: build-gitea
image: thegeeklab/drone-docker-buildx
privileged: true
settings:
provenance: false
registry: git.mrmeeb.stream
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: git.mrmeeb.stream/mrmeeb/certbot-cron
platforms:
- linux/arm64
- linux/amd64
depends_on:
- make-tags
- name: notify
image: plugins/slack
when:
status:
- success
- failure
settings:
webhook:
from_secret: slack_webhook
depends_on:
- build-gitea
---
kind: pipeline
type: docker
name: build-develop-images
trigger:
event:
exclude:
- pull_request
branch:
- develop
platform:
os: linux
arch: amd64
steps:
# Set tags for develop branch - git commit SHA and 'develop'
- name: make-tags
image: node
commands:
- echo -n "develop-${DRONE_COMMIT_SHA:0:8}, develop" > .tags
# Build containers from develop branch
- name: build-gitea
image: thegeeklab/drone-docker-buildx
privileged: true
settings:
provenance: false
registry: git.mrmeeb.stream
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: git.mrmeeb.stream/mrmeeb/certbot-cron
platforms:
- linux/arm64
- linux/amd64
depends_on:
- make-tags
- name: notify
image: plugins/slack
when:
status:
- success
- failure
settings:
webhook:
from_secret: slack_webhook
depends_on:
- build-gitea

View File

@ -0,0 +1,91 @@
name: Build Image
on:
push:
branches:
- 'master'
env:
TEST_TAG: mrmeeb/certbot-cron:test
FULL_TAG: git.mrmeeb.stream/mrmeeb/certbot-cron:latest
jobs:
"Validate Image":
runs-on: [ubuntu-docker-latest, linux/amd64]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build locally
uses: docker/build-push-action@v5
with:
context: .
load: true
tags: ${{ env.TEST_TAG }}
provenance: false
- name: Test certificate issuing
id: test
run: |
# First create a volume
docker volume create ${{ gitea.sha }} && \
# Then issue a certificate
docker run --rm -v ${{ gitea.sha }}:/config -e STAGING=true -e EMAIL=${{ secrets.EMAIL }} -e DOMAINS=${{ gitea.sha }}.mrmeeb.stream -e PLUGIN=cloudflare -e CLOUDFLARE_TOKEN=${{ secrets.CLOUDFLARE_TOKEN }} -e ONE_SHOT=true -e GENERATE_DHPARAM=false ${{ env.TEST_TAG }} && \
# Then revoke it again
docker run --rm --entrypoint "/usr/bin/certbot" -v ${{ gitea.sha }}:/config ${{ env.TEST_TAG }} revoke --non-interactive --agree-tos --email ${{ secrets.EMAIL }} --staging --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --cert-path /config/letsencrypt/live/${{ gitea.sha }}.mrmeeb.stream/fullchain.pem
- name: Tidy up
if: always()
run: |
echo "Removing docker volume ${{ gitea.sha }}" && \
docker volume rm ${{ gitea.sha }}
- name: Test Failure
uses: rjstone/discord-webhook-notify@v1
if: failure()
with:
severity: error
details: Test Failed!
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
username: Gitea
avatarUrl: ${{ vars.RUNNER_ICON_URL }}
"Publish Image":
runs-on: [ubuntu-docker-latest, linux/amd64]
needs: ["Validate Image"]
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Gitea Container Registry
uses: docker/login-action@v3
with:
registry: git.mrmeeb.stream
username: ${{ env.GITHUB_ACTOR }}
password: ${{ secrets.GTCR_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ env.FULL_TAG }}
provenance: false
- name: Build Failure
uses: rjstone/discord-webhook-notify@v1
if: failure()
with:
severity: error
details: Build Failed!
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
username: Gitea
avatarUrl: ${{ vars.RUNNER_ICON_URL }}
"Notify":
runs-on: [ubuntu-docker-latest, linux/amd64]
needs: ["Validate Image", "Publish Image"]
steps:
- name: Notify of success
uses: rjstone/discord-webhook-notify@v1
if: success()
with:
severity: info
details: Build succeeded!
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
username: Gitea
avatarUrl: ${{ vars.RUNNER_ICON_URL }}

View File

@ -0,0 +1,80 @@
name: Build Tagged Release Image
on:
push:
tags:
- '*'
env:
FULL_TAG: git.mrmeeb.stream/mrmeeb/certbot-cron
jobs:
"Build Image":
runs-on: [ubuntu-docker-latest, linux/amd64]
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Gitea Container Registry
uses: docker/login-action@v3
with:
registry: git.mrmeeb.stream
username: ${{ env.GITHUB_ACTOR }}
password: ${{ secrets.GTCR_TOKEN }}
- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_TAG }}
tags: |
type=pep440,pattern={{version}}
- name: Build and push
uses: docker/build-push-action@v5
with:
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
provenance: false
- name: Notify on failure
uses: rjstone/discord-webhook-notify@v1
if: failure()
with:
severity: error
details: Build failed!
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
username: Gitea
avatarUrl: ${{ vars.RUNNER_ICON_URL }}
"Create Release":
runs-on: ubuntu-latest
needs: ["Build Image"]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.24.2
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser
version: latest
args: release --clean -f .goreleaser-gitea.yaml
env:
GITEA_TOKEN: ${{ secrets.GORELEASER_TOKEN }}
"Notify":
runs-on: [ubuntu-docker-latest, linux/amd64]
needs: ["Build Image", "Create Release"]
steps:
- name: Notify of success
uses: rjstone/discord-webhook-notify@v1
if: success()
with:
severity: info
details: Build succeeded!
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
username: Gitea
avatarUrl: ${{ vars.RUNNER_ICON_URL }}

View File

@ -0,0 +1,47 @@
name: Test Pull Request
on:
pull_request:
branches:
- 'master'
- 'develop'
env:
FULL_TAG: git.mrmeeb.stream/mrmeeb/certbot-cron:develop
jobs:
"Build Image":
runs-on: [ubuntu-docker-latest, linux/amd64]
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build
uses: docker/build-push-action@v5
with:
push: false
platforms: linux/amd64,linux/arm64
tags: ${{ env.FULL_TAG }}
provenance: false
- name: Notify on failure
uses: rjstone/discord-webhook-notify@v1
if: failure()
with:
severity: error
details: Build failed!
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
username: Gitea
avatarUrl: ${{ vars.RUNNER_ICON_URL }}
"Notify":
runs-on: [ubuntu-docker-latest, linux/amd64]
needs: ["Build Image"]
steps:
- name: Notify of success
uses: rjstone/discord-webhook-notify@v1
if: success()
with:
severity: info
details: Build succeeded!
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
username: Gitea
avatarUrl: ${{ vars.RUNNER_ICON_URL }}

View File

@ -1,14 +1,21 @@
dist: dist-gitea dist: dist-gitea
build: builds:
skip: true - skip: true
archives: archives:
- format: binary - format: binary
release: release:
draft: true draft: true
header: |
# Certbot Cron v{{ .Tag }}
## Docker Image:
`git.mrmeeb.stream/mrmeeb/certbot-cron:{{ .Tag }}`
gitea: gitea:
owner: MrMeeb owner: MrMeeb
name: certbot-cron-docker name: certbot-cron-docker

View File

@ -1,4 +1,4 @@
FROM alpine:latest as base FROM alpine:3.21.3 AS base
ARG TARGETARCH ARG TARGETARCH
FROM base AS base-amd64 FROM base AS base-amd64
@ -9,21 +9,38 @@ ENV S6_OVERLAY_ARCH=aarch64
FROM base-${TARGETARCH}${TARGETVARIANT} FROM base-${TARGETARCH}${TARGETVARIANT}
ARG S6_OVERLAY_VERSION=3.1.5.0 ARG S6_OVERLAY_VERSION="3.2.0.2"
ENV DOMAINS= # Core variables
ENV EMAIL=
ENV INTERVAL="0 */6 * * *"
ENV STAGING=false
ENV PROPOGATION_TIME=10
ENV GENERATE_DHPARAM=true
ENV TZ=UTC
ENV PUID=1000 ENV PUID=1000
ENV PGID=1000 ENV PGID=1000
ENV TZ=UTC
ENV GENERATE_DHPARAM=true
ENV INTERVAL="0 */6 * * *"
ENV ONE_SHOT=false
ENV APPRISE_URL=
ENV NOTIFY_ON_FAILURE=false
ENV NOTIFY_ON_SUCCESS=false
# Single domain
ENV DOMAINS=
ENV EMAIL=
ENV STAGING=false
# Custom CA support
ENV CUSTOM_CA=
ENV CUSTOM_CA_SERVER=
# Different plugin support (to support Cloudflare but also normal mode)
ENV PLUGIN=standalone
ENV PROPOGATION_TIME=10
ENV CLOUDFLARE_TOKEN= ENV CLOUDFLARE_TOKEN=
## Multi-cert support
ENV CERT_COUNT=1
#Get required packages #Get required packages
RUN apk update && apk add curl bash python3 py3-virtualenv procps tzdata nano shadow xz busybox-suid openssl RUN apk update && apk add curl bash python3 py3-virtualenv procps tzdata nano shadow xz busybox-suid openssl logrotate
#Make folders #Make folders
RUN mkdir /config && \ RUN mkdir /config && \
@ -42,16 +59,19 @@ ENV S6_BEHAVIOUR_IF_STAGE2_FAILS=2 S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 S6_VERBOSI
RUN python3 -m venv /app/certbot/ && /app/certbot/bin/pip install --upgrade pip RUN python3 -m venv /app/certbot/ && /app/certbot/bin/pip install --upgrade pip
#Get required packages for building, build, then cleanup #Get required packages for building, build, then cleanup
#Added additional pip steps to fix cython 3.0.0 issue - https://github.com/yaml/pyyaml/issues/601
COPY requirements.txt /app/certbot/requirements.txt
RUN apk add --no-cache --virtual .deps gcc python3-dev libc-dev libffi-dev && \ RUN apk add --no-cache --virtual .deps gcc python3-dev libc-dev libffi-dev && \
/app/certbot/bin/pip install certbot certbot-dns-cloudflare && \ /app/certbot/bin/pip install wheel setuptools && \
ln -s /app/certbot/bin/certbot /usr/bin/certbot &&\ /app/certbot/bin/pip install "Cython<3.0" pyyaml --no-build-isolation && \
/app/certbot/bin/pip install -r /app/certbot/requirements.txt && \
ln -s /app/certbot/bin/certbot /usr/bin/certbot && \
ln -s /app/certbot/bin/apprise /usr/bin/apprise && \
apk del .deps apk del .deps
COPY root / COPY root /
RUN chmod +x /container-init.sh && \ RUN chmod +x /container-init.sh /certbot-prepare.sh /check-one-shot.sh /renew-function.sh && \
chmod +x /certbot-prepare.sh && \
chmod +x /certbot-renew.sh && \
chown -R ${PUID}:${PGID} /app /config chown -R ${PUID}:${PGID} /app /config
ENTRYPOINT [ "/init" ] ENTRYPOINT [ "/init" ]

159
README.md
View File

@ -1,30 +1,28 @@
# Certbot Cron Docker # Certbot Cron Docker
![Drone (self-hosted) with branch](https://img.shields.io/drone/build/MrMeeb/certbot-cron-docker/master?label=latest&server=https%3A%2F%2Fdrone.mrmeeb.stream&style=for-the-badge) ![Drone (self-hosted) with branch](https://img.shields.io/drone/build/MrMeeb/certbot-cron-docker/develop?label=develop&server=https%3A%2F%2Fdrone.mrmeeb.stream&style=for-the-badge) Dockerised Certbot that utilises cron to schedule creating and renewing SSL certificates. Supports standalone, webroot or Cloudflare methods. Automatic renewal attempt happens every 6 hours by default.
Dockerised Certbot that utilises cron to schedule creating and renewing SSL certificates. Uses Cloudflare for DNS-01 verification. Automatic renewal attempt happens every 6 hours by default.
## Tags ## Tags
|Tag |Description| I use the [Feature Branch](https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow) workflow. The `latest` tag contains all of the latest changes that have been merged from individual feature branches. Feature branches are squashed into `master`.
|-------|-----------|
|latest |Latest image built from the main branch. Usually coincides with a tagged release.| Pinned releases are created by creating a tag off `master` to capture the repo in a particular state. They are recommended for stability.
|develop|Latest image built from the develop branch. Commits are made to the develop branch before being merged to main. Old versions of `develop` are removed after 14 days.|
## Running ## Running
### Docker CLI ### Docker CLI
``` ```bash
docker run -d --name certbot \ docker run -d --name certbot \
-e EMAIL=admin@domain.com \ -e EMAIL=admin@domain.com \
-e DOMAINS=domain.com \ -e DOMAINS=domain.com \
-e PLUGIN=cloudflare \
-e CLOUDFLARE_TOKEN=123abc -e CLOUDFLARE_TOKEN=123abc
-v /docker/certbot-cron:/config \ -v ./certbot-cron:/config \
git.mrmeeb.stream/mrmeeb/certbot-cron:latest git.mrmeeb.stream/mrmeeb/certbot-cron:latest
``` ```
### Docker Compose ### Docker Compose
``` ```yaml
version: "3" version: "3"
services: services:
certbot: certbot:
@ -36,30 +34,157 @@ services:
environment: environment:
- EMAIL=admin@domain.com - EMAIL=admin@domain.com
- DOMAINS=domain.com,*.domain.com - DOMAINS=domain.com,*.domain.com
- PLUGIN=cloudflare
- CLOUDFLARE_TOKEN=123abc - CLOUDFLARE_TOKEN=123abc
``` ```
## Environment Variables: ## Environment Variables:
| Variable | Default Value | Description | ### Core Options:
Core options to the container
| Variable | Default | Description |
| --- | --- | --- | | --- | --- | --- |
|PUID |int |1000 |Sets the UID of the user certbot runs under | |PUID |int |1000 |Sets the UID of the user certbot runs under |
|PGID |int |1000 |Sets the GID of the user certbot runs under | |PGID |int |1000 |Sets the GID of the user certbot runs under |
|TZ |[List of valid TZs](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List) |UTC |Sets the timezone of the container | |TZ |[List of valid TZs](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List) |UTC |Sets the timezone of the container |
| ONE_SHOT | false | Whether container exits after first run of certbot, or starts cron-based auto-renewal |
| GENERATE_DHPARAM | true (case-sensitive) | Generate Diffie-Hellman keys in /config/letsencrypt/keys |
| INTERVAL | 0 */6 * * * | How often certbot attempts to renew the certificate. Cron syntax |
| CERT_COUNT | 1 | How many certificates certbot will try to issue. [Details here](https://git.mrmeeb.stream/MrMeeb/certbot-cron-docker#multiple-certificates) |
| APPRISE_URL | None | URL for Apprise notifications. [Syntax](https://github.com/caronc/apprise?tab=readme-ov-file#supported-notifications)
| NOTIFY_ON_SUCCESS | false | Notify on a successful renewal attempt. Note that this isn't just when the cert is renewed, but on every renewal attempt. |
| NOTIFY_ON_FAILURE | false | Notify on a failed renewal attempt.
### Certificate Options
These options apply when `CERT_COUNT` is `1`
| Variable | Default | Description |
| --- | --- | --- |
| EMAIL | None | Email address for renewal information & other communications | | EMAIL | None | Email address for renewal information & other communications |
| DOMAINS | None | Domains to be included in the certificate. Comma separated list, no spaces. Wildcards supported | | DOMAINS | None | Domains to be included in the certificate. Comma separated list, no spaces. Wildcards supported |
| INTERVAL | 0 */6 * * * | How often certbot attempts to renew the certificate. Cron syntax | | STAGING | false (case-sensitive) | Uses the LetsEncrypt staging endpoint for testing - avoids the aggressive rate-limiting of the production endpoint. **Not supported when using a custom Certificate Authority.** |
| STAGING | false (case-sensitive) | Uses the LetsEncrypt staging endpoint for testing - avoids the aggressive rate-limiting of the production endpoint |
### Plugins
Plugins that can used for issuing a certificate
| Variable | Default | Description |
| --- | --- | --- |
| PLUGIN | standalone | Options are `webroot`, `standalone`, or `cloudflare` |
- `webroot` - relies on a webserver running on the FQDN for which you're trying to issue a certificate to serve validation files
- Requires the webserver's root directory to be mounted to the container as `/config/webroot`
- `standalone` - certbot spawns a webserver on port 80 for validation
- Requires this container to be bound to port 80 on the host
- `cloudflare` - Creates a TXT record with Cloudflare pointing to the domain you're requesting a certificate for
- Requires the domain you're requesting a certificate for to be entered in Cloudflare
#### Cloudflare Plugin
Options that affect the behaviour of certbot running with the Cloudflare plugin
| Variable | Default | Description |
| --- | --- | --- |
| PROPOGATION_TIME | 10 | The amount of time (seconds) that certbot waits for the TXT records to propogate to Cloudflare before verifying - the more domains in the certificate, the longer you might need | | PROPOGATION_TIME | 10 | The amount of time (seconds) that certbot waits for the TXT records to propogate to Cloudflare before verifying - the more domains in the certificate, the longer you might need |
| GENERATE_DHPARAM | true (case-sensitive) | Generate Diffie-Hellman keys in /config/letsencrypt/keys | | CLOUDFLARE_TOKEN | null | Cloudflare token for verification |
| CLOUDFLARE_TOKEN | N/A | Cloudflare token for verification |
### Custom Certificate Authority
Options to use a custom Certificate Authority, for example when issuing internal certificates
| Variable | Default | Description |
| --- | --- | --- |
| CUSTOM_CA | null | Name of the root certificate Certbot/ACME will trust requesting the certificate, e.g `root.pem`. **Must be placed in `/config/custom_ca`** |
| CUSTOM_CA_SERVER | null | Custom server URL used by Certbot/ACME when requesting a certificate, e.g `https://ca.internal/acme/acme/directory` |
### Multiple Certificates
This container can issue multiple certificates each containing different domains. This could be used to issue a certificate for a public domain on Cloudflare, but then also for a local certificate from an internal Certificate Authority, for example. Another example would be you have a web-server hosting two separate websites and you want them to have dedicated SSL certificates instead of sharing one.
When issuing multiple certificates, first `CERT_COUNT` must be set to a value greater than 1.
#### Global Environment Variables
Some environment variables can be set globally, where they apply to all certificates (unless otherwise specifically specified). The following can be used globally:
| Variable | DESCRIPTION |
| --- | --- |
|EMAIL| Email address for renewal information & other communications |
|STAGING| Uses the LetsEncrypt staging endpoint for testing - avoids the aggressive rate-limiting of the production endpoint. **Not supported when using a custom Certificate Authority.** |
|CUSTOM_CA| Name of the root certificate Certbot/ACME will trust requesting the certificate, e.g `root.pem`. **Must be placed in `/config/custom_ca`** |
|CUSTOM_CA_SERVER| Custom server URL used by Certbot/ACME when requesting a certificate, e.g `https://ca.internal/acme/acme/directory` |
|PLUGIN| Options are `webroot`, `standalone`, or `cloudflare` |
|PROPOGATION_TIME| **(Applies to Cloudflare plugin)** The amount of time (seconds) that certbot waits for the TXT records to propogate to Cloudflare before verifying - the more domains in the certificate, the longer you might need |
More detail on these environment variables may be found further up.
#### Certificate-specific Environment Variables
Any variable other than those described as **Core Options** can be set per-certificate in a multi-certificate environment. The syntax is `${VARIABLE_NAME}_${CERT_NUMBER}`. The only certificate-specific option that **must** be set is the `DOMAINS` option.
##### Multi-certificate container using global variables:
```yaml
certbot:
container_name: certbot
image: git.mrmeeb.stream/mrmeeb/certbot-cron
volumes:
- /docker/certbot-cron:/config
- /docker/nginx/www:/config/webroot
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/London
- GENERATE_DHPARAM=false
- CERT_COUNT=2
- EMAIL=admin@domain.com
- CUSTOM_CA=root.pem
- CUSTOM_CA_SERVER=https://ca.internal/acme/acme/directory
- PLUGIN=webroot
- STAGING=false
- DOMAINS_1=website1.com
- DOMAINS_2=website2.com
```
##### Multi-certificate container using different options for each certificate:
```yaml
certbot:
container_name: certbot
image: git.mrmeeb.stream/mrmeeb/certbot-cron
volumes:
- /docker/certbot-cron:/config
- /docker/nginx/www:/config/webroot
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/London
- GENERATE_DHPARAM=false
- CERT_COUNT=2
- EMAIL=admin@domain.com
- DOMAINS_1=website1.com
- CUSTOM_CA_1=root.pem
- CUSTOM_CA_SERVER_1=https://ca.internal/acme/acme/directory
- PLUGIN_1=webroot
- STAGING_1=false
- DOMAINS_2=website2.com
- PLUGIN_2=cloudflare
- CLOUDFLARE_TOKEN_2=abc123
- PROPOGATION_TIME_2=30
- STAGING_2=true
```
## Volumes ## Volumes
| Docker path | Purpose | | Docker path | Purpose |
| --- | --- | | --- | --- |
| /config | Stores configs and LetsEncrypt output for mounting in other containers | /config | Stores configs and LetsEncrypt output for mounting in other containers
| /config/webroot | Mountpoint for the webroot of a separate webserver. **Required if `PLUGIN=webroot` is set**
## Other ## Ports
Thanks to [this guy](https://stackoverflow.com/questions/63447441/docker-stop-for-crond-times-out) for explaining how to make cron actually shutdown when stopping the container. | Port | Purpose |
| --- | --- |
| 80 | Used by ACME to verify domain ownership. **Required if `PLUGIN=standalone` is set**

29
renovate.json Normal file
View File

@ -0,0 +1,29 @@
{
"extends": [":automergeMinor", ":automergePr", ":automergeRequireAllStatusChecks", ":dependencyDashboard", ":disableRateLimiting", ":rebaseStalePrs"],
"baseBranches": ["master"],
"major": {
"dependencyDashboardApproval": true
},
"minimumReleaseAge": "7 days",
"customManagers": [
{
"customType": "regex",
"fileMatch": ["Dockerfile"],
"matchStrings": ["ARG S6_OVERLAY_VERSION=[\"](?<currentValue>.*)[\"]"],
"datasourceTemplate": "github-releases",
"depNameTemplate": "just-containers/s6-overlay"
}
],
"packageRules": [
{
"matchDatasources": ["github-releases"],
"matchDepNames": ["just-containers/s6-overlay"],
"extractVersion": "^v(?<version>.*)$",
"versioning": "loose"
},
{
"matchPackagePatterns": ["certbot"],
"groupName": "certbot"
}
]
}

5
requirements.txt Normal file
View File

@ -0,0 +1,5 @@
# For pinning Python packages to then be parsed by Renovate
certbot ==3.3.0
certbot-dns-cloudflare ==3.3.0
apprise ==1.9.3

View File

@ -1,7 +1,10 @@
#!/command/with-contenv bash #!/command/with-contenv bash
# shellcheck shell=bash # shellcheck shell=bash
#Creating needed folders and files if they don't already exist # Halt container if anything returns a non-zero exit code
set -e
# Creating needed folders and files if they don't already exist
if [ ! -d /config/.secrets ] if [ ! -d /config/.secrets ]
then then
mkdir /config/.secrets mkdir /config/.secrets
@ -32,54 +35,763 @@ then
touch /config/.crontab.txt touch /config/.crontab.txt
fi fi
if [ ! -f /config/.secrets/cloudflare.ini ] function better_exit {
then
touch /config/.secrets/cloudflare.ini
fi
if [ -n "$CLOUDFLARE_TOKEN" ] echo ""
then echo ""
echo "Cloudflare token is present" echo ""
echo "You can ignore the below error messages - they happened because the container exited with a non-0 exit code due misconfiguration"
echo "=========================================================="
exit 1
echo "dns_cloudflare_api_token = $CLOUDFLARE_TOKEN" > /config/.secrets/cloudflare.ini }
# Check APPRISE_URL is set if either NOTIFY_ON_SUCCESS or NOTIFY_ON_FAILURE are set
if [ "${NOTIFY_ON_SUCCESS}" = "true" ] || [ "${NOTIFY_ON_FAILURE}" = "true" ] && [ -z "${APPRISE_URL}" ]; then
echo "You have notifications enabled but have not set APPRISE_URL. Please set APPRISE_URL and restart the container."
better_exit
fi fi
if [ ! -s /config/.secrets/cloudflare.ini ] # Cleanup renew list and create it fresh, ready for commands to be run and added
then echo "#!/command/with-contenv bash
echo "cloudflare.ini is empty - please add your Cloudflare credentials or API key before continuing. This can be done as an ENV var, or by editing the file directly"
exit 22 date
echo \"Attempting to renew certificates\"
source /renew-function.sh
" > /config/.renew-list.sh
chmod +x /config/.renew-list.sh
# Create original config file to track changes to environmental variables
if [ ! -f /config/.donoteditthisfile ]
then
echo -e "ORIGDOMAINS=\"${DOMAINS}\" ORIGEMAIL=\"${EMAIL}\" ORIGSTAGING=\"${STAGING}\" ORIGCUSTOM_CA=\"${CUSTOM_CA}\" ORIGCUSTOM_CA_SERVER=\"${CUSTOM_CA_SERVER}\" ORIGPLUGIN=\"${PLUGIN}\" ORIGPROPOGATION_TIME=\"${PROPOGATION_TIME}\" ORIGCERT_COUNT=${CERT_COUNT}" > /config/.donoteditthisfile
fi fi
#Securing cloudflare.ini to supress warnings # Load original config file
chmod 600 /config/.secrets/cloudflare.ini . /config/.donoteditthisfile
echo "Creating certificates, or attempting to renew if they already exist" # Revoke all certs if CERT_COUNT has decreased, starting fresh
if [ "${CERT_COUNT}" -lt "${ORIGCERT_COUNT}" ]; then
if [[ $STAGING = true ]] echo ""
echo "CERT_COUNT has decreased - revoking all certificates then reissuing to cleanup any lingerers."
# Use .donoteditthisfile_cert_* to get details of each issued certificate to revoke with correct parameters
x=1
while [ $x -le ${ORIGCERT_COUNT} ]; do
# Load config of particular cert
. /config/.donoteditthisfile_cert_${x}
# Setting up variables (requires two passes to clean away requirement for indirect variables)
## Pass 1
DOMAINS_P1=ORIGDOMAINS_${x}
EMAIL_P1=ORIGEMAIL_${x}
STAGING_P1=ORIGSTAGING_${x}
CUSTOM_CA_P1=ORIGCUSTOM_CA_${x}
CUSTOM_CA_SERVER_P1=ORIGCUSTOM_CA_SERVER_${x}
PLUGIN_P1=ORIGPLUGIN_${x}
PROPOGATION_TIME_P1=ORIGPROPOGATION_TIME_${x}
CLOUDFLARE_TOKEN_P1=ORIGCLOUDFLARE_TOKEN_${x}
## Pass 2
DOMAINS_MULTI=${!DOMAINS_P1}
EMAIL_MULTI=${!EMAIL_P1}
STAGING_MULTI=${!STAGING_P1}
CUSTOM_CA_MULTI=${!CUSTOM_CA_P1}
CUSTOM_CA_SERVER_MULTI=${!CUSTOM_CA_SERVER_P1}
PLUGIN_MULTI=${!PLUGIN_P1}
PROPOGATION_TIME_MULTI=${!PROPOGATION_TIME_P1}
CLOUDFLARE_TOKEN_MULTI=${!CLOUDFLARE_TOKEN_P1}
FIRST_DOMAIN_MULTI=$(echo ${DOMAINS_MULTI} | cut -d \, -f1)
echo ${FIRST_DOMAIN_MULTI}
if [ ! -z ${CUSTOM_CA_MULTI} ]
then
echo "A custom CA was used for issuing certificate ${x}. Using it to revoke as well."
if [ ! -d /config/custom_ca ]
then
mkdir /config/custom_ca
echo "Please place the custom CA root file used to generate the current certificate ${x} into /config/custom_ca and restart the container"
better_exit
fi
if [ -z "$(ls -A /config/custom_ca)" ]
then
echo "A root certificate called ${CUSTOM_CA_MULTI} was used to generate a certificate, but the /config/custom_ca dir is now empty. Please place this root certificate back this directory and restart the container so it can be safely revoked"
better_exit
fi
CUSTOM_CA_PATH_MULTI=/config/custom_ca/${CUSTOM_CA_MULTI}
CUSTOM_CA_SERVER_OPT_MULTI="--server ${CUSTOM_CA_SERVER_MULTI}"
fi
if [ $STAGING_MULTI = "true" ]
then
# Reusing the CUSTOM_CA_SERVER_OPT variable to add staging option if that was selected
CUSTOM_CA_SERVER_OPT_MULTI="--server https://acme-staging-v02.api.letsencrypt.org/directory"
fi
if [ -f /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}"/fullchain.pem ]
then
REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH_MULTI certbot revoke --non-interactive --agree-tos --email $EMAIL_MULTI --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --cert-path /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}"/fullchain.pem ${CUSTOM_CA_SERVER_OPT_MULTI} || true
rm -rf /config/letsencrypt/archive/"${FIRST_DOMAIN_MULTI}"
rm -rf /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}"
rm -rf /config/letsencrypt/renewal/"${FIRST_DOMAIN_MULTI}".conf
fi
# Delete .donoteditthisfile_cert_${x}
rm -rf /config/.donoteditthisfile_cert_${x}
# Scrubbing variables before running next cert revoke to prevent overlap of values
DOMAINS_MULTI=
EMAIL_MULTI=
STAGING_MULTI=
CUSTOM_CA_MULTI=
CUSTOM_CA_SERVER_MULTI=
PLUGIN_MULTI=
PROPOGATION_TIME_MULTI=
CLOUDFLARE_TOKEN_MULTI=
CUSTOM_CA_PATH_MULTI=
CUSTOM_CA_SERVER_OPT_MULTI=
x=$(( $x + 1 ))
done
echo "Tidying up any potential lingering ACME challenges in /config/webroot from failed webroot activations"
rm -rf /config/webroot/.well-known/acme-challenge
fi
function single_domain {
# Checking for changes to config file, revoke certs if necessary
if [ ! "${DOMAINS}" = "${ORIGDOMAINS}" ] ||
[ ! "${EMAIL}" = "${ORIGEMAIL}" ] ||
[ ! "${STAGING}" = "${ORIGSTAGING}" ] ||
[ ! "${CUSTOM_CA}" = "${ORIGCUSTOM_CA}" ] ||
[ ! "${CUSTOM_CA_SERVER}" = "${ORIGCUSTOM_CA_SERVER}" ] ||
[ ! "${PLUGIN}" = "${ORIGPLUGIN}" ] ||
[ ! "${PROPOGATION_TIME}" = "${ORIGPROPOGATION_TIME}" ]
then
echo ""
echo "Configuration has changed since the last certificate was issued. Revoking and regenerating certs"
FIRST_DOMAIN=$(echo $ORIGDOMAINS | cut -d \, -f1)
if [ ! -z $ORIGCUSTOM_CA ]
then
echo "A custom CA was used for issuing. Using it to revoke as well."
if [ ! -d /config/custom_ca ]
then
mkdir /config/custom_ca
echo "Please place the custom CA root file used to generate the current certificate into /config/custom_ca and restart the container"
better_exit
fi
if [ -z "$(ls -A /config/custom_ca)" ]
then
echo "A root certificate called ${ORIGCUSTOM_CA} was used to generate a certificate, but the /config/custom_ca dir is now empty. Please place this root certificate back this directory and restart the container so it can be safely revoked"
better_exit
fi
ORIGCUSTOM_CA_PATH=/config/custom_ca/$ORIGCUSTOM_CA
ORIGCUSTOM_CA_SERVER_OPT="--server $ORIGCUSTOM_CA_SERVER"
fi
if [ $ORIGSTAGING = "true" ]
then
# Reusing the CUSTOM_CA_SERVER_OPT variable to add staging option if that was selected
ORIGCUSTOM_CA_SERVER_OPT="--server https://acme-staging-v02.api.letsencrypt.org/directory"
fi
if [ -f /config/letsencrypt/live/"${FIRST_DOMAIN}"/fullchain.pem ]
then
REQUESTS_CA_BUNDLE=$ORIGCUSTOM_CA_PATH certbot revoke --non-interactive --agree-tos --email $ORIGEMAIL --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --cert-path /config/letsencrypt/live/"${FIRST_DOMAIN}"/fullchain.pem $ORIGCUSTOM_CA_SERVER_OPT || true
rm -rf /config/letsencrypt/archive/"${FIRST_DOMAIN}"
rm -rf /config/letsencrypt/live/"${FIRST_DOMAIN}"
rm -rf /config/letsencrypt/renewal/"${FIRST_DOMAIN}".conf
fi
fi
# Update config file with new env vars
echo -e "ORIGDOMAINS=\"${DOMAINS}\" ORIGEMAIL=\"${EMAIL}\" ORIGSTAGING=\"${STAGING}\" ORIGCUSTOM_CA=\"${CUSTOM_CA}\" ORIGCUSTOM_CA_SERVER=\"${CUSTOM_CA_SERVER}\" ORIGPLUGIN=\"${PLUGIN}\" ORIGPROPOGATION_TIME=\"${PROPOGATION_TIME}\" ORIGCERT_COUNT=${CERT_COUNT}" > /config/.donoteditthisfile
echo ""
if [ ! -z $CUSTOM_CA ]
then
echo "Using a custom CA for issuing certificates"
if [ ! -d /config/custom_ca ]
then
mkdir /config/custom_ca
echo "Please place your custom CA file into /config/custom_ca and restart the container"
better_exit
fi
if [ -z "$(ls -A /config/custom_ca)" ]
then
echo "The CUSTOM_CA option is populated, but the /config/custom_ca dir is empty. Please place your root certificate in this directory and restart the container"
better_exit
fi
if [ -z $CUSTOM_CA_SERVER ]
then
echo "CUSTOM_CA_SERVER has not been defined. It is required for using a custom CA to issue a certificate"
better_exit
fi
CUSTOM_CA_PATH=/config/custom_ca/$CUSTOM_CA
CUSTOM_CA_SERVER_OPT="--server $CUSTOM_CA_SERVER"
if [ $STAGING = "true" ]
then
echo "Staging option is not supported when using a custom CA. To remove this alert, set staging to false. If your CA has a standing endpoint, use the CUSTOM_CA_SERVER option to point to it instead"
better_exit
fi
fi
BASE_COMMAND=(certbot certonly --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos $CUSTOM_CA_SERVER_OPT --email $EMAIL -d $DOMAINS)
## Run with Cloudflare plugin
if [ $PLUGIN == "cloudflare" ]
then
echo "Using Cloudflare plugin"
if [ ! -f /config/.secrets/cloudflare.ini ]
then
touch /config/.secrets/cloudflare.ini
fi
if [ -n "$CLOUDFLARE_TOKEN" ]
then
echo "Cloudflare token is present"
echo "dns_cloudflare_api_token = $CLOUDFLARE_TOKEN" > /config/.secrets/cloudflare.ini
fi
if [ ! -s /config/.secrets/cloudflare.ini ]
then
echo "cloudflare.ini is empty - please add your Cloudflare credentials or API key before continuing. This can be done by setting CLOUDFLARE_TOKEN, or by editing /config/.secrets/cloudflare.ini directly"
better_exit
fi
#Securing cloudflare.ini to supress warnings
chmod 600 /config/.secrets/cloudflare.ini
echo "Creating certificates, or attempting to renew if they already exist"
if [ $STAGING = true ]
then
echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY"
${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging
# Add to renewal list
echo "renew \"REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging\"" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
elif [ $STAGING = false ]
then
echo "Using production endpoint"
${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini
# Add to renewal list
echo "renew \"REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini\"" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
else
echo "Unrecognised option for STAGING variable - check your configuration"
better_exit
fi
## Run with Standalone plugin
elif [ $PLUGIN == "standalone" ]
then
echo "Using HTTP verification via built-in web-server - please ensure port 80 is exposed."
if [ $STAGING = true ]
then
echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY"
REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone --staging
# Add to renewal list
echo "renew \"REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone --staging\"" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
elif [ $STAGING = false ]
then
echo "Using production endpoint"
REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone
# Add to renewal list
echo "renew \"REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone\"" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
else
echo "Unrecognised option for STAGING variable - check your configuration"
better_exit
fi
## Run with webroot plugin
elif [ $PLUGIN == "webroot" ]
then
echo "Using HTTP verification via webroot - please ensure you have mounted a webroot at /config/webroot from a web-server reachable via the domain you are issuing a certificate for."
if [ $STAGING = true ]
then
echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY"
REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging
# Add to renewal list
echo "renew \"REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging\"" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
elif [ $STAGING = false ]
then
echo "Using production endpoint"
REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot
# Add to renewal list
echo "renew \"REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot\"" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
else
echo "Unrecognised option for STAGING variable - check your configuration"
better_exit
fi
else
echo "Unrecognised option for PLUGIN variable - check your configuration"
fi
}
function multi_domain {
# Update config file with new env vars
echo -e "ORIGDOMAINS=\"${DOMAINS}\" ORIGEMAIL=\"${EMAIL}\" ORIGSTAGING=\"${STAGING}\" ORIGCUSTOM_CA=\"${CUSTOM_CA}\" ORIGCUSTOM_CA_SERVER=\"${CUSTOM_CA_SERVER}\" ORIGPLUGIN=\"${PLUGIN}\" ORIGPROPOGATION_TIME=\"${PROPOGATION_TIME}\" ORIGCERT_COUNT=${CERT_COUNT}" > /config/.donoteditthisfile
## Start multi-domain looper
x=1
while [ $x -le $CERT_COUNT ]
do
# Setting up variables (requires two passes to clean away requirement for indirect variable)
## Pass 1
DOMAINS_P1=DOMAINS_${x}
EMAIL_P1=EMAIL_${x}
STAGING_P1=STAGING_${x}
CUSTOM_CA_P1=CUSTOM_CA_${x}
CUSTOM_CA_SERVER_P1=CUSTOM_CA_SERVER_${x}
PLUGIN_P1=PLUGIN_${x}
PROPOGATION_TIME_P1=PROPOGATION_TIME_${x}
CLOUDFLARE_TOKEN_P1=CLOUDFLARE_TOKEN_${x}
## Pass 2
DOMAINS_MULTI=${!DOMAINS_P1}
EMAIL_MULTI=${!EMAIL_P1}
STAGING_MULTI=${!STAGING_P1}
CUSTOM_CA_MULTI=${!CUSTOM_CA_P1}
CUSTOM_CA_SERVER_MULTI=${!CUSTOM_CA_SERVER_P1}
PLUGIN_MULTI=${!PLUGIN_P1}
PROPOGATION_TIME_MULTI=${!PROPOGATION_TIME_P1}
CLOUDFLARE_TOKEN_MULTI=${!CLOUDFLARE_TOKEN_P1}
# Inheriting global default if undefined for certain variables
if [ -z ${EMAIL_MULTI} ]; then
EMAIL_MULTI=${EMAIL}
fi
if [ -z ${STAGING_MULTI} ]; then
STAGING_MULTI=${STAGING}
fi
if [ -z ${CUSTOM_CA_MULTI} ]; then
CUSTOM_CA_MULTI=${CUSTOM_CA}
fi
if [ -z ${CUSTOM_CA_SERVER_MULTI} ]; then
CUSTOM_CA_SERVER_MULTI=${CUSTOM_CA_SERVER}
fi
if [ -z ${PLUGIN_MULTI} ]; then
PLUGIN_MULTI=${PLUGIN}
fi
if [ -z ${PROPOGATION_TIME_MULTI} ]; then
PROPOGATION_TIME_MULTI=${PROPOGATION_TIME}
fi
# Create original config file to track changes to environmental variables
if [ ! -f /config/.donoteditthisfile_cert_${x} ]
then
echo -e "ORIGDOMAINS_${x}=\"${DOMAINS_MULTI}\" ORIGEMAIL_${x}=\"${EMAIL_MULTI}\" ORIGSTAGING_${x}=\"${STAGING_MULTI}\" ORIGCUSTOM_CA_${x}=\"${CUSTOM_CA_MULTI}\" ORIGCUSTOM_CA_SERVER_${x}=\"${CUSTOM_CA_SERVER_MULTI}\" ORIGPLUGIN_${x}=\"${PLUGIN_MULTI}\" ORIGPROPOGATION_TIME_${x}=\"${PROPOGATION_TIME_MULTI}\"" > /config/.donoteditthisfile_cert_${x}
fi
# Load original config file
. /config/.donoteditthisfile_cert_${x}
ORIGDOMAINS_MULTI=ORIGDOMAINS_${x}
ORIGEMAIL_MULTI=ORIGEMAIL_${x}
ORIGSTAGING_MULTI=ORIGSTAGING_${x}
ORIGCUSTOM_CA_MULTI=ORIGCUSTOM_CA_${x}
ORIGCUSTOM_CA_SERVER_MULTI=ORIGCUSTOM_CA_SERVER_${x}
ORIGPLUGIN_MULTI=ORIGPLUGIN_${x}
ORIGPROPOGATION_TIME_MULTI=ORIGPROPOGATION_TIME_${x}
ORIGCLOUDFLARE_TOKEN_MULTI=ORIGCLOUDFLARE_TOKEN_${x}
# Log variables to console (have to remove indent because bash dumb)
echo "
----------------------------------------------------------------------
CERTIFICATE ${x} ENVIRONMENT
----------------------------------------------------------------------"
echo \
"DOMAINS_${x}=${DOMAINS_MULTI}
EMAIL_${x}=${EMAIL_MULTI}
STAGING_${x}=${STAGING_MULTI}
CUSTOM_CA_${x}=${CUSTOM_CA_MULTI}
CUSTOM_CA_SERVER_${x}=${CUSTOM_CA_SERVER_MULTI}
PLUGIN_${x}=${PLUGIN_MULTI}"
## Get plugin-specific data if single certificate config
if [ ${PLUGIN_MULTI} == 'cloudflare' ]; then
echo \
"PROPOGATION_TIME_${x}=${PROPOGATION_TIME_MULTI}"
fi
if [ ${PLUGIN_MULTI} == 'cloudflare' ] && [ ! -z ${CLOUDFLARE_TOKEN_MULTI} ]; then
echo \
"CLOUDFLARE_TOKEN_${x}=[hidden]"
elif [ ${PLUGIN_MULTI} == 'cloudflare' ] && [ -z ${CLOUDFLARE_TOKEN_MULTI} ]; then
echo \
"CLOUDFLARE_TOKEN_${x}="
fi
echo \
"----------------------------------------------------------------------
"
# Begin actually requesting the certificate
echo "Requesting certificate $x"
# Checking for changes to config file, revoke certs if necessary
if [ ! "${DOMAINS_MULTI}" = "${!ORIGDOMAINS_MULTI}" ] ||
[ ! "${EMAIL_MULTI}" = "${!ORIGEMAIL_MULTI}" ] ||
[ ! "${STAGING_MULTI}" = "${!ORIGSTAGING_MULTI}" ] ||
[ ! "${CUSTOM_CA_MULTI}" = "${!ORIGCUSTOM_CA_MULTI}" ] ||
[ ! "${CUSTOM_CA_SERVER_MULTI}" = "${!ORIGCUSTOM_CA_SERVER_MULTI}" ] ||
[ ! "${PLUGIN_MULTI}" = "${!ORIGPLUGIN_MULTI}" ] ||
[ ! "${PROPOGATION_TIME_MULTI}" = "${!ORIGPROPOGATION_TIME_MULTI}" ]
then
echo ""
echo "Configuration has changed since certificate ${x} was last issued. Revoking and regenerating cert ${x}"
FIRST_DOMAIN_MULTI=$(echo ${!ORIGDOMAINS_MULTI} | cut -d \, -f1)
if [ ! -z ${!ORIGCUSTOM_CA_MULTI} ]
then
echo "A custom CA was used for issuing certificate ${x}. Using it to revoke as well."
if [ ! -d /config/custom_ca ]
then
mkdir /config/custom_ca
echo "Please place the custom CA root file used to generate the current certificate ${x} into /config/custom_ca and restart the container"
better_exit
fi
if [ -z "$(ls -A /config/custom_ca)" ]
then
echo "A root certificate called ${!ORIGCUSTOM_CA_MULTI} was used to generate a certificate, but the /config/custom_ca dir is now empty. Please place this root certificate back this directory and restart the container so it can be safely revoked"
better_exit
fi
ORIGCUSTOM_CA_PATH_MULTI=/config/custom_ca/${!ORIGCUSTOM_CA_MULTI}
ORIGCUSTOM_CA_SERVER_OPT_MULTI="--server ${!ORIGCUSTOM_CA_SERVER_MULTI}"
fi
if [ $ORIGSTAGING_MULTI = "true" ]
then
# Reusing the CUSTOM_CA_SERVER_OPT variable to add staging option if that was selected
ORIGCUSTOM_CA_SERVER_OPT_MULTI="--server https://acme-staging-v02.api.letsencrypt.org/directory"
fi
if [ -f /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}"/fullchain.pem ]
then
REQUESTS_CA_BUNDLE=$ORIGCUSTOM_CA_PATH_MULTI certbot revoke --non-interactive --agree-tos --email $ORIGEMAIL_MULTI --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --cert-path /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}"/fullchain.pem ${ORIGCUSTOM_CA_SERVER_OPT_MULTI} || true
rm -rf /config/letsencrypt/archive/"${FIRST_DOMAIN_MULTI}"
rm -rf /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}"
rm -rf /config/letsencrypt/renewal/"${FIRST_DOMAIN_MULTI}".conf
fi
echo "Tidying up any potential lingering ACME challenges in /config/webroot from failed webroot activations"
rm -rf /config/webroot/.well-known/acme-challenge
fi
# Update config file with new cert-specific env vars
echo -e "ORIGDOMAINS_${x}=\"${DOMAINS_MULTI}\" ORIGEMAIL_${x}=\"${EMAIL_MULTI}\" ORIGSTAGING_${x}=\"${STAGING_MULTI}\" ORIGCUSTOM_CA_${x}=\"${CUSTOM_CA_MULTI}\" ORIGCUSTOM_CA_SERVER_${x}=\"${CUSTOM_CA_SERVER_MULTI}\" ORIGPLUGIN_${x}=\"${PLUGIN_MULTI}\" ORIGPROPOGATION_TIME_${x}=\"${PROPOGATION_TIME_MULTI}\"" > /config/.donoteditthisfile_cert_${x}
echo ""
if [ ! -z ${CUSTOM_CA_MULTI} ]
then
echo "Using a custom CA for issuing certificate ${x}"
if [ ! -d /config/custom_ca ]
then
mkdir /config/custom_ca
echo "Please place your custom CA file into /config/custom_ca and restart the container"
better_exit
fi
if [ -z "$(ls -A /config/custom_ca)" ]
then
echo "The CUSTOM_CA_${x} option is populated, but the /config/custom_ca dir is empty. Please place your root certificate for certificate ${x} in this directory and restart the container"
better_exit
fi
if [ -z ${CUSTOM_CA_SERVER_MULTI} ]
then
echo "CUSTOM_CA_SERVER_${x} has not been defined. It is required when using a custom CA to issue certificate ${x}"
better_exit
fi
CUSTOM_CA_PATH_MULTI=/config/custom_ca/${CUSTOM_CA_MULTI}
CUSTOM_CA_SERVER_OPT_MULTI="--server ${CUSTOM_CA_SERVER_MULTI}"
if [ ${STAGING_MULTI} = "true" ]
then
echo "Staging option is not supported when using a custom CA. To remove this alert, set staging to false. If your CA has a standing endpoint, use the CUSTOM_CA_SERVER_${x} option to point to it instead"
better_exit
fi
fi
BASE_COMMAND=(certbot certonly --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos "${CUSTOM_CA_SERVER_OPT_MULTI}" --email "${EMAIL_MULTI}" -d "${DOMAINS_MULTI}")
## Run with Cloudflare plugin
if [ ${PLUGIN_MULTI} == "cloudflare" ]
then
echo "Using Cloudflare plugin"
if [ ! -f /config/.secrets/cloudflare.ini ]
then
touch /config/.secrets/cloudflare.ini
fi
if [ -n "${CLOUDFLARE_TOKEN_MULTI}" ]
then
echo "Cloudflare token is present"
echo "dns_cloudflare_api_token = ${CLOUDFLARE_TOKEN_MULTI}" > /config/.secrets/cloudflare.ini
fi
if [ ! -s /config/.secrets/cloudflare.ini ]
then
echo "cloudflare.ini is empty - please add your Cloudflare credentials or API key before continuing. This can be done by setting CLOUDFLARE_TOKEN_${x}"
better_exit
fi
#Securing cloudflare.ini to supress warnings
chmod 600 /config/.secrets/cloudflare.ini
echo "Creating certificates, or attempting to renew if they already exist"
if [ ${STAGING_MULTI} = true ]
then
echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY"
${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds ${PROPOGATION_TIME_MULTI} --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging
# Add to renewal list
echo "## Certificate ${x}" >> /config/.renew-list.sh
echo "renew \"${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds ${PROPOGATION_TIME_MULTI} --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging\"" >> /config/.renew-list.sh
echo "" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
elif [ ${STAGING_MULTI} = false ]
then
echo "Using production endpoint"
${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds ${PROPOGATION_TIME_MULTI} --dns-cloudflare-credentials /config/.secrets/cloudflare.ini
# Add to renewal list
echo "## Certificate ${x}" >> /config/.renew-list.sh
echo "renew \"REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds ${PROPOGATION_TIME_MULTI} --dns-cloudflare-credentials /config/.secrets/cloudflare.ini\"" >> /config/.renew-list.sh
echo "" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
else
echo "Unrecognised option for STAGING variable - check your configuration"
better_exit
fi
## Run with Standalone plugin
elif [ ${PLUGIN_MULTI} == "standalone" ]
then
echo "Using HTTP verification via built-in web-server - please ensure port 80 is exposed."
if [ ${STAGING_MULTI} = true ]
then
echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY"
REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --standalone --staging
# Add to renewal list
echo "## Certificate ${x}" >> /config/.renew-list.sh
echo "renew \"REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --standalone --staging\"" >> /config/.renew-list.sh
echo "" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
elif [ ${STAGING_MULTI} = false ]
then
echo "Using production endpoint"
REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --standalone
# Add to renewal list
echo "## Certificate ${x}" >> /config/.renew-list.sh
echo "renew \"REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --standalone\"" >> /config/.renew-list.sh
echo "" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
else
echo "Unrecognised option for STAGING variable - check your configuration"
better_exit
fi
## Run with webroot plugin
elif [ ${PLUGIN_MULTI} == "webroot" ]
then
echo "Using HTTP verification via webroot - please ensure you have mounted a webroot at /config/webroot from a web-server reachable via the domain you are issuing a certificate for."
if [ ${STAGING_MULTI} = true ]
then
echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY"
REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging
# Add to renewal list
echo "## Certificate ${x}" >> /config/.renew-list.sh
echo "renew \"REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging\"" >> /config/.renew-list.sh
echo "" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
elif [ ${STAGING_MULTI} = false ]
then
echo "Using production endpoint"
REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot
# Add to renewal list
echo "## Certificate ${x}" >> /config/.renew-list.sh
echo "renew \"REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot\"" >> /config/.renew-list.sh
echo "" >> /config/.renew-list.sh
echo "Creation/renewal attempt complete"
else
echo "Unrecognised option for STAGING variable - check your configuration"
better_exit
fi
else
echo "Unrecognised option for PLUGIN variable - check your configuration"
fi
# Scrubbing variables before running next cert to prevent overlap of values
DOMAINS_MULTI=
EMAIL_MULTI=
STAGING_MULTI=
CUSTOM_CA_MULTI=
CUSTOM_CA_SERVER_MULTI=
PLUGIN_MULTI=
PROPOGATION_TIME_MULTI=
CLOUDFLARE_TOKEN_MULTI=
CUSTOM_CA_PATH_MULTI=
CUSTOM_CA_SERVER_OPT_MULTI=
ORIGDOMAINS_MULTI=
ORIGEMAIL_MULTI=
ORIGSTAGING_MULTI=
ORIGCUSTOM_CA_MULTI=
ORIGCUSTOM_CA_SERVER_MULTI=
ORIGPLUGIN_MULTI=
ORIGPROPOGATION_TIME_MULTI=
ORIGCLOUDFLARE_TOKEN_MULTI=
FIRST_DOMAIN_MULTI=
ORIGCUSTOM_CA_PATH_MULTI=
ORIGCUSTOM_CA_SERVER_OPT_MULTI=
x=$(( $x + 1 ))
done
}
if [ $CERT_COUNT == 1 ]
then then
echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" single_domain
certbot certonly --staging --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --email $EMAIL -d $DOMAINS elif [ $CERT_COUNT -gt 1 ]
echo "Creation/renewal attempt complete"
elif [[ $STAGING = false ]]
then then
echo "Using production endpoint" multi_domain
certbot certonly --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --email $EMAIL -d $DOMAINS
echo "Creation/renewal attempt complete"
else else
echo "Unrecognised option for STAGING variable - check your configuration" echo "CERT_COUNT varaible not recognised. It needs to be a value of 1 or greater."
exit 22
fi fi
if [[ $GENERATE_DHPARAM = true ]] && [[ ! -s /config/letsencrypt/keys/ssl-dhparams.pem ]] # Finish /config/.renew-list.sh now all certs have been added
echo "
echo \"Renewal attempts complete\"" >> /config/.renew-list.sh
if [ $GENERATE_DHPARAM = true ] && [ ! -s /config/letsencrypt/keys/ssl-dhparams.pem ]
then then
echo "Generating Diffie-Hellman keys, saved to /config/letsencrypt/keys" echo ""
echo "Generating Diffie-Hellman keys, saved to /config/letsencrypt/keys. This can take a long time!"
openssl dhparam -out /config/letsencrypt/keys/ssl-dhparams.pem 4096 openssl dhparam -out /config/letsencrypt/keys/ssl-dhparams.pem 4096
fi fi
echo "$INTERVAL /certbot-renew.sh >> /config/logs/renew.log" > /config/.crontab.txt if [ $ONE_SHOT == "true" ]; then
echo "Starting automatic renewal job. Schedule is $INTERVAL" echo ""
crontab /config/.crontab.txt
echo "ONE_SHOT is true - exiting container"
elif [ $ONE_SHOT == "false" ]; then
echo "$INTERVAL /config/.renew-list.sh >> /config/logs/renew.log
0 0 * * * logrotate -v --state /config/logs/logrotate.status /logrotate.conf" > /config/.crontab.txt
echo ""
echo "Starting automatic renewal job. Schedule is $INTERVAL"
crontab /config/.crontab.txt
fi

View File

@ -1,20 +0,0 @@
#!/command/with-contenv bash
# shellcheck shell=bash
echo ''
date
echo "Attempting to renew certificates"
if [[ $STAGING = true ]]
then
echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY"
certbot certonly --staging --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --email $EMAIL -d $DOMAINS
echo "Renewal attempt complete"
elif [[ $STAGING = false ]]
then
echo "Using production endpoint"
certbot certonly --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --email $EMAIL -d $DOMAINS
echo "Renewal attempt complete"
else
echo "Unrecognised option for STAGING variable - check your configuration"
exit 8
fi

10
root/check-one-shot.sh Normal file
View File

@ -0,0 +1,10 @@
#!/command/with-contenv bash
# shellcheck shell=bash
if [ $ONE_SHOT == "true" ]; then
# Cleanly kill container by sending kill signal to supervisor process
echo 0 > /run/s6-linux-init-container-results/exitcode
/run/s6/basedir/bin/halt
fi

View File

@ -13,21 +13,55 @@ echo "| |"
echo "================================================" echo "================================================"
echo "" echo ""
echo "Initialising container" echo "Initialising container"
echo " if [ ${CERT_COUNT} == 1 ]; then
---------------------------------------------------------------------- echo \
"----------------------------------------------------------------------
ENVIRONMENT ENVIRONMENT
---------------------------------------------------------------------- ----------------------------------------------------------------------"
PUID=${PUID} else
echo \
"----------------------------------------------------------------------
ENVIRONMENT (Certificate options logged later)
----------------------------------------------------------------------"
fi
echo \
"PUID=${PUID}
PGID=${PGID} PGID=${PGID}
TZ=${TZ} TZ=${TZ}
DOMAINS=${DOMAINS} ONE_SHOT=${ONE_SHOT}
EMAIL=${EMAIL}
INTERVAL=${INTERVAL} INTERVAL=${INTERVAL}
STAGING=${STAGING}
PROPOGATION_TIME=${PROPOGATION_TIME}
GENERATE_DHPARAM=${GENERATE_DHPARAM} GENERATE_DHPARAM=${GENERATE_DHPARAM}
CLOUDFLARE_TOKEN=${CLOUDFLARE_TOKEN} CERT_COUNT=${CERT_COUNT}
---------------------------------------------------------------------- NOTIFY_ON_SUCCESS=${NOTIFY_ON_SUCCESS}
NOTIFY_ON_FAILURE=${NOTIFY_ON_FAILURE}"
if [ ! -z ${APPRISE_URL} ]; then
echo \
"APPRISE_URL=[hidden]"
fi
## Send extra detail to logs if single certificate config
if [ ${CERT_COUNT} == 1 ]; then
echo \
"DOMAINS=${DOMAINS}
EMAIL=${EMAIL}
STAGING=${STAGING}
CUSTOM_CA=${CUSTOM_CA}
CUSTOM_CA_SERVER=${CUSTOM_CA_SERVER}
PLUGIN=${PLUGIN}"
fi
## Get plugin-specific data if single certificate config
if [ ${CERT_COUNT} == 1 ] && [ ${PLUGIN} == 'cloudflare' ]; then
echo \
"PROPOGATION_TIME=${PROPOGATION_TIME}"
fi
if [ ${CERT_COUNT} == 1 ] && [ ${PLUGIN} == 'cloudflare' ] && [ ! -z ${CLOUDFLARE_TOKEN} ]; then
echo \
"CLOUDFLARE_TOKEN=[hidden]"
elif [ ${CERT_COUNT} == 1 ] && [ ${PLUGIN} == 'cloudflare' ] && [ -z ${CLOUDFLARE_TOKEN} ]; then
echo \
"CLOUDFLARE_TOKEN="
fi
echo \
"----------------------------------------------------------------------
" "
#Setting UID and GID as configured #Setting UID and GID as configured
@ -41,7 +75,7 @@ if [[ ! "${PUID}" -eq 0 ]] && [[ ! "${PGID}" -eq 0 ]]; then
groupmod -o -g "${PGID}" mrmeeb groupmod -o -g "${PGID}" mrmeeb
else else
echo "Running as root is not supported, please fix your PUID and PGID!" echo "Running as root is not supported, please fix your PUID and PGID!"
exit 1 sleep infinity
fi fi
echo "Checking permissions in /config and /app." echo "Checking permissions in /config and /app."

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
exec /check-one-shot.sh

View File

@ -1 +1,9 @@
echo "$e" > /run/s6-linux-init-container-results/exitcode #!/command/with-contenv bash
# shellcheck shell=bash
if [ $ONE_SHOT == "false" ]; then
# Export exit code if not a ONE_SHOT
echo "$e" > /run/s6-linux-init-container-results/exitcode
fi

View File

@ -1 +1,9 @@
echo "$e" > /run/s6-linux-init-container-results/exitcode #!/command/with-contenv bash
# shellcheck shell=bash
if [ $ONE_SHOT == "false" ]; then
# Export exit code if not a ONE_SHOT
echo "$e" > /run/s6-linux-init-container-results/exitcode
fi

15
root/logrotate.conf Normal file
View File

@ -0,0 +1,15 @@
missingok
/config/logs/letsencrypt.log {
daily
rotate 10
postrotate
find /config/logs -type f -regex '.*letsencrypt\.log\.\(.[2-9]\|[2-9].\|[1-9][0-9]\{2,\}\).*' -delete
endscript
}
/config/logs/renew.log {
rotate 5
size 100k
compress
}

27
root/renew-function.sh Normal file
View File

@ -0,0 +1,27 @@
function renew() {
#Variables:
#$1 = Certbot command
RENEWAL_DOMAINS=$(echo $1 | sed -r 's/.*\s-d\s(\S*).*/\1/')
CUSTOM_CA_PATH=$(echo $1 | sed -r 's/REQUESTS_CA_BUNDLE=(\S*)\s(.*)/\1/')
CERTBOT_COMMAND=$(echo $1 | sed -r 's/REQUESTS_CA_BUNDLE=(\S*)\s(.*)/\2/')
echo "Renewing certificate for ${RENEWAL_DOMAINS}"
echo "REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH} ${CERTBOT_COMMAND}" | bash
if [ $? = 0 ]; then
echo "Renewal attempt of certificate for ${RENEWAL_DOMAINS} succeeded"
if [ "${NOTIFY_ON_SUCCESS}" = "true" ]; then
apprise -b "Renewal of certificate for ${RENEWAL_DOMAINS} succeeded" ${APPRISE_URL}
fi
else
echo "Renewal attempt of certificate for ${RENEWAL_DOMAINS} failed"
if [ "${NOTIFY_ON_FAILURE}" = "true" ]; then
apprise -b "Renewal of certificate for ${RENEWAL_DOMAINS} failed" ${APPRISE_URL}
fi
fi
}