Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47538330f8 | ||
|
|
89e359ae7d | ||
|
|
96812e7ed4 | ||
|
|
72de4581be | ||
|
|
bf4bd0e3ea | ||
|
|
28f76dd30c | ||
|
|
807271359d | ||
|
|
479287c3e6 | ||
|
|
809a271859 | ||
|
|
a16eae23ce | ||
|
|
46b20246db | ||
|
|
6f31504a29 | ||
|
|
f0e2fd35bd | ||
|
|
69eee39904 | ||
|
|
ba8e522ff8 |
5
Makefile
5
Makefile
@@ -11,7 +11,7 @@ PROCFILE_UTIL_URL ?= $(shell jq -r --arg name procfile-util --arg arch $(TARGET
|
||||
SIGIL_URL ?= $(shell jq -r --arg name gliderlabs-sigil --arg arch $(TARGETARCH) '.predependencies[] | select(.name == $$name) | .urls[$$arch]' contrib/dependencies.json)
|
||||
SSHCOMMAND_URL ?= $(shell jq -r --arg name sshcommand --arg arch $(TARGETARCH) '.dependencies[] | select(.name == $$name) | .urls[$$arch]' contrib/dependencies.json)
|
||||
STACK_URL ?= https://github.com/gliderlabs/herokuish.git
|
||||
PREBUILT_STACK_URL ?= gliderlabs/herokuish:latest-24
|
||||
PREBUILT_STACK_URL ?= ccr.ccs.tencentyun.com/miaogai/herokuish:latest-24
|
||||
DOKKU_LIB_ROOT ?= /var/lib/dokku
|
||||
PLUGINS_PATH ?= ${DOKKU_LIB_ROOT}/plugins
|
||||
CORE_PLUGINS_PATH ?= ${DOKKU_LIB_ROOT}/core-plugins
|
||||
@@ -190,7 +190,8 @@ docker:
|
||||
grep -i -E "^docker" /etc/group || groupadd docker
|
||||
usermod -aG docker dokku
|
||||
ifndef CI
|
||||
wget -nv -O - https://get.docker.com/ | sh
|
||||
sudo apt install docker.io
|
||||
#wget --no-check-certificate -nv -O - https://get.docker.com/ | sh
|
||||
ifdef DOCKER_VERSION
|
||||
apt-get -qq -y --no-install-recommends install docker-engine=${DOCKER_VERSION} || (apt-cache madison docker-engine ; exit 1)
|
||||
endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
GO_ARGS ?=
|
||||
GO_PLUGIN_MAKE_TARGET ?= build
|
||||
GO_REPO_ROOT := /go/src/github.com/dokku/dokku
|
||||
BUILD_IMAGE := golang:1.26.2
|
||||
BUILD_IMAGE := hub.diyla.com/golang:1.26.2
|
||||
GO_BUILD_CACHE ?= /tmp/dokku-go-build-cache
|
||||
GO_MOD_CACHE ?= /tmp/dokku-go-mod-mod
|
||||
GO_ROOT_MOUNT ?= $$PWD/../..:$(GO_REPO_ROOT)
|
||||
@@ -19,6 +19,7 @@ build-in-docker: clean
|
||||
-v $(GO_MOD_CACHE):/go/pkg/mod \
|
||||
-e PLUGIN_NAME=$(PLUGIN_NAME) \
|
||||
-e GO111MODULE=on \
|
||||
-e GOPROXY=https://goproxy.cn,direct \
|
||||
-w $(GO_REPO_ROOT)/plugins/$(PLUGIN_NAME) \
|
||||
$(BUILD_IMAGE) \
|
||||
bash -c "GO_ARGS='$(GO_ARGS)' CGO_ENABLED=0 GOOS=linux GOARCH=$(GOARCH) GOWORK=off make -j4 $(GO_PLUGIN_MAKE_TARGET)" || exit $$?
|
||||
|
||||
@@ -4,56 +4,56 @@
|
||||
"name": "docker-container-healthchecker",
|
||||
"version": "0.16.0",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/dokku/docker-container-healthchecker/releases/download/v0.16.0/docker-container-healthchecker-linux-amd64",
|
||||
"arm64": "https://github.com/dokku/docker-container-healthchecker/releases/download/v0.16.0/docker-container-healthchecker-linux-arm64"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/dokku/docker-container-healthchecker/releases/download/v0.16.0/docker-container-healthchecker-linux-amd64",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/dokku/docker-container-healthchecker/releases/download/v0.16.0/docker-container-healthchecker-linux-arm64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "docker-image-labeler",
|
||||
"version": "0.10.0",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/dokku/docker-image-labeler/releases/download/v0.10.0/docker-image-labeler-linux-amd64",
|
||||
"arm64": "https://github.com/dokku/docker-image-labeler/releases/download/v0.10.0/docker-image-labeler-linux-arm64"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/dokku/docker-image-labeler/releases/download/v0.10.0/docker-image-labeler-linux-amd64",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/dokku/docker-image-labeler/releases/download/v0.10.0/docker-image-labeler-linux-arm64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lambda-builder",
|
||||
"version": "0.9.4",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/dokku/lambda-builder/releases/download/v0.9.4/lambda-builder-linux-amd64",
|
||||
"arm64": "https://github.com/dokku/lambda-builder/releases/download/v0.9.4/lambda-builder-linux-arm64"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/dokku/lambda-builder/releases/download/v0.9.4/lambda-builder-linux-amd64",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/dokku/lambda-builder/releases/download/v0.9.4/lambda-builder-linux-arm64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "netrc",
|
||||
"version": "0.11.1",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/dokku/netrc/releases/download/v0.11.1/netrc-linux-amd64",
|
||||
"arm64": "https://github.com/dokku/netrc/releases/download/v0.11.1/netrc-linux-arm64"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/dokku/netrc/releases/download/v0.11.1/netrc-linux-amd64",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/dokku/netrc/releases/download/v0.11.1/netrc-linux-arm64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pack",
|
||||
"version": "0.40.9",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/buildpacks/pack/releases/download/v0.40.9/pack-v0.40.9-linux.tgz",
|
||||
"arm64": "https://github.com/buildpacks/pack/releases/download/v0.40.9/pack-v0.40.9-linux-arm64.tgz"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/buildpacks/pack/releases/download/v0.40.9/pack-v0.40.9-linux.tgz",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/buildpacks/pack/releases/download/v0.40.9/pack-v0.40.9-linux-arm64.tgz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "procfile-util",
|
||||
"version": "0.20.8",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/dokku/procfile-util/releases/download/v0.20.8/procfile-util-linux-amd64",
|
||||
"arm64": "https://github.com/dokku/procfile-util/releases/download/v0.20.8/procfile-util-linux-arm64"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/dokku/procfile-util/releases/download/v0.20.8/procfile-util-linux-amd64",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/dokku/procfile-util/releases/download/v0.20.8/procfile-util-linux-arm64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sshcommand",
|
||||
"version": "0.20.2",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/dokku/sshcommand/releases/download/v0.20.2/sshcommand",
|
||||
"arm64": "https://github.com/dokku/sshcommand/releases/download/v0.20.2/sshcommand"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/dokku/sshcommand/releases/download/v0.20.2/sshcommand",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/dokku/sshcommand/releases/download/v0.20.2/sshcommand"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -62,16 +62,16 @@
|
||||
"name": "gliderlabs-sigil",
|
||||
"version": "0.12.1",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/gliderlabs/sigil/releases/download/v0.12.1/sigil-linux-amd64",
|
||||
"arm64": "https://github.com/gliderlabs/sigil/releases/download/v0.12.1/sigil-linux-arm64"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/gliderlabs/sigil/releases/download/v0.12.1/sigil-linux-amd64",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/gliderlabs/sigil/releases/download/v0.12.1/sigil-linux-arm64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "plugn",
|
||||
"version": "0.17.1",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/dokku/plugn/releases/download/v0.17.1/plugn-linux-amd64",
|
||||
"arm64": "https://github.com/dokku/plugn/releases/download/v0.17.1/plugn-linux-arm64"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/dokku/plugn/releases/download/v0.17.1/plugn-linux-amd64",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/dokku/plugn/releases/download/v0.17.1/plugn-linux-arm64"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -80,24 +80,24 @@
|
||||
"name": "dokku-event-listener",
|
||||
"version": "0.20.1",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/dokku/dokku-event-listener/releases/download/v0.20.1/dokku-event-listener-linux-amd64",
|
||||
"arm64": "https://github.com/dokku/dokku-event-listener/releases/download/v0.20.1/dokku-event-listener-linux-arm64"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/dokku/dokku-event-listener/releases/download/v0.20.1/dokku-event-listener-linux-amd64",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/dokku/dokku-event-listener/releases/download/v0.20.1/dokku-event-listener-linux-arm64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dokku-update",
|
||||
"version": "0.10.0",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/dokku/dokku-update/releases/download/v0.10.0/dokku-update",
|
||||
"arm64": "https://github.com/dokku/dokku-update/releases/download/v0.10.0/dokku-update"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/dokku/dokku-update/releases/download/v0.10.0/dokku-update",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/dokku/dokku-update/releases/download/v0.10.0/dokku-update"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "herokuish",
|
||||
"version": "0.11.16",
|
||||
"urls": {
|
||||
"amd64": "https://github.com/gliderlabs/herokuish/releases/download/v0.11.16/herokuish_0.11.16_linux_x86_64.tgz",
|
||||
"arm64": "https://github.com/gliderlabs/herokuish/releases/download/v0.11.16/herokuish_0.11.16_linux_x86_64.tgz"
|
||||
"amd64": "https://hub.diyla.com/https://github.com/gliderlabs/herokuish/releases/download/v0.11.16/herokuish_0.11.16_linux_x86_64.tgz",
|
||||
"arm64": "https://hub.diyla.com/https://github.com/gliderlabs/herokuish/releases/download/v0.11.16/herokuish_0.11.16_linux_x86_64.tgz"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
4
dokku
4
dokku
@@ -39,8 +39,8 @@ DOKKU_DISTRO=$(
|
||||
# configuration can ever override the DOCKER_BIN value
|
||||
export DOCKER_BIN=${DOCKER_BIN:="docker"}
|
||||
|
||||
export DOKKU_IMAGE=${DOKKU_IMAGE:="gliderlabs/herokuish:latest-24"}
|
||||
export DOKKU_CNB_BUILDER=${DOKKU_CNB_BUILDER:="heroku/builder:24"}
|
||||
export DOKKU_IMAGE=${DOKKU_IMAGE:="ccr.ccs.tencentyun.com/miaogai/herokuish:latest-24"}
|
||||
export DOKKU_CNB_BUILDER=${DOKKU_CNB_BUILDER:="ccr.ccs.tencentyun.com/miaogai/heroku:builder24"}
|
||||
export DOKKU_LIB_ROOT=${DOKKU_LIB_PATH:="/var/lib/dokku"}
|
||||
|
||||
export PLUGIN_PATH=${PLUGIN_PATH:="$DOKKU_LIB_ROOT/plugins"}
|
||||
|
||||
9
plugins/letsencrypt/.editorconfig
Normal file
9
plugins/letsencrypt/.editorconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
# http://EditorConfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
12
plugins/letsencrypt/.github/dependabot.yaml
vendored
Normal file
12
plugins/letsencrypt/.github/dependabot.yaml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
52
plugins/letsencrypt/.github/workflows/bump-version.yaml
vendored
Normal file
52
plugins/letsencrypt/.github/workflows/bump-version.yaml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: "bump-version"
|
||||
|
||||
# yamllint disable-line rule:truthy
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
bump_type:
|
||||
description: "Bump type"
|
||||
default: "patch"
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- patch
|
||||
- minor
|
||||
- major
|
||||
|
||||
env:
|
||||
GITHUB_ACCESS_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
|
||||
jobs:
|
||||
bump-version:
|
||||
name: bump-version
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ env.GITHUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Get Latest Tag
|
||||
id: latest-tag
|
||||
run: |
|
||||
echo GIT_LATEST_TAG="$(git describe --tags "$(git rev-list --tags --max-count=1)")" >>"$GITHUB_OUTPUT"
|
||||
|
||||
- name: Compute Next Tag
|
||||
id: next-tag
|
||||
uses: docker://ghcr.io/dokku/semver-generator:latest
|
||||
with:
|
||||
bump: ${{ github.event.inputs.bump_type }}
|
||||
input: ${{ steps.latest-tag.outputs.GIT_LATEST_TAG }}
|
||||
|
||||
- name: Create and Push Tag
|
||||
run: |
|
||||
git config --global user.name 'Dokku Bot'
|
||||
git config --global user.email no-reply@dokku.com
|
||||
git tag "$GIT_NEXT_TAG"
|
||||
git push origin "$GIT_NEXT_TAG"
|
||||
env:
|
||||
GIT_NEXT_TAG: ${{ steps.next-tag.outputs.version }}
|
||||
20
plugins/letsencrypt/.github/workflows/tagged-release.yaml
vendored
Normal file
20
plugins/letsencrypt/.github/workflows/tagged-release.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: "tagged-release"
|
||||
|
||||
# yamllint disable-line rule:truthy
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
tagged-release:
|
||||
name: tagged-release
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2.6.1
|
||||
with:
|
||||
generate_release_notes: true
|
||||
make_latest: "true"
|
||||
10
plugins/letsencrypt/.gitignore
vendored
Normal file
10
plugins/letsencrypt/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#### joe made this: http://goel.io/joe
|
||||
|
||||
#####=== Vim ===#####
|
||||
[._]*.s[a-w][a-z]
|
||||
[._]s[a-w][a-z]
|
||||
*.un~
|
||||
Session.vim
|
||||
.netrwhist
|
||||
*~
|
||||
|
||||
1
plugins/letsencrypt/Dockerfile
Normal file
1
plugins/letsencrypt/Dockerfile
Normal file
@@ -0,0 +1 @@
|
||||
FROM goacme/lego:v4.33.0
|
||||
22
plugins/letsencrypt/LICENSE
Normal file
22
plugins/letsencrypt/LICENSE
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Stefan Seemayer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
217
plugins/letsencrypt/README.md
Normal file
217
plugins/letsencrypt/README.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# dokku-letsencrypt
|
||||
|
||||
dokku-letsencrypt is the official plugin for [dokku][dokku] that gives the ability to automatically retrieve and install TLS certificates from [letsencrypt.org](https://letsencrypt.org). During ACME validation, your app will stay available at any time.
|
||||
|
||||
> By running this plugin, you agree to the Let's Encrypt Subscriber Agreement automatically (because prompting you whether you agree might break running the plugin as part of a cronjob).
|
||||
>
|
||||
> If you like Let's Encrypt, please consider [donating to Let's Encrypt](https://letsencrypt.org/donate).
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
|
||||
sudo dokku letsencrypt:cron-job --add # <- To enable auto-renew
|
||||
```
|
||||
|
||||
### Upgrading from previous versions
|
||||
|
||||
```shell
|
||||
sudo dokku plugin:update letsencrypt
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```
|
||||
$ dokku letsencrypt:help
|
||||
letsencrypt:active <app> Verify if letsencrypt is active for an app
|
||||
letsencrypt:auto-renew Auto-renew all apps secured by letsencrypt if renewal is necessary
|
||||
letsencrypt:auto-renew <app> Auto-renew app if renewal is necessary
|
||||
letsencrypt:cleanup <app> Cleanup stale certificates and configurations
|
||||
letsencrypt:cron-job <--add|--remove> Add or remove an auto-renewal cronjob
|
||||
letsencrypt:disable <app> Disable letsencrypt for an app
|
||||
letsencrypt:enable <app> Enable or renew letsencrypt for an app
|
||||
letsencrypt:list List letsencrypt-secured apps with certificate expiry
|
||||
letsencrypt:revoke <app> Revoke letsencrypt certificate for app
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
> If using this plugin with Cloudflare:
|
||||
>
|
||||
> - The domain dns should be setup in "Proxied" mode
|
||||
> - SSL/TLS mode must be in "Full" mode
|
||||
> - Using letsencrypt in "Flexible" mode will cause Cloudflare to detect your server as down
|
||||
> - Using "Full" mode will require disabling SSL/TLS in cloudflare in order to renew the certificate.
|
||||
>
|
||||
> If using "Flexible" SSL/TLS mode, avoid using this plugin.
|
||||
>
|
||||
> See these two links for more details:
|
||||
>
|
||||
> - https://community.cloudflare.com/t/lets-encrypt-ssl-cannot-renew-with-cloudflare/257666
|
||||
> - https://support.cloudflare.com/hc/en-us/articles/214820528-Validating-a-Let-s-Encrypt-Certificate-on-a-Site-Already-Active-on-Cloudflare
|
||||
|
||||
The app which is obtaining a letsencrypt certificate must already be deployed and accessible over the internet (i.e. in the browser) in order to add letsencrypt to your app. This plugin will fail to apply for an app that has otherwise only been created.
|
||||
|
||||
Obtain a Let's encrypt TLS certificate for app `myapp` (you can also run this command to renew the certificate):
|
||||
|
||||
```
|
||||
$ dokku letsencrypt:set myapp email your@email.tld
|
||||
-----> Setting email to your@email.tld
|
||||
$ dokku letsencrypt:enable myapp
|
||||
=====> Let's Encrypt myapp...
|
||||
-----> Updating letsencrypt docker image...
|
||||
latest: Pulling from dokku/letsencrypt
|
||||
|
||||
Digest: sha256:20f2a619795c1a3252db6508f77d6d3648ad5b336e67caaf801126367dbdfa22
|
||||
Status: Image is up to date for dokku/letsencrypt:latest
|
||||
done
|
||||
-----> Enabling letsencrypt proxy for myapp...
|
||||
-----> Getting letsencrypt certificate for myapp...
|
||||
- Domain 'myapp.mydomain.com'
|
||||
|
||||
[ removed various log messages for brevity ]
|
||||
|
||||
-----> Certificate retrieved successfully.
|
||||
-----> Symlinking let's encrypt certificates
|
||||
-----> Configuring SSL for myapp.mydomain.com...(using /var/lib/dokku/plugins/available/nginx-vhosts/templates/nginx.ssl.conf.template)
|
||||
-----> Creating https nginx.conf
|
||||
-----> Running nginx-pre-reload
|
||||
Reloading nginx
|
||||
-----> Disabling letsencrypt proxy for myapp...
|
||||
done
|
||||
```
|
||||
|
||||
Once the certificate is installed, you can use the `certs:*` built-in commands to edit and query your certificate.
|
||||
|
||||
You could also use the following command to set an email address for global. So you don't need to type the email address for different application.
|
||||
|
||||
```shell
|
||||
dokku letsencrypt:set --global email your@email.tld
|
||||
```
|
||||
|
||||
## Automatic certificate renewal
|
||||
|
||||
To enable the automatic renewal of certificates, a cronjob needs to be defined for
|
||||
the `dokku` user which will run daily and renew any certificates that are due to
|
||||
be renewed.
|
||||
|
||||
This can be done using the following command:
|
||||
|
||||
```shell
|
||||
dokku letsencrypt:cron-job --add
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
`dokku-letsencrypt` uses the [Dokku environment variable manager](https://dokku.com/docs/configuration/environment-variables/) for all configuration. The important environment variables are:
|
||||
|
||||
Variable | Default | Description
|
||||
---------------------|-------------------|-------------------------------------------------------------------------
|
||||
`dns-provider` | (none) | The name of a [valid lego dns-provider](https://go-acme.github.io/lego/dns/)
|
||||
`email` | (none) | **REQUIRED:** E-mail address to use for registering with Let's Encrypt.
|
||||
`graceperiod` | 2592000 (30 days) | Time in seconds left on a certificate before it should get renewed
|
||||
`lego-docker-args` | (none) | Extra arguments to pass via `docker run`. See the [lego CLI documentation](https://go-acme.github.io/lego/usage/cli/) for available options.
|
||||
`server` | default | Which ACME server to use. Can be 'default', 'staging' or a URL
|
||||
|
||||
You can set a setting using `dokku letsencrypt:set $APP $SETTING_NAME $SETTING_VALUE`. When looking for a setting, the plugin will first look if it was defined for the current app and fall back to settings defined by `--global`.
|
||||
|
||||
> Note: See "DNS-01 Challenge" for more information on configuration a dns-provider for DNS-01 based challenges and wildcard support.
|
||||
|
||||
## Redirecting from HTTP to HTTPS
|
||||
|
||||
Dokku's default nginx template will automatically redirect HTTP requests to HTTPS when a certificate is present.
|
||||
|
||||
You can [customize the nginx template](https://dokku.com/docs/networking/proxies/nginx/) if you want different behaviour.
|
||||
|
||||
## Design
|
||||
|
||||
`dokku-letsencrypt` gets around having to disable your web server using the following workflow:
|
||||
|
||||
1. Temporarily add a reverse proxy for the `/.well-known/` path of your app to `https://127.0.0.1:$ACMEPORT`
|
||||
2. Run [the acme/lego Let's Encrypt client](https://github.com/go-acme/lego) in a [Docker container](https://hub.docker.com/r/goacme/lego/) binding to `$ACMEPORT` to complete the ACME challenge and retrieve the TLS certificates
|
||||
3. Install the TLS certificates
|
||||
4. Remove the reverse proxy and reload nginx
|
||||
|
||||
For a more in-depth explanation, see [this blog post](https://blog.semicolonsoftware.de/securing-dokku-with-lets-encrypt-tls-certificates/)
|
||||
|
||||
## Dockerfile and Image-based Deploys
|
||||
|
||||
When securing Dockerfile and Image-based deploys with dokku-letsencrypt, be aware of the [proxy mechanism for dokku 0.6+](https://dokku.com/docs/networking/port-management/#dockerfile).
|
||||
|
||||
For Dockerfile deploys - as well as those via `git:from-image` - Dokku will determine which ports a container exposes (using `EXPOSE`) and will proxy them on the same port numbers on the host. If the Dockerfile exposes another port than 443, then HTTPS port 443 **needs to be manually configured** using the `dokku ports:*` commands in order for certificate validation and browsing to the app via HTTPS to work.
|
||||
|
||||
A full workflow for creating a new Dockerfile/Image-based deployment (assuming the app is listening/exposed on port 5555) with `dokku-letsencrypt` would be:
|
||||
|
||||
1. Create a new app `myapp` in dokku and push to the `dokku@myhost.com` remote.
|
||||
2. On the dokku host, use `dokku letsencrypt:enable myapp` to retrieve HTTPS certificates.
|
||||
3. On the dokku host, use `dokku ports:add myapp https:443:5555` to proxy HTTPS port 443 to port 5555 on the Docker image
|
||||
|
||||
After these steps, the output of `dokku ports:report myapp` should look like this:
|
||||
|
||||
```
|
||||
=====> myapp ports information
|
||||
Ports map: https:443:5555
|
||||
Ports map detected: https:5555:5555
|
||||
```
|
||||
|
||||
Replace the container port (`5555` in the above example) with the port your app is listening on.
|
||||
|
||||
## Dealing with rate limit
|
||||
|
||||
Be aware that Let's Encrypt is subject to [rate limiting](https://letsencrypt.org/docs/rate-limits/). The limit about the number of certificates you can add on a domain per week is a concern for dokku because of the default domain added to your new applications, named like `<app>.<dokku-domain>`: using `dokku-letsencrypt` on all your applications would create a certificate for each application subdomain on `<dokku-domain>`.
|
||||
|
||||
As a workaround, if you want to encrypt many applications, make sure to add a proper domain for each one and remove their default domain before running `dokku-letsencrypt`. For example, if your dokku domain is `dokku.example.com` and you want to encrypt your `foo` app:
|
||||
|
||||
```sh
|
||||
dokku domains:add foo foo.com
|
||||
dokku domains:remove foo foo.dokku.example.com
|
||||
dokku letsencrypt:enable foo
|
||||
```
|
||||
|
||||
While playing around with this plugin, you might want to switch to the let's encrypt staging server by running `dokku letsencrypt:set myapp server staging` to enjoy much higher rate limits and switching back to the real server by running `dokku letsencrypt:set myapp server` once you are ready.
|
||||
|
||||
## Generating a Cert for multiple domains
|
||||
|
||||
Your [default dokku app](https://dokku.com/docs/networking/proxies/nginx/?h=default+site#default-site) is accessible under the root domain too. So if you have an application `00-default` that is running under `00-default.mydomain.com` it is accessible under `mydomain.com` too. Now if you enable letsencrypt for your `00-default` application, it is not accessible anymore on `mydomain.com`. You can add the root domain to your dokku domains by typing:
|
||||
|
||||
```shell
|
||||
dokku domains:add 00-default mydomain.com
|
||||
dokku letsencrypt:enable 00-default
|
||||
```
|
||||
|
||||
## DNS-01 Challenge
|
||||
|
||||
> Functionality sponsored by [Orca Scan Ltd](https://orcascan.com/).
|
||||
|
||||
In order to provide a Letsencrypt certificate for a wildcard domain, a DNS-01 challenge must be used. To configure, the `dns-provider` property must be set to a [supported Lego provider](https://go-acme.github.io/lego/dns/). Additionally, the environment variables used by the DNS provider must be set as letsencrypt properties with the prefix `dns-provider-`. Both global and app-specific properties are supported.
|
||||
|
||||
> Warning: Before using a DNS-based challenge, ensure all DNS records - including wildcard records - are pointing at your server.
|
||||
|
||||
```shell
|
||||
# set the provider to namecheap
|
||||
dokku letsencrypt:set --global dns-provider namecheap
|
||||
|
||||
# set the properties necessary for namecheap usage
|
||||
dokku letsencrypt:set --global dns-provider-NAMECHEAP_API_USER user
|
||||
dokku letsencrypt:set --global dns-provider-NAMECHEAP_API_KEY key
|
||||
```
|
||||
|
||||
Due to limitations in how certain DNS providers work, environment variables _must not_ use the `_FILE` based method for referring to values in files.
|
||||
|
||||
Please see the Lego documentation for your DNS provider for more information on what configuration is necessary to utilize DNS-01 challenges.
|
||||
|
||||
## Conditional enabling
|
||||
|
||||
`dokku letsencrypt:enable <app>` enables letsencrypt for an application or renews the certificate. This may lead to hitting rate limits with letsencrypt.
|
||||
|
||||
To avoid renewals, for example in a continuous deployment scenario, you could first check if letsencrypt has already been enabled for the app:
|
||||
|
||||
```shell
|
||||
dokku letsencrypt:active <app> || dokku letsencrypt:enable <app>
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This plugin is released under the MIT license. See the file [LICENSE](LICENSE).
|
||||
|
||||
[dokku]: https://github.com/dokku/dokku
|
||||
323
plugins/letsencrypt/command-functions
Executable file
323
plugins/letsencrypt/command-functions
Executable file
@@ -0,0 +1,323 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/internal-functions"
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-active() {
|
||||
declare desc="Verify if letsencrypt is active for an app"
|
||||
declare cmd="letsencrypt:active"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
# Support --app/$DOKKU_APP_NAME flag by reordering args into "$cmd $DOKKU_APP_NAME $@"
|
||||
[[ -n "$DOKKU_APP_NAME" ]] && set -- $DOKKU_APP_NAME $@
|
||||
|
||||
declare APP="$1"
|
||||
|
||||
verify_app_name "$APP"
|
||||
fn-letsencrypt-is-active "$APP"
|
||||
}
|
||||
|
||||
cmd-letsencrypt-auto-renew() {
|
||||
declare desc="auto-renew certificates if necessary"
|
||||
declare cmd="letsencrypt:auto-renew"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
# Support --app/$DOKKU_APP_NAME flag by reordering args into "$cmd $DOKKU_APP_NAME $@"
|
||||
[[ -n "$DOKKU_APP_NAME" ]] && set -- $DOKKU_APP_NAME $@
|
||||
|
||||
declare APP="$1"
|
||||
local expiry grace_period
|
||||
|
||||
if [ -z "$APP" ]; then
|
||||
dokku_log_info2 "Auto-renewing all apps..."
|
||||
local EXIT_CODE=0
|
||||
|
||||
# For all apps, sorted by ascending time left until renewal.
|
||||
# This way, we'll prioritize apps that need to be renewed soon
|
||||
# if we should hit a rate limit along the way.
|
||||
# Store the list in a temporary file to avoid subshell issues with pipelines
|
||||
local temp_file=$(mktemp)
|
||||
fn-letsencrypt-list-apps-with-expiry | sort -nk5 > "$temp_file"
|
||||
|
||||
while IFS=$'\t' read -r -a appExpiry; do
|
||||
if [[ ${appExpiry[4]} -lt 0 ]]; then
|
||||
dokku_log_info1 "${appExpiry[0]} needs renewal"
|
||||
if ! dokku letsencrypt:enable "${appExpiry[0]}"; then
|
||||
EXIT_CODE=1
|
||||
fi
|
||||
else
|
||||
days_left=$(fn-letsencrypt-format-timediff "${appExpiry[4]}")
|
||||
dokku_log_verbose "${appExpiry[0]} still has $days_left days left before renewal"
|
||||
fi
|
||||
done < "$temp_file"
|
||||
|
||||
rm -f "$temp_file"
|
||||
|
||||
dokku_log_info2 "Finished auto-renewal"
|
||||
if [[ "$EXIT_CODE" != 0 ]]; then
|
||||
dokku_log_fail "One or more apps failed to have their certificates renewed"
|
||||
fi
|
||||
else
|
||||
verify_app_name "$APP"
|
||||
|
||||
if [[ "$(fn-letsencrypt-is-active "$APP")" != "true" ]]; then
|
||||
dokku_log_info1 "Letsencrypt not enabled for ${APP}"
|
||||
return
|
||||
fi
|
||||
|
||||
expiry=$(fn-letsencrypt-expiration "$APP")
|
||||
grace_period=$(fn-letsencrypt-computed-graceperiod "$APP")
|
||||
local time_to_renewal=$((expiry - grace_period - $(date +%s)))
|
||||
|
||||
if [[ $time_to_renewal -lt 0 ]]; then
|
||||
dokku_log_info2 "Auto-renew ${APP}..."
|
||||
dokku letsencrypt:enable "$APP"
|
||||
else
|
||||
days_left=$(fn-letsencrypt-format-timediff $time_to_renewal)
|
||||
dokku_log_verbose "$APP still has $days_left left before renewal"
|
||||
fi
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
cmd-letsencrypt-cleanup() {
|
||||
declare desc="clean up unused certificate directories"
|
||||
declare cmd="letsencrypt:cleanup"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
local certdir_basename current_config
|
||||
|
||||
# Support --app/$DOKKU_APP_NAME flag by reordering args into "$cmd $DOKKU_APP_NAME $@"
|
||||
[[ -n "$DOKKU_APP_NAME" ]] && set -- $DOKKU_APP_NAME $@
|
||||
|
||||
declare APP="$1"
|
||||
verify_app_name "$APP"
|
||||
|
||||
local app_root="$DOKKU_ROOT/$APP"
|
||||
local le_root="$app_root/letsencrypt"
|
||||
|
||||
current_config="$(basename "$(readlink "$le_root/certs/current")")"
|
||||
|
||||
if [ -z "$current_config" ] || [[ ! -d "$le_root/certs/$current_config" ]]; then
|
||||
dokku_log_warn "Cannot resolve the 'current' certificate directory!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
dokku_log_info2 "Cleaning up stale certificate directories for $APP"
|
||||
dokku_log_info1 " - current config hash $current_config"
|
||||
|
||||
for certdir in $le_root/certs/*; do
|
||||
certdir_basename="$(basename "$certdir")"
|
||||
|
||||
if [[ "$certdir_basename" == "current" ]] || [[ "$certdir_basename" == "$current_config" ]]; then continue; fi
|
||||
dokku_log_info1 " - stale directory $certdir_basename"
|
||||
|
||||
rm -rf "$le_root/certs/$certdir_basename"
|
||||
done
|
||||
}
|
||||
|
||||
cmd-letsencrypt-cron-job() {
|
||||
declare desc="Add or remove a cron job that periodically calls auto-renew"
|
||||
declare cmd="letsencrypt:cron-job"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare FLAG="$1"
|
||||
|
||||
if [[ "$FLAG" == "--add" ]]; then
|
||||
fn-letsencrypt-cron-job-add
|
||||
elif [[ "$FLAG" == "--remove" ]]; then
|
||||
fn-letsencrypt-cron-job-remove
|
||||
else
|
||||
dokku_log_verbose "Specify --add or --remove to modify the cron-job"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd-letsencrypt-disable() {
|
||||
declare desc="Disable letsencrypt for an app"
|
||||
declare cmd="letsencrypt:disable"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
# Support --app/$DOKKU_APP_NAME flag by reordering args into "$cmd $DOKKU_APP_NAME $@"
|
||||
[[ -n "$DOKKU_APP_NAME" ]] && set -- $DOKKU_APP_NAME $@
|
||||
|
||||
declare APP="$1"
|
||||
verify_app_name "$APP"
|
||||
|
||||
dokku_log_info1 "Disabling letsencrypt for app"
|
||||
local le_root="$DOKKU_ROOT/$APP/letsencrypt"
|
||||
local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls"
|
||||
|
||||
dokku_log_verbose "Removing letsencrypt files for $APP"
|
||||
rm -rf "$le_root"
|
||||
|
||||
dokku_log_verbose "Removing SSL endpoint from $APP"
|
||||
rm -rf "$APP_SSL_PATH"
|
||||
plugn trigger post-certs-remove "$APP"
|
||||
plugn trigger post-domains-update "$APP"
|
||||
|
||||
dokku_log_info1 "Done"
|
||||
}
|
||||
|
||||
cmd-letsencrypt-enable() {
|
||||
declare desc="Enable or renew letsencrypt for an app"
|
||||
declare cmd="letsencrypt:enable"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
# Support --app/$DOKKU_APP_NAME flag by reordering args into "$cmd $DOKKU_APP_NAME $@"
|
||||
[[ -n "$DOKKU_APP_NAME" ]] && set -- $DOKKU_APP_NAME $@
|
||||
|
||||
declare APP="$1"
|
||||
if [[ "$APP" == "--all" ]]; then
|
||||
for app in $(dokku_apps); do
|
||||
fn-letsencrypt-enable "$app"
|
||||
done
|
||||
else
|
||||
fn-letsencrypt-enable "$APP"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd-letsencrypt-list() {
|
||||
declare desc="list letsencrypt-secured apps and certificate expiries"
|
||||
declare cmd="letsencrypt:list"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
dokku_col_log_info1_quiet "App name" "Certificate Expiry" "Time before expiry" "Time before renewal"
|
||||
|
||||
fn-letsencrypt-list-apps-with-expiry \
|
||||
| sort -nk2 \
|
||||
| while IFS=$'\t' read -r -a appExpiry; do
|
||||
expire_date=$(date -d "@${appExpiry[1]}" +"%F %T")
|
||||
expire_time=$(fn-letsencrypt-format-timediff "${appExpiry[3]}")
|
||||
renew_time=$(fn-letsencrypt-format-timediff "${appExpiry[4]}")
|
||||
dokku_col_log_msg "${appExpiry[0]}" "${expire_date}" "${expire_time}" "${renew_time}"
|
||||
done
|
||||
}
|
||||
|
||||
cmd-letsencrypt-report() {
|
||||
declare desc="displays a letsencrypt report for one or more apps"
|
||||
declare cmd="letsencrypt:report"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1" INFO_FLAG="$2"
|
||||
local INSTALLED_APPS
|
||||
INSTALLED_APPS=$(dokku_apps)
|
||||
|
||||
if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then
|
||||
INFO_FLAG="$APP"
|
||||
APP=""
|
||||
fi
|
||||
|
||||
if [[ -z "$APP" ]] && [[ -z "$INFO_FLAG" ]]; then
|
||||
INFO_FLAG="true"
|
||||
fi
|
||||
|
||||
if [[ -z "$APP" ]]; then
|
||||
for app in $INSTALLED_APPS; do
|
||||
cmd-letsencrypt-report-single "$app" "$INFO_FLAG" | tee || true
|
||||
done
|
||||
else
|
||||
cmd-letsencrypt-report-single "$APP" "$INFO_FLAG"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd-letsencrypt-report-single() {
|
||||
declare APP="$1" INFO_FLAG="$2"
|
||||
if [[ "$INFO_FLAG" == "true" ]]; then
|
||||
INFO_FLAG=""
|
||||
fi
|
||||
verify_app_name "$APP"
|
||||
local flag_map=(
|
||||
"--letsencrypt-active: $(fn-letsencrypt-is-active "$APP")"
|
||||
"--letsencrypt-autorenew: $(fn-letsencrypt-is-autorenew-enabled "$APP")"
|
||||
"--letsencrypt-computed-dns-provider: $(fn-letsencrypt-computed-dns-provider "$APP")"
|
||||
"--letsencrypt-global-dns-provider: $(fn-letsencrypt-global-dns-provider)"
|
||||
"--letsencrypt-dns-provider: $(fn-letsencrypt-dns-provider "$APP")"
|
||||
"--letsencrypt-computed-email: $(fn-letsencrypt-computed-email "$APP")"
|
||||
"--letsencrypt-global-email: $(fn-letsencrypt-global-email)"
|
||||
"--letsencrypt-email: $(fn-letsencrypt-email "$APP")"
|
||||
"--letsencrypt-expiration: $(fn-letsencrypt-expiration "$APP")"
|
||||
"--letsencrypt-computed-graceperiod: $(fn-letsencrypt-computed-graceperiod "$APP")"
|
||||
"--letsencrypt-global-graceperiod: $(fn-letsencrypt-global-graceperiod)"
|
||||
"--letsencrypt-graceperiod: $(fn-letsencrypt-graceperiod "$APP")"
|
||||
"--letsencrypt-computed-lego-docker-args: $(fn-letsencrypt-computed-lego-docker-args "$APP")"
|
||||
"--letsencrypt-global-lego-docker-args: $(fn-letsencrypt-global-lego-docker-args)"
|
||||
"--letsencrypt-lego-docker-args: $(fn-letsencrypt-lego-docker-args "$APP")"
|
||||
"--letsencrypt-computed-server: $(fn-letsencrypt-computed-server "$APP")"
|
||||
"--letsencrypt-global-server: $(fn-letsencrypt-global-server)"
|
||||
"--letsencrypt-server: $(fn-letsencrypt-server "$APP")"
|
||||
)
|
||||
|
||||
if [[ -z "$INFO_FLAG" ]]; then
|
||||
dokku_log_info2_quiet "${APP} letsencrypt information"
|
||||
for flag in "${flag_map[@]}"; do
|
||||
key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')"
|
||||
dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")"
|
||||
done
|
||||
else
|
||||
local match=false
|
||||
local value_exists=false
|
||||
for flag in "${flag_map[@]}"; do
|
||||
valid_flags="${valid_flags} $(echo "$flag" | cut -d':' -f1)"
|
||||
if [[ "$flag" == "${INFO_FLAG}:"* ]]; then
|
||||
value=${flag#*: }
|
||||
size="${#value}"
|
||||
if [[ "$size" -ne 0 ]]; then
|
||||
echo "$value" && match=true && value_exists=true
|
||||
else
|
||||
match=true
|
||||
fi
|
||||
fi
|
||||
done
|
||||
[[ "$match" == "true" ]] || dokku_log_fail "Invalid flag passed, valid flags:${valid_flags}"
|
||||
[[ "$value_exists" == "true" ]] || dokku_log_fail "not deployed"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd-letsencrypt-revoke() {
|
||||
declare desc="Revoke a certificate"
|
||||
declare cmd="letsencrypt:revoke"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
# Support --app/$DOKKU_APP_NAME flag by reordering args into "$cmd $DOKKU_APP_NAME $@"
|
||||
[[ -n "$DOKKU_APP_NAME" ]] && set -- $DOKKU_APP_NAME $@
|
||||
|
||||
declare APP="$1"
|
||||
verify_app_name "$APP"
|
||||
|
||||
dokku_log_info2 "Revoke letsencrypt certificate from ${APP}..."
|
||||
|
||||
fn-letsencrypt-check-email "$APP"
|
||||
fn-letsencrypt-acme-revoke "$APP" || true
|
||||
|
||||
dokku_log_info1 "Done"
|
||||
}
|
||||
|
||||
cmd-letsencrypt-set() {
|
||||
declare desc="set or clear a letsencrypt property for an app"
|
||||
declare cmd="letsencrypt:set"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1" KEY="$2" VALUE="$3"
|
||||
local VALID_KEYS=("dns-provider" "email" "graceperiod" "server" "lego-docker-args")
|
||||
[[ "$APP" == "--global" ]] || verify_app_name "$APP"
|
||||
|
||||
[[ -z "$KEY" ]] && dokku_log_fail "No key specified"
|
||||
|
||||
if ! fn-in-array "$KEY" "${VALID_KEYS[@]}" && [[ "$KEY" != dns-provider-* ]]; then
|
||||
dokku_log_fail "Invalid key specified, valid keys include: dns-provider, dns-provider-*, email, graceperiod, server, lego-docker-args"
|
||||
fi
|
||||
|
||||
if [[ -n "$VALUE" ]]; then
|
||||
dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}"
|
||||
fn-plugin-property-write "letsencrypt" "$APP" "$KEY" "$VALUE"
|
||||
else
|
||||
dokku_log_info2_quiet "Unsetting ${KEY}"
|
||||
if [[ "$KEY" == "rev-env-var" ]]; then
|
||||
fn-plugin-property-write "letsencrypt" "$APP" "$KEY" "$VALUE"
|
||||
else
|
||||
fn-plugin-property-delete "letsencrypt" "$APP" "$KEY"
|
||||
if [[ "$KEY" == "enabled" ]]; then
|
||||
fn-plugin-property-destroy "letsencrypt" "$APP"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
16
plugins/letsencrypt/commands
Executable file
16
plugins/letsencrypt/commands
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
[[ " help letsencrypt:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/help-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
case "$1" in
|
||||
help | letsencrypt:help)
|
||||
cmd-letsencrypt-help "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
|
||||
;;
|
||||
|
||||
esac
|
||||
15
plugins/letsencrypt/config
Executable file
15
plugins/letsencrypt/config
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
export LETSENCRYPT_IMAGE=${LETSENCRYPT_IMAGE:="$(awk -F '[ :]' '{print $2}' "${_DIR}/Dockerfile")"}
|
||||
export LETSENCRYPT_IMAGE_VERSION=${LETSENCRYPT_IMAGE_VERSION:="$(awk -F '[ :]' '{print $3}' "${_DIR}/Dockerfile")"}
|
||||
|
||||
export PLUGIN_DISABLE_PULL=${LETSENCRYPT_DISABLE_PULL:=}
|
||||
export PLUGIN_DISABLE_PULL_VARIABLE="LETSENCRYPT_DISABLE_PULL"
|
||||
export PLUGIN_IMAGE=$LETSENCRYPT_IMAGE
|
||||
export PLUGIN_IMAGE_VERSION=$LETSENCRYPT_IMAGE_VERSION
|
||||
|
||||
export LETSENCRYPT_CRON_CMD="$PLUGIN_AVAILABLE_PATH/letsencrypt/cron-job"
|
||||
export LETSENCRYPT_CRON_JOB="@daily $LETSENCRYPT_CRON_CMD"
|
||||
9
plugins/letsencrypt/cron-entries
Executable file
9
plugins/letsencrypt/cron-entries
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
trigger-letsencrypt-cron-entries() {
|
||||
if [[ -f "${DOKKU_LIB_ROOT}/data/letsencrypt/autorenew" ]]; then
|
||||
echo "24 6 * * *;dokku letsencrypt:auto-renew;/var/log/dokku/letsencrypt.log"
|
||||
fi
|
||||
}
|
||||
|
||||
trigger-letsencrypt-cron-entries "$@"
|
||||
4
plugins/letsencrypt/cron-job
Executable file
4
plugins/letsencrypt/cron-job
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PATH=$PATH:/usr/local/bin
|
||||
dokku letsencrypt:auto-renew &>>/var/log/dokku/letsencrypt.log
|
||||
41
plugins/letsencrypt/help-functions
Executable file
41
plugins/letsencrypt/help-functions
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-help() {
|
||||
declare desc="help command"
|
||||
declare CMD="$1"
|
||||
local plugin_name="letsencrypt"
|
||||
local plugin_description="Manage the letsencrypt integration"
|
||||
|
||||
if [[ "$CMD" == "${plugin_name}:help" ]]; then
|
||||
echo -e "Usage: dokku ${plugin_name}[:COMMAND]"
|
||||
echo ''
|
||||
echo "$plugin_description"
|
||||
echo ''
|
||||
echo 'Additional commands:'
|
||||
fn-help-content | sort | column -c2 -t -s,
|
||||
elif [[ $(ps -o command= $PPID) == *"--all"* ]]; then
|
||||
fn-help-content
|
||||
else
|
||||
cat <<help_desc
|
||||
$plugin_name, $plugin_description
|
||||
help_desc
|
||||
fi
|
||||
}
|
||||
|
||||
fn-help-content() {
|
||||
declare desc="return help content"
|
||||
cat <<help_content
|
||||
letsencrypt:active <app>, Verify if letsencrypt is active for an app
|
||||
letsencrypt:auto-renew [<app>], Auto-renew app if renewal is necessary
|
||||
letsencrypt:cleanup <app>, Remove stale certificate directories for app
|
||||
letsencrypt:cron-job [--add --remove], Add or remove a cron job that periodically calls auto-renew.
|
||||
letsencrypt:disable <app>, Disable letsencrypt for an app
|
||||
letsencrypt:enable <app>, Enable or renew letsencrypt for an app
|
||||
letsencrypt:help, Display letsencrypt help
|
||||
letsencrypt:list, List letsencrypt-secured apps with certificate expiry times
|
||||
letsencrypt:revoke <app>, Revoke letsencrypt certificate for app
|
||||
letsencrypt:set <app> <property> (<value>), Set or clear a letsencrypt property for an app
|
||||
help_content
|
||||
}
|
||||
92
plugins/letsencrypt/install
Executable file
92
plugins/letsencrypt/install
Executable file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
fn-letsencrypt-migrate-properties() {
|
||||
declare desc="migrates deprecated config variables to property counterpart"
|
||||
local value
|
||||
|
||||
value=$(plugn trigger config-get-global "DOKKU_LETSENCRYPT_EMAIL" || true)
|
||||
if [[ -n "$value" ]]; then
|
||||
dokku_log_info1 "Migrating deprecated global DOKKU_LETSENCRYPT_EMAIL to letsencrypt email property."
|
||||
fn-plugin-property-write "letsencrypt" "--global" "email" "$value"
|
||||
DOKKU_QUIET_OUTPUT=1 config_unset --global DOKKU_LETSENCRYPT_EMAIL || true
|
||||
fi
|
||||
|
||||
value=$(plugn trigger config-get-global "DOKKU_LETSENCRYPT_GRACEPERIOD" || true)
|
||||
if [[ -n "$value" ]]; then
|
||||
dokku_log_info1 "Migrating deprecated global DOKKU_LETSENCRYPT_GRACEPERIOD to letsencrypt graceperiod property."
|
||||
fn-plugin-property-write "letsencrypt" "--global" "graceperiod" "$value"
|
||||
DOKKU_QUIET_OUTPUT=1 config_unset --global DOKKU_LETSENCRYPT_GRACEPERIOD || true
|
||||
fi
|
||||
|
||||
value=$(plugn trigger config-get-global "DOKKU_LETSENCRYPT_ARGS" || true)
|
||||
if [[ -n "$value" ]]; then
|
||||
dokku_log_info1 "Migrating deprecated global DOKKU_LETSENCRYPT_ARGS to letsencrypt lego-docker-args property."
|
||||
fn-plugin-property-write "letsencrypt" "--global" "lego-docker-args" "$value"
|
||||
DOKKU_QUIET_OUTPUT=1 config_unset --global DOKKU_LETSENCRYPT_ARGS || true
|
||||
fi
|
||||
|
||||
value=$(plugn trigger config-get-global "DOKKU_LETSENCRYPT_SERVER" || true)
|
||||
if [[ -n "$value" ]]; then
|
||||
dokku_log_info1 "Migrating deprecated global DOKKU_LETSENCRYPT_SERVER to letsencrypt server property."
|
||||
fn-plugin-property-write "letsencrypt" "--global" "server" "$value"
|
||||
DOKKU_QUIET_OUTPUT=1 config_unset --global DOKKU_LETSENCRYPT_SERVER || true
|
||||
fi
|
||||
|
||||
for app in $(dokku_apps "false"); do
|
||||
value="$(plugn trigger config-get "$app" DOKKU_LETSENCRYPT_EMAIL || true)"
|
||||
if [[ -n "$value" ]]; then
|
||||
dokku_log_info1 "Migrating deprecated DOKKU_LETSENCRYPT_EMAIL to letsencrypt email property for $app."
|
||||
fn-plugin-property-write "letsencrypt" "$app" "email" "$value"
|
||||
DOKKU_QUIET_OUTPUT=1 config_unset --no-restart "$app" "DOKKU_LETSENCRYPT_EMAIL" || true
|
||||
fi
|
||||
|
||||
value="$(plugn trigger config-get "$app" DOKKU_LETSENCRYPT_GRACEPERIOD || true)"
|
||||
if [[ -n "$value" ]]; then
|
||||
dokku_log_info1 "Migrating deprecated DOKKU_LETSENCRYPT_GRACEPERIOD to letsencrypt graceperiod property for $app."
|
||||
fn-plugin-property-write "letsencrypt" "$app" "graceperiod" "$value"
|
||||
DOKKU_QUIET_OUTPUT=1 config_unset --no-restart "$app" "DOKKU_LETSENCRYPT_GRACEPERIOD" || true
|
||||
fi
|
||||
|
||||
value="$(plugn trigger config-get "$app" DOKKU_LETSENCRYPT_ARGS || true)"
|
||||
if [[ -n "$value" ]]; then
|
||||
dokku_log_info1 "Migrating deprecated DOKKU_LETSENCRYPT_ARGS to letsencrypt lego-docker-args property for $app."
|
||||
fn-plugin-property-write "letsencrypt" "$app" "lego-docker-args" "$value"
|
||||
DOKKU_QUIET_OUTPUT=1 config_unset --no-restart "$app" "DOKKU_LETSENCRYPT_ARGS" || true
|
||||
fi
|
||||
|
||||
value="$(plugn trigger config-get "$app" DOKKU_LETSENCRYPT_SERVER || true)"
|
||||
if [[ -n "$value" ]]; then
|
||||
dokku_log_info1 "Migrating deprecated DOKKU_LETSENCRYPT_SERVER to letsencrypt server property for $app."
|
||||
fn-plugin-property-write "letsencrypt" "$app" "server" "$value"
|
||||
DOKKU_QUIET_OUTPUT=1 config_unset --no-restart "$app" "DOKKU_LETSENCRYPT_SERVER" || true
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
plugin-install() {
|
||||
pull-docker-image() {
|
||||
declare IMAGE="$1"
|
||||
if [[ "$PLUGIN_DISABLE_PULL" == "true" ]]; then
|
||||
echo " ! ${PLUGIN_DISABLE_PULL_VARIABLE} environment variable detected. Not running pull command." 1>&2
|
||||
echo " ! docker pull ${IMAGE}" 1>&2
|
||||
return
|
||||
fi
|
||||
if [[ "$(docker images -q "${IMAGE}" 2>/dev/null)" == "" ]]; then
|
||||
docker pull "${IMAGE}"
|
||||
fi
|
||||
}
|
||||
|
||||
pull-docker-image "${PLUGIN_IMAGE}:${PLUGIN_IMAGE_VERSION}"
|
||||
|
||||
mkdir -p "${DOKKU_LIB_ROOT}/data/letsencrypt"
|
||||
chown -R "${DOKKU_SYSTEM_USER}:${DOKKU_SYSTEM_GROUP}" "${DOKKU_LIB_ROOT}/data/letsencrypt"
|
||||
fn-plugin-property-setup "letsencrypt"
|
||||
fn-letsencrypt-migrate-properties
|
||||
}
|
||||
|
||||
plugin-install "$@"
|
||||
639
plugins/letsencrypt/internal-functions
Executable file
639
plugins/letsencrypt/internal-functions
Executable file
@@ -0,0 +1,639 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/certs/functions"
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/domains/functions"
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/nginx-vhosts/functions"
|
||||
if [[ -f "$PLUGIN_CORE_AVAILABLE_PATH/nginx-vhosts/internal-functions" ]]; then
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/nginx-vhosts/internal-functions"
|
||||
fi
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
fn-letsencrypt-acme-execute-challenge() {
|
||||
declare desc="perform actual ACME validation procedure"
|
||||
declare APP="$1"
|
||||
local FAKE_NGINX_CONF=false
|
||||
local challenge_mode config_dir
|
||||
|
||||
if [[ ! -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then
|
||||
FAKE_NGINX_CONF=true
|
||||
fi
|
||||
|
||||
fn-letsencrypt-create-root "$APP"
|
||||
|
||||
challenge_mode="HTTP-01"
|
||||
dns_provider="$(fn-letsencrypt-computed-dns-provider "$APP")"
|
||||
if [[ -n "$dns_provider" ]]; then
|
||||
challenge_mode="DNS-01"
|
||||
fi
|
||||
|
||||
dokku_log_info1 "Getting letsencrypt certificate for ${APP} via ${challenge_mode}"
|
||||
|
||||
# read arguments from appropriate config file into the config array
|
||||
config_dirs="$(fn-letsencrypt-configure-and-get-dir "$APP")"
|
||||
host_config_dir="$(echo "$config_dirs" | cut -d: -f1)"
|
||||
container_config_dir="$(echo "$config_dirs" | cut -d: -f2)"
|
||||
read -r -a config <"$container_config_dir/config"
|
||||
|
||||
# run letsencrypt as a docker container using "certonly" mode
|
||||
# port 80 of the standalone webserver will be forwarded by the proxy
|
||||
set +e
|
||||
export DOKKU_UID=$(id -u)
|
||||
export DOKKU_GID=$(id -g)
|
||||
mkdir -p "$DOKKU_LIB_ROOT/data/letsencrypt/$APP"
|
||||
docker run --rm \
|
||||
--env-file "$host_config_dir/docker.env" \
|
||||
--user $DOKKU_UID:$DOKKU_GID \
|
||||
-v "$host_config_dir:/certs" \
|
||||
-v "$DOKKU_LIB_ROOT/data/letsencrypt/$APP:/webroot" \
|
||||
"${PLUGIN_IMAGE}:${PLUGIN_IMAGE_VERSION}" \
|
||||
"${config[@]}" run | sed "s/^/ /"
|
||||
|
||||
local exit_code=$?
|
||||
set -e
|
||||
|
||||
if [[ "$FAKE_NGINX_CONF" == "true" ]]; then
|
||||
rm "$DOKKU_ROOT/$APP/nginx.conf"
|
||||
fi
|
||||
|
||||
if [[ $exit_code != 0 ]]; then
|
||||
dokku_log_info1 "Certificate retrieval failed!"
|
||||
return $exit_code
|
||||
fi
|
||||
|
||||
# got certificate
|
||||
dokku_log_info1 "Certificate retrieved successfully."
|
||||
fn-letsencrypt-symlink-certs "$APP" "$container_config_dir"
|
||||
plugn trigger proxy-build-config "$APP"
|
||||
}
|
||||
|
||||
fn-letsencrypt-acme-revoke() {
|
||||
declare desc="perform actual certificate revocation"
|
||||
local APP="$1"
|
||||
|
||||
fn-letsencrypt-create-root "$APP"
|
||||
|
||||
challenge_mode="HTTP-01"
|
||||
dns_provider="$(fn-letsencrypt-computed-dns-provider "$APP")"
|
||||
if [[ -n "$dns_provider" ]]; then
|
||||
challenge_mode="DNS-01"
|
||||
fi
|
||||
|
||||
dokku_log_info1 "Revoking letsencrypt certificate for ${APP} via ${challenge_mode}"
|
||||
local acme_port="$(plugn trigger ports-get-available)"
|
||||
if [[ -z "$acme_port" ]]; then
|
||||
acme_port="$(get_available_port)"
|
||||
fi
|
||||
|
||||
# read arguments from appropriate config file into the config array
|
||||
config_dirs="$(fn-letsencrypt-configure-and-get-dir "$APP")"
|
||||
host_config_dir="$(echo "$config_dirs" | cut -d: -f1)"
|
||||
container_config_dir="$(echo "$config_dirs" | cut -d: -f2)"
|
||||
read -r -a config <"$container_config_dir/config"
|
||||
|
||||
# run letsencrypt as a docker container using "certonly" mode
|
||||
# port 80 of the standalone webserver will be forwarded by the proxy
|
||||
set +e
|
||||
export DOKKU_UID=$(id -u)
|
||||
export DOKKU_GID=$(id -g)
|
||||
mkdir -p "$DOKKU_LIB_ROOT/data/letsencrypt/$APP"
|
||||
docker run --rm \
|
||||
--env-file "$host_config_dir/docker.env" \
|
||||
--user $DOKKU_UID:$DOKKU_GID \
|
||||
-p "$acme_port:$acme_port" \
|
||||
-v "$host_config_dir:/certs" \
|
||||
-v "$DOKKU_LIB_ROOT/data/letsencrypt/$APP:/webroot" \
|
||||
"${PLUGIN_IMAGE}:${PLUGIN_IMAGE_VERSION}" \
|
||||
"${config[@]}" revoke | sed "s/^/ /"
|
||||
|
||||
local exit_code=$?
|
||||
set -e
|
||||
|
||||
# handle return codes
|
||||
if [[ $exit_code == 0 ]]; then
|
||||
# certificate revoked
|
||||
dokku_log_info1 "Certificate revoked successfully."
|
||||
else
|
||||
# error - don't try to link certificates
|
||||
dokku_log_info1 "Certificate revocation failed (code $simple_result)!"
|
||||
return
|
||||
fi
|
||||
|
||||
local domain="$(get_app_domains "$APP" | xargs | awk '{print $1}')"
|
||||
|
||||
# removing the certificate will automatically reconfigure nginx
|
||||
if [[ -z $DOKKU_APP_NAME ]]; then
|
||||
dokku certs:remove "$APP"
|
||||
else
|
||||
dokku certs:remove
|
||||
fi
|
||||
}
|
||||
|
||||
fn-letsencrypt-acme-proxy-disable() {
|
||||
declare desc="disable ACME proxy for an app"
|
||||
local APP="$1"
|
||||
|
||||
local app_root="$DOKKU_ROOT/$APP"
|
||||
local app_config_dir="$app_root/nginx.conf.d"
|
||||
|
||||
dokku_log_info1 "Disabling ACME proxy for $APP..."
|
||||
|
||||
[[ -f "$app_config_dir/letsencrypt.conf" ]] && rm "$app_config_dir/letsencrypt.conf"
|
||||
|
||||
restart_nginx | sed "s/^/ /"
|
||||
}
|
||||
|
||||
fn-letsencrypt-acme-proxy-enable() {
|
||||
declare desc="enable ACME proxy for an app"
|
||||
local APP="$1"
|
||||
|
||||
local app_root="$DOKKU_ROOT/$APP"
|
||||
local app_config_dir="$app_root/nginx.conf.d"
|
||||
|
||||
dokku_log_info1 "Enabling ACME proxy for ${APP}..."
|
||||
|
||||
# ensure the nginx.conf.d directory exists
|
||||
[[ -d "$app_config_dir" ]] || mkdir "$app_config_dir"
|
||||
|
||||
# generate letsencrypt config
|
||||
sigil -f "$PLUGIN_AVAILABLE_PATH/letsencrypt/templates/letsencrypt.conf.sigil" \
|
||||
APP="$APP" \
|
||||
DOKKU_LIB_ROOT="$DOKKU_LIB_ROOT" \
|
||||
>"$app_config_dir/letsencrypt.conf"
|
||||
|
||||
restart_nginx | sed "s/^/ /"
|
||||
}
|
||||
|
||||
fn-letsencrypt-computed-dns-provider() {
|
||||
declare desc="get configured dns provider"
|
||||
declare APP="$1"
|
||||
|
||||
value="$(fn-letsencrypt-dns-provider "$APP")"
|
||||
if [[ -z "$value" ]]; then
|
||||
value="$(fn-letsencrypt-global-dns-provider)"
|
||||
fi
|
||||
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
fn-letsencrypt-global-dns-provider() {
|
||||
declare desc="get configured dns provider"
|
||||
|
||||
fn-plugin-property-get-default "letsencrypt" "--global" "dns-provider" ""
|
||||
}
|
||||
|
||||
fn-letsencrypt-dns-provider() {
|
||||
declare desc="get configured dns provider"
|
||||
declare APP="$1"
|
||||
|
||||
fn-plugin-property-get-default "letsencrypt" "$APP" "dns-provider" ""
|
||||
}
|
||||
|
||||
fn-letsencrypt-computed-lego-docker-args() {
|
||||
declare desc="get configured lego docker args"
|
||||
declare APP="$1"
|
||||
|
||||
value="$(fn-letsencrypt-lego-docker-args "$APP")"
|
||||
if [[ -z "$value" ]]; then
|
||||
value="$(fn-letsencrypt-global-lego-docker-args)"
|
||||
fi
|
||||
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
fn-letsencrypt-global-lego-docker-args() {
|
||||
declare desc="get configured lego docker args"
|
||||
|
||||
fn-plugin-property-get-default "letsencrypt" "--global" "lego-docker-args" ""
|
||||
}
|
||||
|
||||
fn-letsencrypt-lego-docker-args() {
|
||||
declare desc="get configured lego docker args"
|
||||
declare APP="$1"
|
||||
|
||||
fn-plugin-property-get-default "letsencrypt" "$APP" "lego-docker-args" ""
|
||||
}
|
||||
|
||||
fn-letsencrypt-check-email() {
|
||||
declare desc="Check if an e-mail address is provided globally or for the app"
|
||||
declare APP="$1"
|
||||
|
||||
# check we have a valid e-mail address
|
||||
if [[ -z "$(fn-letsencrypt-computed-email "$APP")" ]]; then
|
||||
dokku_log_warn "ERROR: Cannot request a certificate without an e-mail address!"
|
||||
dokku_log_warn " please provide your e-mail address using"
|
||||
dokku_log_warn " dokku letsencrypt:set $APP email <e-mail>"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
fn-letsencrypt-configure-and-get-dir() {
|
||||
declare desc="assemble lego command line arguments and create a config hash directory for them"
|
||||
declare APP="$1"
|
||||
local config config_dir config_hash dns_provider domain_args domains email extra_args cert_timeout key server value
|
||||
|
||||
local app_root="$DOKKU_ROOT/$APP"
|
||||
local le_root="$app_root/letsencrypt"
|
||||
mkdir -p "$DOKKU_ROOT/$APP/letsencrypt/account"
|
||||
|
||||
# build up a string of all certificate-controlling configuration settings.
|
||||
# this will be used to determine the folder name for the account key and certificates
|
||||
|
||||
# get the selected ACME server
|
||||
server="$(fn-letsencrypt-computed-server "$APP")"
|
||||
|
||||
# construct domain arguments
|
||||
domains="$(get_app_domains "$APP")"
|
||||
domain_args=''
|
||||
for domain in $domains; do
|
||||
dokku_log_verbose " - Domain '$domain'" >&2
|
||||
domain_args="$domain_args --domains $domain"
|
||||
done
|
||||
|
||||
# lego --cert.timeout is in seconds and defaults to 30
|
||||
cert_timeout=30
|
||||
email="$(fn-letsencrypt-computed-email "$APP")"
|
||||
extra_args="$(fn-letsencrypt-computed-lego-docker-args "$APP")"
|
||||
config="--pem --accept-tos --cert.timeout $cert_timeout --path /certs --server $server --email $email $extra_args $domain_args"
|
||||
|
||||
dns_provider="$(fn-letsencrypt-computed-dns-provider "$APP")"
|
||||
if [[ -n "$dns_provider" ]]; then
|
||||
config="--dns $dns_provider $config"
|
||||
else
|
||||
config="--http --http.webroot /webroot $config"
|
||||
fi
|
||||
|
||||
config_hash=$(echo "$config" | sha1sum | awk '{print $1}')
|
||||
config_dir="$le_root/certs/$config_hash"
|
||||
mkdir -p "$config_dir"
|
||||
|
||||
rm -f "$config_dir/docker.env"
|
||||
touch "$config_dir/docker.env"
|
||||
if [[ -n "$dns_provider" ]]; then
|
||||
fn-plugin-property-get-all "letsencrypt" "--global" | while read -r line; do
|
||||
[[ -n "$line" ]] || continue
|
||||
key="$(cut -d" " -f1 <<<"$line")"
|
||||
if [[ "$key" == dns-provider-* ]]; then
|
||||
value="$(cut -d" " -f2 <<<"$line")"
|
||||
echo "${key#"dns-provider-"}=$value" >>"$config_dir/docker.env"
|
||||
fi
|
||||
done
|
||||
fn-plugin-property-get-all "letsencrypt" "$APP" | while read -r line; do
|
||||
[[ -n "$line" ]] || continue
|
||||
key="$(cut -d" " -f1 <<<"$line")"
|
||||
if [[ "$key" == dns-provider-* ]]; then
|
||||
value="$(cut -d" " -f2 <<<"$line")"
|
||||
echo "${key#"dns-provider-"}=$value" >>"$config_dir/docker.env"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# ensure the permissions are set correctly on anything that may expose api keys
|
||||
chmod 0755 "$config_dir/docker.env"
|
||||
|
||||
# store config settings
|
||||
echo "$config" >"$config_dir/config"
|
||||
|
||||
# send both host and container path
|
||||
# to respect mapped DOKKU_ROOT when running in a container
|
||||
echo "$DOKKU_HOST_ROOT/$APP/letsencrypt/certs/$config_hash:$config_dir"
|
||||
}
|
||||
|
||||
fn-letsencrypt-cron-job-enabled() {
|
||||
declare desc="Check if the cron plugin is available"
|
||||
|
||||
if [[ ! -f "$PLUGIN_AVAILABLE_PATH/cron/cron-write" ]]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
fn-letsencrypt-cron-job-add() {
|
||||
declare desc="Add auto-renew cronjob to dokku user's crontab"
|
||||
|
||||
touch "${DOKKU_LIB_ROOT}/data/letsencrypt/autorenew"
|
||||
if fn-letsencrypt-cron-job-enabled; then
|
||||
plugn trigger cron-write
|
||||
else
|
||||
crons="$(crontab -l || true)"
|
||||
crons="$(grep -v -F "$LETSENCRYPT_CRON_CMD" <<<"$crons")"
|
||||
printf "%s\n%s\n" "$crons" "$LETSENCRYPT_CRON_JOB" | crontab -
|
||||
fi
|
||||
|
||||
dokku_log_info1 "Added cron job to dokku's crontab."
|
||||
}
|
||||
|
||||
fn-letsencrypt-cron-job-remove() {
|
||||
declare desc="Remove auto-renew cronjob from dokku user's crontab"
|
||||
|
||||
rm -f "${DOKKU_LIB_ROOT}/data/letsencrypt/autorenew"
|
||||
if fn-letsencrypt-cron-job-enabled; then
|
||||
plugn trigger cron-write
|
||||
else
|
||||
crons="$(crontab -l || true)"
|
||||
crons="$(grep -v -F "$LETSENCRYPT_CRON_CMD" <<<"$crons")"
|
||||
printf "%s" "$crons" | crontab -
|
||||
fi
|
||||
dokku_log_info1 "Removed cron job from dokku's crontab."
|
||||
}
|
||||
|
||||
fn-letsencrypt-create-root() {
|
||||
declare desc="Ensure the let's encrypt root directory exists"
|
||||
declare APP="$1"
|
||||
local NGINX_ACCESS_LOG_FORMAT NGINX_ACCESS_LOG_PATH NGINX_ERROR_LOG_PATH
|
||||
|
||||
local app_root="$DOKKU_ROOT/$APP"
|
||||
local le_root="$app_root/letsencrypt"
|
||||
|
||||
mkdir -p "$le_root"
|
||||
|
||||
if [[ ! -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then
|
||||
dokku_log_info1 "Setting temporary site"
|
||||
NGINX_ACCESS_LOG_FORMAT="$(fn-nginx-access-log-format "$APP")"
|
||||
NGINX_ACCESS_LOG_PATH="$(fn-nginx-access-log-path "$APP")"
|
||||
NGINX_ERROR_LOG_PATH="$(fn-nginx-error-log-path "$APP")"
|
||||
if [[ -z "$NGINX_ACCESS_LOG_FORMAT" ]]; then
|
||||
NGINX_ACCESS_LOG_FORMAT="$(fn-nginx-computed-access-log-format "$APP")"
|
||||
fi
|
||||
if [[ -z "$NGINX_ACCESS_LOG_PATH" ]]; then
|
||||
NGINX_ACCESS_LOG_PATH="$(fn-nginx-computed-access-log-path "$APP")"
|
||||
fi
|
||||
if [[ -z "$NGINX_ERROR_LOG_PATH" ]]; then
|
||||
NGINX_ERROR_LOG_PATH="$(fn-nginx-computed-error-log-path "$APP")"
|
||||
fi
|
||||
|
||||
sigil -f "$PLUGIN_AVAILABLE_PATH/letsencrypt/templates/default-nginx.conf.sigil" \
|
||||
DOMAINS="$(get_app_domains "$APP" | xargs)" DOKKU_ROOT="$DOKKU_ROOT" APP="$APP" \
|
||||
NGINX_ACCESS_LOG_FORMAT="$NGINX_ACCESS_LOG_FORMAT" NGINX_ACCESS_LOG_PATH="$NGINX_ACCESS_LOG_PATH" \
|
||||
NGINX_ERROR_LOG_PATH="$NGINX_ERROR_LOG_PATH" \
|
||||
>"$DOKKU_ROOT/$APP/nginx.conf"
|
||||
restart_nginx | sed "s/^/ /"
|
||||
fi
|
||||
}
|
||||
|
||||
fn-letsencrypt-is-autorenew-enabled() {
|
||||
declare desc="check if autorenew is enabled"
|
||||
local enabled=false
|
||||
|
||||
if [[ -f "${DOKKU_LIB_ROOT}/data/letsencrypt/autorenew" ]]; then
|
||||
enabled=true
|
||||
fi
|
||||
|
||||
echo "$enabled"
|
||||
}
|
||||
|
||||
fn-letsencrypt-computed-email() {
|
||||
declare desc="get configured email address"
|
||||
declare APP="$1"
|
||||
|
||||
value="$(fn-letsencrypt-email "$APP")"
|
||||
if [[ -z "$value" ]]; then
|
||||
value="$(fn-letsencrypt-global-email)"
|
||||
fi
|
||||
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
fn-letsencrypt-global-email() {
|
||||
declare desc="get configured email address"
|
||||
|
||||
fn-plugin-property-get-default "letsencrypt" "--global" "email" ""
|
||||
}
|
||||
|
||||
fn-letsencrypt-email() {
|
||||
declare desc="get configured email address"
|
||||
declare APP="$1"
|
||||
|
||||
fn-plugin-property-get-default "letsencrypt" "$APP" "email" ""
|
||||
}
|
||||
|
||||
fn-letsencrypt-enable() {
|
||||
declare APP="$1"
|
||||
local EXIT_CODE=0
|
||||
local domain
|
||||
|
||||
verify_app_name "$APP"
|
||||
|
||||
domain="$(get_app_domains "$APP" | xargs | awk '{print $1}')"
|
||||
if [[ -z "$domain" ]]; then
|
||||
dokku_log_warn "No domains detected for $APP"
|
||||
return 1
|
||||
fi
|
||||
|
||||
dokku_log_info2 "Enabling letsencrypt for $APP"
|
||||
|
||||
fn-letsencrypt-check-email "$APP"
|
||||
fn-letsencrypt-acme-proxy-enable "$APP"
|
||||
fn-letsencrypt-acme-execute-challenge "$APP" || EXIT_CODE=$? # remove ACME proxy even if this fails
|
||||
fn-letsencrypt-acme-proxy-disable "$APP"
|
||||
|
||||
if [[ "$EXIT_CODE" == 0 ]]; then
|
||||
dokku_log_info1 "Done"
|
||||
return
|
||||
fi
|
||||
|
||||
dokku_log_warn "Failed to setup letsencrypt"
|
||||
DOKKU_FAIL_EXIT_CODE="$EXIT_CODE" dokku_log_fail "Check log output for further information on failure"
|
||||
}
|
||||
|
||||
fn-letsencrypt-expiration() {
|
||||
declare desc="prints expiration time"
|
||||
declare APP="$1"
|
||||
|
||||
if [[ -f "$DOKKU_ROOT/$APP/tls/server.letsencrypt.crt" ]]; then
|
||||
date -u -d "$(openssl x509 -in "$DOKKU_ROOT/$APP/tls/server.letsencrypt.crt" -enddate -noout | sed -e "s/^notAfter=//")" "+%s"
|
||||
else
|
||||
date -u -d "$(openssl x509 -in "$DOKKU_ROOT/$APP/tls/server.crt" -enddate -noout | sed -e "s/^notAfter=//")" "+%s"
|
||||
fi
|
||||
}
|
||||
|
||||
fn-letsencrypt-computed-graceperiod() {
|
||||
declare desc="get configured graceperiod"
|
||||
declare APP="$1"
|
||||
local value
|
||||
|
||||
value="$(fn-letsencrypt-graceperiod "$APP")"
|
||||
if [[ -z "$value" ]]; then
|
||||
value="$(fn-letsencrypt-global-graceperiod)"
|
||||
fi
|
||||
|
||||
if [[ -z "$value" ]]; then
|
||||
value="$((60 * 60 * 24 * 30))"
|
||||
fi
|
||||
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
fn-letsencrypt-global-graceperiod() {
|
||||
declare desc="get configured graceperiod"
|
||||
|
||||
fn-plugin-property-get-default "letsencrypt" "--global" "graceperiod" ""
|
||||
}
|
||||
|
||||
fn-letsencrypt-graceperiod() {
|
||||
declare desc="get configured graceperiod"
|
||||
declare APP="$1"
|
||||
|
||||
fn-plugin-property-get-default "letsencrypt" "$APP" "graceperiod" ""
|
||||
}
|
||||
|
||||
fn-letsencrypt-format-timediff() {
|
||||
declare desc="format a time difference in seconds into a human-readable string"
|
||||
local td="$1"
|
||||
local negative_td=0
|
||||
|
||||
if [ "$td" -lt 0 ]; then
|
||||
negative_td=1
|
||||
td=$((-td))
|
||||
fi
|
||||
|
||||
local days=$((td / (24 * 60 * 60)))
|
||||
td=$((td % (24 * 60 * 60)))
|
||||
|
||||
local hours=$((td / (60 * 60)))
|
||||
td=$((td % (60 * 60)))
|
||||
|
||||
local minutes=$((td / 60))
|
||||
local secs=$((td % 60))
|
||||
|
||||
local res=""
|
||||
if [ $days -gt 0 ]; then
|
||||
res="${days}d, "
|
||||
fi
|
||||
|
||||
if [ $hours -gt 0 ]; then
|
||||
res="${res}${hours}h, "
|
||||
fi
|
||||
|
||||
if [ $minutes -gt 0 ]; then
|
||||
res="${res}${minutes}m, "
|
||||
fi
|
||||
|
||||
if [ $secs -gt 0 ]; then
|
||||
res="${res}${secs}s, "
|
||||
fi
|
||||
|
||||
# remove trailing comma
|
||||
res="$(echo "$res" | sed -re 's/, ?$//g')"
|
||||
|
||||
if [[ $negative_td == 1 ]]; then
|
||||
res="${res} ago"
|
||||
fi
|
||||
|
||||
echo "$res"
|
||||
}
|
||||
|
||||
fn-letsencrypt-is-active() {
|
||||
declare desc="outputs true if active, false otherwise"
|
||||
declare APP=$1
|
||||
local domain
|
||||
|
||||
# check if SSL is enabled on per-app level
|
||||
if ! is_ssl_enabled "$APP"; then
|
||||
echo "false"
|
||||
return
|
||||
fi
|
||||
|
||||
domain="$(get_app_domains "$APP" | xargs | awk '{print $1}')"
|
||||
|
||||
# check if certificate is identical to the current let's encrypt certificate by comparing SHA1 hashes
|
||||
local cert_sha1
|
||||
if [[ -f "$DOKKU_ROOT/$APP/tls/server.letsencrypt.crt" ]]; then
|
||||
cert_sha1=$( (cat "$DOKKU_ROOT/$APP/tls/server.letsencrypt.crt" 2>/dev/null) | sha1sum || echo "not_found")
|
||||
else
|
||||
cert_sha1=$( (cat "$DOKKU_ROOT/$APP/tls/server.crt" 2>/dev/null) | sha1sum || echo "not_found")
|
||||
fi
|
||||
|
||||
local le_sha1="not_found"
|
||||
local fileSafeDomain
|
||||
fileSafeDomain="${domain/\*/_}" # wildcards are using *.example.com which have certificates named _.example.com
|
||||
if [[ -f "$DOKKU_ROOT/$APP/letsencrypt/certs/current/certificates/$fileSafeDomain.pem" ]]; then
|
||||
le_sha1=$( (cat "$DOKKU_ROOT/$APP/letsencrypt/certs/current/certificates/$fileSafeDomain.crt" 2>/dev/null) | sha1sum || echo "not_found")
|
||||
elif [[ -f "$DOKKU_ROOT/$APP/letsencrypt/certs/current/fullchain.pem" ]]; then
|
||||
le_sha1=$( (cat "$DOKKU_ROOT/$APP/letsencrypt/certs/current/fullchain.pem" 2>/dev/null) | sha1sum || echo "not_found")
|
||||
fi
|
||||
|
||||
if [[ "$cert_sha1" != "$le_sha1" ]]; then
|
||||
echo "false"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "true"
|
||||
}
|
||||
|
||||
fn-letsencrypt-list-apps-with-expiry() {
|
||||
declare desc="list all letsencrypt-secured apps together with their expiry date"
|
||||
|
||||
# prints a tab-separated list of
|
||||
# * app name
|
||||
# * expiry dates as UNIX timestamp (seconds since epoch)
|
||||
# * selected renewal grace period (in seconds)
|
||||
# * time left on certificate (in seconds)
|
||||
# * time until renewal (in seconds)
|
||||
|
||||
for APP in $(dokku_apps); do
|
||||
if [[ "$APP" == "=====>" ]] || [[ "$APP" == "My" ]] || [[ "$APP" == "Apps" ]]; then continue; fi
|
||||
if [[ "$(fn-letsencrypt-is-active "$APP")" == "true" ]]; then
|
||||
local expiry=$(fn-letsencrypt-expiration "$APP")
|
||||
local grace_period="$(fn-letsencrypt-computed-graceperiod "$APP")"
|
||||
local time_to_expiry=$((expiry - $(date +%s)))
|
||||
local time_to_renewal=$((expiry - grace_period - $(date +%s)))
|
||||
echo -e "$APP\t$expiry\t$grace_period\t$time_to_expiry\t$time_to_renewal"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
fn-letsencrypt-computed-server() {
|
||||
declare desc="get configured server"
|
||||
declare APP="$1"
|
||||
|
||||
value="$(fn-letsencrypt-server "$APP")"
|
||||
if [[ -z "$value" ]]; then
|
||||
value="$(fn-letsencrypt-global-server)"
|
||||
fi
|
||||
|
||||
if [[ -z "$value" ]] || [[ "$value" == "default" ]]; then
|
||||
value="https://acme-v02.api.letsencrypt.org/directory"
|
||||
elif [[ "$value" == "staging" ]]; then
|
||||
value="https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
fi
|
||||
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
fn-letsencrypt-global-server() {
|
||||
declare desc="get configured server"
|
||||
|
||||
fn-plugin-property-get-default "letsencrypt" "--global" "server" ""
|
||||
}
|
||||
|
||||
fn-letsencrypt-server() {
|
||||
declare desc="get configured server"
|
||||
declare APP="$1"
|
||||
|
||||
fn-plugin-property-get-default "letsencrypt" "$APP" "server" ""
|
||||
}
|
||||
|
||||
fn-letsencrypt-symlink-certs() {
|
||||
declare desc="symlink let's encrypt certificates so they can be found by dokku"
|
||||
declare APP="$1" config_dir="$2"
|
||||
|
||||
local app_root="$DOKKU_ROOT/$APP"
|
||||
local le_root="$app_root/letsencrypt"
|
||||
local domain
|
||||
|
||||
dokku_log_info1 "Installing let's encrypt certificates"
|
||||
|
||||
# link the current config directory to 'current'
|
||||
ln -nsf "$config_dir" "$le_root/certs/current"
|
||||
|
||||
# install the let's encrypt certificate for the app
|
||||
unset DOKKU_APP_NAME
|
||||
domain="$(get_app_domains "$APP" | xargs | awk '{print $1}')"
|
||||
local fileSafeDomain
|
||||
fileSafeDomain="${domain/\*/_}" # wildcards are using *.example.com which have certificates named _.example.com
|
||||
dokku certs:add "$APP" "$config_dir/certificates/$fileSafeDomain.pem" "$config_dir/certificates/$fileSafeDomain.key"
|
||||
rm -f "$app_root/tls/server.letsencrypt.crt" "$app_root/tls/server.crt"
|
||||
cp "$config_dir/certificates/$fileSafeDomain.crt" "$app_root/tls/server.letsencrypt.crt"
|
||||
cp "$config_dir/certificates/$fileSafeDomain.crt" "$app_root/tls/server.crt"
|
||||
}
|
||||
5
plugins/letsencrypt/plugin.toml
Normal file
5
plugins/letsencrypt/plugin.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[plugin]
|
||||
description = "Automated installation of let's encrypt TLS certificates"
|
||||
version = "0.20.4"
|
||||
sponsors = ["orca-scan"]
|
||||
[plugin.config]
|
||||
14
plugins/letsencrypt/post-app-clone-setup
Executable file
14
plugins/letsencrypt/post-app-clone-setup
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
trigger-letsencrypt-post-app-clone-setup() {
|
||||
declare desc="removes cert file when setting up a clone"
|
||||
declare trigger="post-app-clone-setup"
|
||||
declare OLD_APP="$1" NEW_APP="$2"
|
||||
local APP_ROOT="$DOKKU_ROOT/$NEW_APP"
|
||||
|
||||
rm -rf "$APP_ROOT/letsencrypt"
|
||||
}
|
||||
|
||||
trigger-letsencrypt-post-app-clone-setup "$@"
|
||||
14
plugins/letsencrypt/post-app-rename-setup
Executable file
14
plugins/letsencrypt/post-app-rename-setup
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
trigger-letsencrypt-post-app-rename-setup() {
|
||||
declare desc="removes cert file when setting up a rename"
|
||||
declare trigger="post-app-clone-setup"
|
||||
declare OLD_APP="$1" NEW_APP="$2"
|
||||
local APP_ROOT="$DOKKU_ROOT/$NEW_APP"
|
||||
|
||||
rm -rf "$APP_ROOT/letsencrypt"
|
||||
}
|
||||
|
||||
trigger-letsencrypt-post-app-rename-setup "$@"
|
||||
14
plugins/letsencrypt/post-delete
Executable file
14
plugins/letsencrypt/post-delete
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
trigger-letsencrypt-post-delete() {
|
||||
declare desc="destroys the letsencrypt properties for a given app"
|
||||
declare trigger="post-delete"
|
||||
declare APP="$1"
|
||||
|
||||
fn-plugin-property-destroy "letsencrypt" "$APP"
|
||||
}
|
||||
|
||||
trigger-letsencrypt-post-delete "$@"
|
||||
16
plugins/letsencrypt/post-domains-update
Executable file
16
plugins/letsencrypt/post-domains-update
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
trigger-letsencrypt-post-domains-update() {
|
||||
declare desc="updates cert file when domains are added or set"
|
||||
declare trigger="post-domains-update"
|
||||
declare APP="$1" ACTION="$2"
|
||||
|
||||
if [[ "$ACTION" == "add" ]] || [[ "$ACTION" == "set" ]]; then
|
||||
dokku_log_warn "Please run dokku letsencrypt:enable to add https support to the new domain"
|
||||
fi
|
||||
}
|
||||
|
||||
trigger-letsencrypt-post-domains-update "$@"
|
||||
6
plugins/letsencrypt/report
Executable file
6
plugins/letsencrypt/report
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-report-single "$@"
|
||||
6
plugins/letsencrypt/subcommands/active
Executable file
6
plugins/letsencrypt/subcommands/active
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-active "$@"
|
||||
6
plugins/letsencrypt/subcommands/auto-renew
Executable file
6
plugins/letsencrypt/subcommands/auto-renew
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-auto-renew "$@"
|
||||
6
plugins/letsencrypt/subcommands/cleanup
Executable file
6
plugins/letsencrypt/subcommands/cleanup
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-cleanup "$@"
|
||||
6
plugins/letsencrypt/subcommands/cron-job
Executable file
6
plugins/letsencrypt/subcommands/cron-job
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-cron-job "$@"
|
||||
6
plugins/letsencrypt/subcommands/default
Executable file
6
plugins/letsencrypt/subcommands/default
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/help-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-help "letsencrypt:help"
|
||||
6
plugins/letsencrypt/subcommands/disable
Executable file
6
plugins/letsencrypt/subcommands/disable
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-disable "$@"
|
||||
6
plugins/letsencrypt/subcommands/enable
Executable file
6
plugins/letsencrypt/subcommands/enable
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-enable "$@"
|
||||
6
plugins/letsencrypt/subcommands/list
Executable file
6
plugins/letsencrypt/subcommands/list
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-list "$@"
|
||||
6
plugins/letsencrypt/subcommands/report
Executable file
6
plugins/letsencrypt/subcommands/report
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-report "$@"
|
||||
6
plugins/letsencrypt/subcommands/revoke
Executable file
6
plugins/letsencrypt/subcommands/revoke
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-revoke "$@"
|
||||
6
plugins/letsencrypt/subcommands/set
Executable file
6
plugins/letsencrypt/subcommands/set
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/command-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-letsencrypt-set "$@"
|
||||
7
plugins/letsencrypt/templates/default-nginx.conf.sigil
Normal file
7
plugins/letsencrypt/templates/default-nginx.conf.sigil
Normal file
@@ -0,0 +1,7 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name {{ .DOMAINS }};
|
||||
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
|
||||
access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }};
|
||||
error_log {{ $.NGINX_ERROR_LOG_PATH }};
|
||||
}
|
||||
8
plugins/letsencrypt/templates/letsencrypt.conf.sigil
Normal file
8
plugins/letsencrypt/templates/letsencrypt.conf.sigil
Normal file
@@ -0,0 +1,8 @@
|
||||
location /.well-known/acme-challenge {
|
||||
# allow every ip address
|
||||
allow all;
|
||||
|
||||
# disable http-auth for /.well-known/acme-challenge
|
||||
auth_basic off;
|
||||
root {{ .DOKKU_LIB_ROOT }}/data/letsencrypt/{{ .APP }};
|
||||
}
|
||||
18
plugins/letsencrypt/uninstall
Executable file
18
plugins/letsencrypt/uninstall
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
trigger-letsencrypt-uninstall() {
|
||||
declare desc="destroys all letsencrypt properties"
|
||||
declare trigger="uninstall"
|
||||
declare PLUGIN="$1"
|
||||
|
||||
if [[ "$PLUGIN" != "$PLUGIN_COMMAND_PREFIX" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
fn-plugin-property-destroy "letsencrypt" "_all_"
|
||||
}
|
||||
|
||||
trigger-letsencrypt-uninstall "$@"
|
||||
1
plugins/letsencrypt/update
Symbolic link
1
plugins/letsencrypt/update
Symbolic link
@@ -0,0 +1 @@
|
||||
install
|
||||
@@ -5,8 +5,4 @@
|
||||
# Procfile for development using the new threaded worker (scheduler, twitter stream and delayed job)
|
||||
cron: node worker.js
|
||||
web: node web.js
|
||||
<<<<<<< HEAD=0
|
||||
worker: node worker.js
|
||||
========0
|
||||
worker: node worker-2.js
|
||||
>>>>>>> 5bb7ec3e2a8f4f6565432a4fc82c92d4a3603d28=0
|
||||
|
||||
Reference in New Issue
Block a user