Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ Your tomcat server must be configured to
* respond with HTTP return code less than 400, on `http://localhost:${LOCAL_HTTP_PORT}/` (default port 8080).

If successful, the certificate files will be stored here:
* Certificate file: `/certs/${DOMAIN}/cert.pem`
* Certificate private key file: `/certs/${DOMAIN}/privkey.pem`
* Certificate chain file: `/certs/${DOMAIN}/fullchain.pem`
* Certificate file: `${CERT_DIR}/${DOMAIN}/cert.pem`
* Certificate private key file: `${CERT_DIR}/${DOMAIN}/privkey.pem`
* Certificate chain file: `${CERT_DIR}/${DOMAIN}/fullchain.pem`

# Configuration at runtime

Expand All @@ -63,8 +63,20 @@ If successful, the certificate files will be stored here:
* `ENABLE_LETSENCRYPT` - if set to `false` the letsencrypt process is not started
* `CREATE_SELFSIGNED` - if set to `false` no selfsigned certifcate is generated at start up.
Depending on your setup this might result in failing startup of the tomcat connectors
* Persistence: Your certs are stored inside your container at `CERT_DIR` (default: `/certs/`), so you might want to
persist this folder.
* `DEHYDRATED_BASEDIR` - defaults to `/dehydrated` for compatibility with letsencrypt-tomcat <= 0.40.
* `CERT_DIR` - if `DEHYDRATED_BASEDIR` is set, defaults to `$DEHYDRATED_BASEDIR/certs`, which is the default of dehydrated. If `DEHYDRATED_BASEDIR` is not set, defaults to `/certs` to be compatible with older letsencrypt-tomcat releases <=0.4.0.
* `DEHYDRATED_WELLKNOWN` - path where dehydrated will place ACME challenge files. Should usually be the document root of a webserver with `/.well-known/acme-challenge` appended.

Note: if you want to save certificates and accounts in persistent storage it is highly recommended to set `DEHYDRATED_BASEDIR` env variable as described below.

`DEHYDRATED_BASEDIR` and `CERT_DIR` interact:
* default (<=0.4.0) if `DEHYDRATED_BASEDIR` is not set:
* `DEHYDRATED_BASEDIR="/dehydrated" CERT_DIR="/certs"`
* `/dehydrated` is not stored in persistent storage and will be deleted with the container (including the letsencrypt account)
* recommended (>0.4.0):
* set `DEHYDRATED_BASEDIR="/certs/dehydrated"`. This will set `CERT_DIR="$DEHYDRATED_BASEDIR/certs"`. This allows all the certificates and dehydrated state (most importantly, accounts) to be stored in one directory, usually a volume mounted at `/certs`.

It is possible to set environment variables in any place Docker supports, and will make them set in the container. This is: in a Dockerfile, as run parameters, as docker-compose.yml configuration, or in an .env file.

# Run Examples

Expand Down Expand Up @@ -94,4 +106,4 @@ docker build -t schnatterer/letsencrypt-tomcat .
docker build -t schnatterer/letsencrypt-tomcat:standalone --file=examples/standalone/Dockerfile .
docker build -t schnatterer/letsencrypt-tomcat:spring-boot --file=examples/spring-boot/Dockerfile .
docker build -t schnatterer/letsencrypt-tomcat:embedded-tomcat --file=examples/embedded-tomcat/Dockerfile .
```
```
5 changes: 3 additions & 2 deletions etc/dehydrated/config
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# See https://github.com/dehydrated-io/dehydrated/blob/master/docs/examples/config

WELLKNOWN="/static/.well-known/acme-challenge"
BASEDIR="/dehydrated"
WELLKNOWN="$DEHYDRATED_WELLKNOWN"
BASEDIR="$DEHYDRATED_BASEDIR"
CERTDIR="$CERT_DIR"
1 change: 1 addition & 0 deletions examples/embedded-tomcat/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ RUN mvn package
FROM letsencrypt-tomcat as aggregator
# Copy letsencrypt-related stuff
RUN mv /letsencrypt /dist
ENV DEHYDRATED_BASEDIR="/certs/dehydrated"

# Copy Libraries: Apache Portable Runtime (APR) and JNI wrappers for APR used by Tomcat (libtcnative)
RUN cp -r /lib/* /dist/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class Main {

private static final int HTTPS_PORT = 8443;
public static final String DOMAIN = System.getenv("DOMAIN");
public static final String CERT_FOLDER = "/certs/";
public static final String CERT_FOLDER = System.getenv("CERT_DIR");
public static final String PK = CERT_FOLDER + DOMAIN + "/privkey.pem";
public static final String CRT = CERT_FOLDER + DOMAIN + "/cert.pem";
public static final String CA = CERT_FOLDER + DOMAIN + "/fullchain.pem";
Expand Down
1 change: 1 addition & 0 deletions examples/spring-boot/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ RUN mvn package
FROM letsencrypt-tomcat as aggregator
# Copy letsencrypt-related stuff
RUN mv /letsencrypt /dist
ENV DEHYDRATED_BASEDIR="/certs/dehydrated"

# Copy Libraries: Apache Portable Runtime (APR) and JNI wrappers for APR used by Tomcat (libtcnative)
RUN cp -r /lib/* /dist/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ server.http.port=8080
# Needed so the letsencrypt challenge is served by tomcat
spring.resources.staticLocations=file:/static

server.ssl.certificateKeyFile=/certs/${DOMAIN}/privkey.pem
server.ssl.certificateFile=/certs/${DOMAIN}/cert.pem
server.ssl.certificateChainFile=/certs/${DOMAIN}/fullchain.pem
server.ssl.certificateKeyFile=${certdir}/${DOMAIN}/privkey.pem
server.ssl.certificateFile=${certdir}/${DOMAIN}/cert.pem
server.ssl.certificateChainFile=${certdir}/${DOMAIN}/fullchain.pem
11 changes: 4 additions & 7 deletions examples/standalone/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,14 @@ FROM schnatterer/letsencrypt-tomcat:${LETSENCRYPT_TOMCAT_VERSION} as letsencrypt
FROM letsencrypt-tomcat as aggregator
# Copy letsencrypt-related stuff
RUN mv /letsencrypt /dist
ENV DEHYDRATED_BASEDIR="/certs/dehydrated"

# Copy reloding connector, so tomcat can automatically reload certificates at runtime
RUN mkdir -p /dist/opt/bitnami/tomcat/lib/
RUN cp -r /tomcat-reloading-connector/* /dist/opt/bitnami/tomcat/lib/

# Make standalone tomcat serve static files in directories used for letsencrypt challenges
RUN mkdir -p /dist/opt/bitnami/tomcat/webapps/ROOT/.well-known/acme-challenge
# It would be simpler to link ROOT -> static but it seems that tomcat does not follow symlinks when serving static content
# So just do it the other way round
RUN rm -rf /dist/static/.well-known/acme-challenge
RUN ln -s /opt/bitnami/tomcat/webapps/ROOT/.well-known/acme-challenge /dist/static/.well-known/acme-challenge
# set directory where dehydrated will create ACME challenge files
ENV DEHYDRATED_WELLKNOWN="/opt/bitnami/tomcat/webapps/ROOT/.well-known/acme-challenge"

# Copy examples/standalone tomcat config
COPY examples/standalone/tomcat /dist/opt/bitnami/tomcat/
Expand All @@ -31,4 +28,4 @@ FROM tomcat
VOLUME /certs/
COPY --from=aggregator --chown=1001:0 /dist /
ENTRYPOINT [ "/meta-entrypoint.sh", "/opt/bitnami/scripts/tomcat/entrypoint.sh" ]
CMD [ "/opt/bitnami/scripts/tomcat/run.sh" ]
CMD [ "/opt/bitnami/scripts/tomcat/run.sh" ]
6 changes: 3 additions & 3 deletions examples/standalone/tomcat/conf/server.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@
maxThreads="150" SSLEnabled="true" >
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig>
<Certificate certificateKeyFile="/certs/${domain}/privkey.pem"
certificateFile="/certs/${domain}/cert.pem"
certificateChainFile="/certs/${domain}/fullchain.pem"
<Certificate certificateKeyFile="${certdir}/${domain}/privkey.pem"
certificateFile="${certdir}/${domain}/cert.pem"
certificateChainFile="${certdir}/${domain}/fullchain.pem"
type="RSA" />
</SSLHostConfig>
</Connector>
Expand Down
13 changes: 9 additions & 4 deletions meta-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ CREATE_SELFSIGNED=${CREATE_SELFSIGNED:-'true'}
STAGING=${STAGING:-'false'}
NO_COLOR=${NO_COLOR:-''}
SELF_SIGNED_CERT_VALIDITY_DAYS=${SELF_SIGNED_CERT_VALIDITY_DAYS:-30}
CERT_DIR=${CERT_DIR:-"/certs/"}
export JAVA_OPTS="-Djava.awt.headless=true -XX:+UseG1GC -Dfile.encoding=UTF-8 -Ddomain=${DOMAIN}"
: "${CERT_DIR:="${DEHYDRATED_BASEDIR}/certs"}"
: "${DEHYDRATED_BASEDIR:="/dehydrated"}"
: "${DEHYDRATED_WELLKNOWN:="/static"}"
export CERT_DIR DEHYDRATED_BASEDIR DEHYDRATED_WELLKNOWN
export JAVA_OPTS="-Djava.awt.headless=true -XX:+UseG1GC -Dfile.encoding=UTF-8 -Dcertdir=${CERT_DIR} -Ddomain=${DOMAIN}"


function main() {
Expand Down Expand Up @@ -68,6 +71,8 @@ createSelfSignedCert() {
}

function fetchCerts() {
mkdir -vp "$DEHYDRATED_BASEDIR"
mkdir -vp "$DEHYDRATED_WELLKNOWN"

if [[ "${STAGING}" == "true" ]]; then
echo 'CA="https://acme-staging-v02.api.letsencrypt.org/directory"' >> /etc/dehydrated/config
Expand All @@ -83,7 +88,7 @@ function fetchCerts() {

while [[ "${SIG_INT_RECEIVED}" == 'false' ]]; do
green "Fetching certificates"
dehydrated --domain ${DOMAIN} --cron --accept-terms --out ${CERT_DIR} && exitCode=$? || exitCode=$?
dehydrated --domain ${DOMAIN} --cron --accept-terms && exitCode=$? || exitCode=$?
if [[ "${exitCode}" > 0 ]]; then
red "Fetching certificates failed"
fi
Expand Down Expand Up @@ -113,4 +118,4 @@ RED='\033[0;31m'
DEFAULT_COLOR='\033[0m'


main "$@"
main "$@"