From eee4d163b84c5801dea4089136521ce87d1826db Mon Sep 17 00:00:00 2001 From: Asharas Date: Wed, 2 Dec 2020 21:42:54 +0100 Subject: [PATCH] Add nginx and supervisor to mimic production setup --- .dockerignore | 3 +- Dockerfile-nginx | 67 +++++++++++++++++ Dockerfile-nginx-alpine | 65 ++++++++++++++++ README.md | 128 +++++++++++++++++++++++++++---- docker-compose.yml | 11 ++- docker-entrypoint.sh | 163 ++++++++++++++++++++++++++++++++++++++++ nginx/Dockerfile | 50 ++++++++++++ nginx/Dockerfile-alpine | 64 ++++++++++++++++ nginx/startup.sh | 2 + nginx/supervisord.conf | 28 +++++++ supervisord.conf | 49 ++++++++++++ traefik2.yml | 33 +++++--- 12 files changed, 637 insertions(+), 26 deletions(-) create mode 100644 Dockerfile-nginx create mode 100644 Dockerfile-nginx-alpine create mode 100755 docker-entrypoint.sh create mode 100644 nginx/Dockerfile create mode 100644 nginx/Dockerfile-alpine create mode 100644 nginx/startup.sh create mode 100644 nginx/supervisord.conf create mode 100644 supervisord.conf diff --git a/.dockerignore b/.dockerignore index 6c154b2..31fb029 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,4 +6,5 @@ cryptpad/.git customize data docker-compose.yml -Dockerfile +traefik2.yml +Dockerfile* diff --git a/Dockerfile-nginx b/Dockerfile-nginx new file mode 100644 index 0000000..8188212 --- /dev/null +++ b/Dockerfile-nginx @@ -0,0 +1,67 @@ +# Multistage build to reduce image size and increase security + +FROM node:12-buster-slim AS build + +# Install requirements to clone repository and install deps +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -yq git \ + && npm install -g bower + +# Get cryptpad from repository submodule +COPY cryptpad /cryptpad + +WORKDIR /cryptpad + +# Install dependencies +RUN npm install --production \ + && npm install -g bower \ + && bower install --allow-root + +# Create actual cryptpad image +FROM node:12-buster-slim + +RUN set -x \ + # Create users and groups for cryptpad + && groupadd -r -g 4001 cryptpad \ + && useradd -rMs /bin/false -d /dev/null -u 4001 -g 4001 cryptpad \ + \ + # Install packages + && apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends nginx supervisor openssl zlib1g \ + && rm -rf /var/lib/apt/lists/* /etc/nginx + +# Copy nginx conf from official image +COPY --from=nginx:latest /etc/nginx /etc/nginx + +# Debian uses www-data user instead of nginx +RUN sed -i 's@\(^user\).*[^;]@\1 www-data@' /etc/nginx/nginx.conf + +# Copy cryptpad with installed modules +COPY --from=build --chown=cryptpad /cryptpad /cryptpad + +# Copy supervisord conf file +COPY supervisord.conf /etc/supervisord.conf + +# Copy docker-entrypoint.sh script +COPY docker-entrypoint.sh /docker-entrypoint.sh + +# Set workdir to cryptpad +WORKDIR /cryptpad + +# Create directories +RUN mkdir blob block customize data datastore \ + && chown cryptpad:cryptpad blob block customize data datastore + +# Volumes for data persistence +VOLUME /cryptpad/blob \ + /cryptpad/block \ + /cryptpad/customize \ + /cryptpad/data \ + /cryptpad/datastore + +# Ports +EXPOSE 80 443 + +ENTRYPOINT ["/bin/sh", "/docker-entrypoint.sh"] + +CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"] diff --git a/Dockerfile-nginx-alpine b/Dockerfile-nginx-alpine new file mode 100644 index 0000000..3138393 --- /dev/null +++ b/Dockerfile-nginx-alpine @@ -0,0 +1,65 @@ +# Multistage build to reduce image size and increase security + +FROM node:12-alpine AS build + +# Install requirements to clone repository and install deps +RUN apk add --no-cache git \ + && npm install -g bower + +# Get cryptpad from repository submodule +COPY cryptpad /cryptpad + +WORKDIR /cryptpad + +# Install dependencies +RUN npm install --production \ + && npm install -g bower \ + && bower install --allow-root + +# Create actual cryptpad image +FROM node:12-alpine + +RUN set -x \ + # Create users and groups for nginx and cryptpad + && addgroup -g 4001 -S cryptpad \ + && adduser -u 4001 -S -D -G cryptpad -H -h /dev/null cryptpad \ + \ + # Create needed dir for nginx pid + && mkdir -p /var/run/nginx \ + \ + # Install packages + && apk add supervisor nginx openssl zlib pcre \ + && rm -rf /etc/nginx + +# Copy nginx conf from official image +COPY --from=nginx:latest /etc/nginx /etc/nginx + +# Copy cryptpad with installed modules +COPY --from=build --chown=cryptpad /cryptpad /cryptpad + +# Copy supervisord conf file +COPY supervisord.conf /etc/supervisord.conf + +# Copy docker-entrypoint.sh script +COPY docker-entrypoint.sh /docker-entrypoint.sh + +# Set workdir to cryptpad +WORKDIR /cryptpad + +# Create directories +RUN mkdir blob block customize data datastore \ + && chown cryptpad:cryptpad blob block customize data datastore + +# Volumes for data persistence +VOLUME /cryptpad/blob \ + /cryptpad/block \ + /cryptpad/customize \ + /cryptpad/data \ + /cryptpad/datastore + +# Ports +EXPOSE 80 443 + +ENTRYPOINT ["/bin/sh", "/docker-entrypoint.sh"] + +CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"] diff --git a/README.md b/README.md index baa6519..f54ddc4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# CryptPad docker +# CryptPad docker This repository has been created as part of an ongoing effort to separate docker from [the CryptPad platform repo](https://github.com/xwiki-labs/cryptpad). @@ -7,22 +7,122 @@ The officially recommended deployment method is to use the `example.nginx.conf` Docker images and their supporting configuration files are provided as a community effort by those using them, with support provided by the core development team on a _best-effort_ basis. Keep in mind that the core team neither uses nor tests Docker images, so your results may vary. ## Migration -Please see the [migration guide](MIGRATION.md) for further information on switching to this repository. +Please see the [migration guide](MIGRATION.md) for further information on switching to this repository. -## Usage +## General notices +* **Important**: New images tagged `nginx` and `nginx-alpine` have been added to this repository. The `docker-compose.yml` and `traefik2.yml` examples files have been modified to use the `nginx` image because the legacy versions didn't provide Content-Security-Policy headers which is a requirement to properly expose CryptPad to the internet. +It is recommended to use the `promasu/cryptpad:nginx` image (see [Standalone Cryptpad](#cryptpad-proxied-by-nginx)). -### General notices -* Mounted files and folders have to be owned by userid 4001. It is possible you have to run -`sudo chown -R 4001:4001 filename` +* Mounted files and folders for CryptPad have to be owned by userid 4001. It is possible you have to run `sudo chown -R 4001:4001 filename`. If your container engine uses namespacing to shift uids and gids in the containers, you need correct the uid and gid or to run the command from within the container. -### Dockerfile +## Standalone CryptPad +Tags: `latest` and `alpine` +Files: `Dockerfile` and `Dockerfile-alpine` -* Run: `docker run -d -p 3000:3000 -p 3001:3001 promasu/cryptpad` -* Run with customizations: `docker run -d -p 3000:3000 -p 3001:3001 -v ${PWD}/customize:/cryptpad/customize promasu/cryptpad` -* Run with configuration: `docker run -d -p 3000:3000 -p 3001:3001 -v ${PWD}/config.js:/cryptpad/config/config.js promasu/cryptpad` -* Run with persistent data: `docker run -d -p 3000:3000 -p 3001:3001 -v ${PWD}/data/blob:/cryptpad/blob -v ${PWD}/data/block:/cryptpad/block -v ${PWD}/customize:/cryptpad/customize -v ${PWD}/data/data:/cryptpad/data -v ${PWD}/data/files:/cryptpad/datastore promasu/cryptpad` +This image provides CryptPad served by Node without certs or CSP. It is up to you to deploy it behind a reverse proxy as per CryptPad's devs recommendations (see [Opening CryptPad to the Internet](https://github.com/xwiki-labs/cryptpad/wiki/Installation-guide#opening-cryptpad-to-the-internet)). +It is kept in order to avoid breaking existing deployment. +If you already have a reverse proxy with CSP properly configured, you can keep using this image. +Otherwise you should use the `nginx` or `nginx-alpine` versions. -### Docker-compose +#### Usage -* Run: `docker-compose up` -* Run with traefik2 labels: `docker-compose -f docker-compose.yml -f traefik2.yml up` +##### Run: +``` +docker run -d -p 3000:3000 -p 3001:3001 promasu/cryptpad +``` + +##### Run with customizations: +``` +docker run -d -p 3000:3000 -p 3001:3001 -v ${PWD}/customize:/cryptpad/customize promasu/cryptpad +``` + +##### Run with configuration: +``` +docker run -d -p 3000:3000 -p 3001:3001 -v ${PWD}/config.js:/cryptpad/config/config.js promasu/cryptpad +``` + +##### Run with persistent data: +``` +docker run -d -p 3000:3000 -p 3001:3001 -v ${PWD}/data/blob:/cryptpad/blob \ +-v ${PWD}/data/block:/cryptpad/block -v ${PWD}/customize:/cryptpad/customize \ +-v ${PWD}/data/data:/cryptpad/data -v ${PWD}/data/files:/cryptpad/datastore promasu/cryptpad +``` + +## CryptPad proxied by Nginx +Tags: `nginx` and `nginx-alpine` +Files: `Dockerfile-nginx` and `Dockerfile-nginx-alpine` + +This image provides CryptPad proxied by Nginx. It offers more configuration options than the standalone version (but will not run if the bare minimum options aren't set) and lets Nginx handle the different HTTP headers like CSP. +The `docker-entrypoint.sh` script copies Nginx configuration from the example provided in CryptPad repository (see file [`example.nginx.conf`](https://github.com/xwiki-labs/cryptpad/blob/main/docs/example.nginx.conf)) and substitutes the deployment environment variables. + +* With minimum settings, Nginx will listen for unencrypted HTTP2 requests on port 80. Most browsers won't be able to connect without a reverse proxy to upgrade the connection (also if you use Traefik, please read `docker-compose.yml` comment above this option). +To disable HTTP2 set the environment variable `CPAD_HTTP2_DISABLE` to `true`. + +* If you'd prefer Nginx to terminate TLS connections, provide a fullchain certificate and a key and set `CPAD_TLS_CERT` and `CPAD_TLS_KEY`. Both variables MUST be set for the entrypoint script to set paths in config. You can also provide Diffie-Hellman parameters with `CPAD_TLS_DHPARAM`. If no `dhparam.pem` file is provided, it will be generated upon container start. Beware that this is a time consuming step. + +#### Environment variables + +| Variables | Description | Required | Default | +| --- | --- | --- | --- | +| `CPAD_MAIN_DOMAIN` | CryptPad main domain FQDN | Yes | None | +| `CPAD_SANDBOX_DOMAIN` | CryptPad sandbox subdomain FQDN | Yes | None | +| `CPAD_API_DOMAIN` | CryptPad API subdomain FQDN| No | `$CPAD_MAIN_DOMAIN` | +| `CPAD_FILES_DOMAIN` | CryptPad files subdomain FQDN | No | `$CPAD_MAIN_DOMAIN` | +| `CPAD_TRUSTED_PROXY` | Trusted proxy address or CIDR | No | None | +| `CPAD_REALIP_HEADER`| Header to get client IP from (`X-Real-IP` or `X-Forwarded-For`) | No | `X-Real-IP` | +| `CPAD_REALIP_RECURSIVE`| Instruct Nginx to perform a recursive search to find client's real IP (`on`/`off`) (see [ngx_http_realip_module](https://nginx.org/en/docs/http/ngx_http_realip_module.html)) | No | `off` | +| `CPAD_TLS_CERT` | Path to TLS certificate file | No | None | +| `CPAD_TLS_KEY` | Path to TLS private key file | No | None | +| `CPAD_TLS_DHPARAM` | Path to Diffie-Hellman parameters file | No | `/etc/nginx/dhparam.pem` | +| `CPAD_HTTP2_DISABLE` | Disable HTTP2, mostly meant for test purpose | No | `false` | + +#### Usage + +##### Run with minimal settings: +``` +docker run -d -e "CPAD_MAIN_DOMAIN=example.com" -e "CPAD_SANDBOX_DOMAIN=sandbox.example.com" -p 80:80 promasu/cryptpad:nginx +``` + +##### Run with configuration: +``` +docker run -d -e "CPAD_MAIN_DOMAIN=example.com" -e "CPAD_SANDBOX_DOMAIN=sandbox.example.com" \ +-v ${PWD}/dhparam.pem:/path/to/dhparam.pem -p 80:80 promasu/cryptpad:nginx +``` + +##### Run with TLS: +``` +docker run -d -e "CPAD_MAIN_DOMAIN=example.com" -e "CPAD_SANDBOX_DOMAIN=sandbox.example.com" \ +-e "CPAD_TLS_CERT=/path/to/cert.pem" -e "CPAD_TLS_KEY=/path/to/key.pem" \ +-e "CPAD_TLS_DHPARAM=/path/to/dhparam.pem" -v ${PWD}/cert.pem:/path/to/cert.pem \ +-v ${PWD}/key.pem:/path/to/key.pem -v ${PWD}/dhparam.pem:/path/to/dhparam.pem \ +-p 443:443 promasu/cryptpad:nginx +``` + +##### Run behind a reverse proxy +``` +docker run -d -e "CPAD_MAIN_DOMAIN=example.com" -e "CPAD_SANDBOX_DOMAIN=sandbox.example.com" \ +-e "CPAD_TRUSTED_PROXY=10.0.0.0/8" -e "CPAD_REALIP_HEADER=X-Forwarded-For" \ +-e "CPAD_REALIP_RECURSIVE=on" -p 80:80 promasu/cryptpad:nginx +``` + +##### Run with customizations: +``` +docker run -d -e "CPAD_MAIN_DOMAIN=example.com" -e "CPAD_SANDBOX_DOMAIN=sandbox.example.com" \ +-v ${PWD}/customize:/cryptpad/customize -p 80:80 promasu/cryptpad:nginx +``` + +##### Run with persistent data: +``` +docker run -d -e "CPAD_MAIN_DOMAIN=example.com" -e "CPAD_SANDBOX_DOMAIN=sandbox.example.com" \ +-v ${PWD}/data/blob:/cryptpad/blob -v ${PWD}/data/block:/cryptpad/block \ +-v ${PWD}/customize:/cryptpad/customize -v ${PWD}/data/data:/cryptpad/data \ +-v ${PWD}/data/files:/cryptpad/datastore -p 80:80 promasu/cryptpad:nginx +``` + +#### Docker-compose + +##### Run: +`docker-compose up` + +##### Run with traefik2 labels: +`docker-compose -f docker-compose.yml -f traefik2.yml up` diff --git a/docker-compose.yml b/docker-compose.yml index 700d7a6..3ce6862 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,25 @@ --- -version: '2' +version: '3.8' services: cryptpad: image: "promasu/cryptpad:latest" hostname: cryptpad + environment: + - CPAD_MAIN_DOMAIN=example.com + - CPAD_SANDBOX_DOMAIN=sandbox.example.com + # Traefik can't use HTTP2 to communicate with cryptpat_websocket + # A workaroung is disabling HTTP2 in Nginx + - CPAD_HTTP2_DISABLE=true + volumes: - ./data/blob:/cryptpad/blob - ./data/block:/cryptpad/block - ./customize:/cryptpad/customize - - ./data/config.js:/cryptpad/config/config.js - ./data/data:/cryptpad/data - ./data/files:/cryptpad/datastore + - ./data/config.js:/cryptpad/config/config.js ports: - "3000:3000" diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..0a02703 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,163 @@ +#/bin/sh + +## Required vars +# CPAD_MAIN_DOMAIN +# CPAD_SANDBOX_DOMAIN +# +## Optional vars +# CPAD_API_DOMAIN +# CPAD_FILES_DOMAIN +# +## Both these vars must be set in order for nginx to terminate TLS +# CPAD_TLS_CERT +# CPAD_TLS_KEY +## If dhparam.pem file is absent it will be generated +# CPAD_TLS_DHPARAM +# +# CPAD_TRUSTED_PROXY +# CPAD_REALIP_HEADER +# CPAD_REALIP_RECURSIVE +# +## Testing vars, may be removed later +# CPAD_HTTP2_DISABLE="true" +# + +set -e + +CPAD_HOME="/cryptpad" + +# Since Nginx configuration is copied from the official image we need to +# correct some stuff +# Fix log path +sed -i -e "s@\(error_log\) */.* \(.*;\)@\1 /dev/stderr \2@" \ + -e "s@\(access_log\) */.* \(.*;\)@\1 /dev/stdout \2@" \ + ${CPAD_NGINX_CONF:=/etc/nginx/nginx.conf} + +# Remove nginx default enabled conf +if [ -f /etc/nginx/conf.d/default.conf ]; then + rm /etc/nginx/conf.d/default.conf +fi + +# Test if nginx config file already exists (eg: docker swarm config) +# if absent, copy example and apply corrections +if [ ! -f "${CPAD_NGINX_CPAD_CONF:=/etc/nginx/conf.d/cryptpad.conf}" ]; then + + # Copy nginx config example from Cryptpad + cp $CPAD_HOME/docs/example.nginx.conf $CPAD_NGINX_CPAD_CONF + + # Set domains + if [ -z "${CPAD_MAIN_DOMAIN:-}" ]; then + echo "Error: No main domain specified" + exit 1 + else + sed -i "s@your-main-domain.com@$CPAD_MAIN_DOMAIN@g" $CPAD_NGINX_CPAD_CONF + fi + + if [ -z "${CPAD_SANDBOX_DOMAIN:-}" ]; then + echo "Error: No sandbox domain specified" + exit 1 + else + sed -i "s@your-sandbox-domain.com@$CPAD_SANDBOX_DOMAIN@g" $CPAD_NGINX_CPAD_CONF + fi + + if [ -z "${CPAD_API_DOMAIN}" ]; then + sed -i "s@api.$CPAD_MAIN_DOMAIN@\$\{main_domain\}@" $CPAD_NGINX_CPAD_CONF + fi + + if [ -z "${CPAD_FILES_DOMAIN}" ]; then + sed -i "s@files.$CPAD_MAIN_DOMAIN@\$\{main_domain\}@" $CPAD_NGINX_CPAD_CONF + fi + + # Change nginx document root + sed -i "s@\(root\) */.*\([^;]\)@\1 $CPAD_HOME@" $CPAD_NGINX_CPAD_CONF + + # Wether or not Nginx should terminate TLS (defaults to true) + if [ -n "$CPAD_TLS_CERT" \ + -a -n "$CPAD_TLS_KEY" ]; then + + # If cert is present, set path. If not, exit with error + if [ -f "$CPAD_TLS_CERT" ]; then + sed -i "s@\( *ssl_certificate[^_key] *\).*[^;]@\1$CPAD_TLS_CERT@" $CPAD_NGINX_CPAD_CONF + else + echo "Error: Missing TLS certificate file" + exit 1 + fi + + # If key is present, set path. If not, exit with error + if [ -f "$CPAD_TLS_KEY" ]; then + sed -i "s@\( *ssl_certificate_key *\).*[^;]@\1$CPAD_TLS_KEY@" $CPAD_NGINX_CPAD_CONF + else + echo "Error: Missing TLS key file" + exit 1 + fi + + # This option is only useful for OCSP stapling which Cryptpad doesn't use + # so we'll comment it to avoid errors. + sed -i "s@\(ssl_trusted_certificate\)@#\1@" $CPAD_NGINX_CPAD_CONF + + # If no DH parameters are provided, generate them + if [ ! -f "${CPAD_TLS_DHPARAM:=/etc/nginx/dhparam.pem}" ]; then + # Generate DH parameters + openssl dhparam -out $CPAD_TLS_DHPARAM 4096 + fi + + # If no TLS termination + else + # Make Nginx listen on 80 in plaintext + # and comment out all ssl related options + sed -i -e "s@\(^.*\) \+443 ssl\(.*$\)@\1 80\2@" \ + -e "s@[^#]ssl_@ #ssl_@g" $CPAD_NGINX_CPAD_CONF + fi + + # Should Nginx use http_realip_module + if [ -n "${CPAD_TRUSTED_PROXY:=}" ]; then + # Set trusted proxy + sed -i -e "/listen/ G" \ + -e "/listen/ a \ \ # Set trusted proxy and header containing real client IP" \ + -e "/listen/ a \ \ set_real_ip_from $CPAD_TRUSTED_PROXY;" $CPAD_NGINX_CPAD_CONF + + # Set header to get real client IP from + if [ -n "${CPAD_REALIP_HEADER:-}" ]; then + sed -i "/set_real_ip_from/ a \ \ real_ip_header $CPAD_REALIP_HEADER;" $CPAD_NGINX_CPAD_CONF + fi + + # Should Nginx perform a recursive search to get real client IP + if [ -n "${CPAD_REALIP_RECURSIVE:-}" ]; then + sed -i "/set_real_ip_from/ a \ \ real_ip_recursive $CPAD_REALIP_RECURSIVE;" $CPAD_NGINX_CPAD_CONF + fi + fi + + # Should nginx use HTTP2 (defaults to false) + if [ "${CPAD_HTTP2_DISABLE:-false}" = "true" ]; then + sed -i -e "s@\(^.*\) \+http2\(.*$\)@\1\2@" $CPAD_NGINX_CPAD_CONF + fi + + ## WIP + # If cryptad conf isn't provided + # if [ ! -f "$CPAD_CONF" ]; then + # echo -e "\n\ + # ############################################### \n\ + # Warning: No config file provided for cryptpad \n\ + # We will create a basic one for now but you should rerun this service \n\ + # by providing a file with your settings \n\ + # eg: docker run -v /path/to/config.js:/cryptpad/config/config.js \n\ + # ############################################### \n" + # + # cp $CPAD_HOME/config/config.example.js $CPAD_CONF + # + # # Set domains + # sed -i -e "s@\(httpUnsafeOrigin:\).*[^,]@\1 'https://$CPAD_MAIN_DOMAIN'@" \ + # -e "s@\(^ *\).*\(httpSafeOrigin:\).*[^,]@\1\2 'https://$CPAD_SANDBOX_DOMAIN'@" $CPAD_CONF + # + # # Set admin email + # if [ -z "$CPAD_ADMIN_EMAIL" ]; then + # echo "Error: Missing admin email (Did you read the config?)" + # exit 1 + # else + # sed -i "s@\(adminEmail:\).*[^,]@\1 '$CPAD_ADMIN_EMAIL'@" $CPAD_CONF + # fi + # fi + +fi + +exec "$@" diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 0000000..a9bda57 --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,50 @@ +# Multistage build to reduce image size and increase security +FROM node:12-buster-slim AS build + +# Install requirements to clone repository and install deps +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq git +RUN npm install -g bower + +# Create folder for cryptpad +RUN mkdir /cryptpad +WORKDIR /cryptpad + +# Get cryptpad from repository submodule +COPY cryptpad /cryptpad + +RUN sed -i "s@//httpAddress: '::'@httpAddress: '0.0.0.0'@" /cryptpad/config/config.example.js + +# Install dependencies +RUN npm install --production \ + && npm install -g bower \ + && bower install --allow-root + +# Create actual cryptpad image +FROM node:12-buster-slim + +# Create user and group for cryptpad so it does not run as root +RUN groupadd cryptpad -g 4001 +RUN useradd cryptpad -u 4001 -g 4001 -d /cryptpad + +# Copy cryptpad with installed modules +COPY --from=build --chown=cryptpad /cryptpad /cryptpad +USER cryptpad + +# Set workdir to cryptpad +WORKDIR /cryptpad + +# Create directories +RUN mkdir blob block customize data datastore + +# Volumes for data persistence +VOLUME /cryptpad/blob +VOLUME /cryptpad/block +VOLUME /cryptpad/customize +VOLUME /cryptpad/data +VOLUME /cryptpad/datastore + +# Ports +EXPOSE 3000 3001 + +# Run cryptpad on startup +CMD ["server.js"] diff --git a/nginx/Dockerfile-alpine b/nginx/Dockerfile-alpine new file mode 100644 index 0000000..4020eca --- /dev/null +++ b/nginx/Dockerfile-alpine @@ -0,0 +1,64 @@ +# Multistage build to reduce image size and increase security +FROM node:12-alpine AS build + +# Install requirements to clone repository and install deps +RUN apk add --no-cache git +RUN npm install -g bower + +# Create folder for cryptpad +RUN mkdir /cryptpad +WORKDIR /cryptpad + +# Get cryptpad from repository submodule +COPY cryptpad /cryptpad + +RUN sed -i "s@//httpAddress: '::'@httpAddress: '0.0.0.0'@" /cryptpad/config/config.example.js +RUN sed -i "s@httpUnsafeOrigin: '(.*)'@httpUnsafeOrigin: process.env.CRYPTPAD_HTTP_UNSAFE_ORIGIN@" /cryptpad/config/config.example.js +RUN sed -i 's@// httpSafeOrigin: "(.*)""@httpSafeOrigin: process.env.CRYPTPAD_HTTP_SAFE_ORIGIN@' /cryptpad/config/config.example.js + +# Install dependencies +RUN npm install --production \ + && npm install -g bower \ + && bower install --allow-root + +# Create actual cryptpad image +FROM node:12-alpine + +ENV CRYPTPAD_HTTP_UNSAFE_ORIGIN http://localhost:3001 +ENV CRYPTPAD_HTTP_SAFE_ORIGIN http://localhost:3001 + +# Install process management tool +RUN apk add --no-cache supervisor nginx + +# Create user and group for cryptpad so it does not run as root +RUN addgroup -g 4001 -S cryptpad \ + && adduser -u 4001 -S -D -g 4001 -H -h /cryptpad cryptpad + +# Copy cryptpad with installed modules +COPY --from=build --chown=cryptpad /cryptpad /cryptpad +USER cryptpad + +# Set workdir to cryptpad +WORKDIR /cryptpad + +# Create directories +RUN mkdir blob block customize data datastore + +# Volumes for data persistence +VOLUME /cryptpad/blob +VOLUME /cryptpad/block +VOLUME /cryptpad/customize +VOLUME /cryptpad/data +VOLUME /cryptpad/datastore + +# Start supervisord as root +USER root + +# Configure supervisord +ADD nginx/supervisord.conf /etc/supervisor/supervisord.conf + +# Ports +EXPOSE 3000 3001 + +# Run supervisord on startup +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] diff --git a/nginx/startup.sh b/nginx/startup.sh new file mode 100644 index 0000000..f682536 --- /dev/null +++ b/nginx/startup.sh @@ -0,0 +1,2 @@ +#! /bin/bash + diff --git a/nginx/supervisord.conf b/nginx/supervisord.conf new file mode 100644 index 0000000..f948a60 --- /dev/null +++ b/nginx/supervisord.conf @@ -0,0 +1,28 @@ +[supervisord] +nodaemon=true +logfile=/dev/null +logfile_maxbytes=0 +pidfile=/run/supervisord.pid + +[program:cryptpad] +directory=/cryptpad +command=node server.js +user=cryptpad +group=cryptpad +environment=HOME="/cryptpad",USER="cryptpad",CRYPTPAD_HTTP_UNSAFE_ORIGIN=%(ENV_CRYPTPAD_HTTP_UNSAFE_ORIGIN)s,CRYPTPAD_HTTP_SAFE_ORIGIN=%(ENV_CRYPTPAD_HTTP_SAFE_ORIGIN)s +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=false +startretries=0 + +;[program:nginx] +;command=nginx -g 'daemon off;' +;stdout_logfile=/dev/stdout +;stdout_logfile_maxbytes=0 +;stderr_logfile=/dev/stderr +;stderr_logfile_maxbytes=0 +;autorestart=false +;startretries=0 + diff --git a/supervisord.conf b/supervisord.conf new file mode 100644 index 0000000..fe8ff10 --- /dev/null +++ b/supervisord.conf @@ -0,0 +1,49 @@ +[unix_http_server] +file=/dev/shm/supervisor.sock ; (the path to the socket file) + +[supervisord] +logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log) +logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB) +logfile_backups=10 ; (num of main logfile rotation backups;default 10) +loglevel=info ; (log level;default info; others: debug,warn,trace) +pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +nodaemon=false ; (start in foreground if true;default false) +minfds=1024 ; (min. avail startup file descriptors;default 1024) +minprocs=200 ; (min. avail process descriptors;default 200) +user=root ; + +; the below section must remain in the config file for RPC +; (supervisorctl/web interface) to work, additional interfaces may be +; added by defining them in separate rpcinterface: sections +;[rpcinterface:supervisor] +;supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +;[supervisorctl] +;serverurl=unix:///dev/shm/supervisor.sock ; use a unix:// URL for a unix socket + +[program:node] +command = /usr/local/bin/node /cryptpad/server.js +user=cryptpad +autostart=true +autorestart=true +priority=5 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +stopsignal=QUIT + +[program:nginx] +command=/usr/sbin/nginx -g "daemon off;" +autostart=true +autorestart=true +priority=10 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +stopsignal=QUIT + +[eventlistener:processes] +command=sh -c "printf 'READY\n' && while read line; do kill -SIGQUIT $PPID; done < /dev/stdin" +events=PROCESS_STATE_STOPPED,PROCESS_STATE_EXITED,PROCESS_STATE_FATAL diff --git a/traefik2.yml b/traefik2.yml index 4ed8f1c..502c11d 100644 --- a/traefik2.yml +++ b/traefik2.yml @@ -1,14 +1,29 @@ --- -version: '2' +version: '3.8' services: cryptpad: labels: - - traefik.http.routers.cryptpad.rule=Host(`cryptpad.example.com`) - - traefik.http.routers.cryptpad-sandbox.rule=Host(`cryptpad-sandbox.example.com`) - - traefik.http.routers.cryptpad.tls="true" - - traefik.http.routers.cryptpad-sandbox.tls="true" - - traefik.http.routers.cryptpad.entrypoints="https" - - traefik.http.routers.cryptpad-sandbox.entrypoints="https" - - traefik.http.services.cryptpad.loadbalancer.server.port=3000 - - traefik.http.services.cryptpad-sandbox.loadbalancer.server.port=3001 \ No newline at end of file + ## Enable traefik + - traefik.enable=true + + ## Declare service + ## Change the port if you enabled TLS + - traefik.http.services.cpad.loadbalancer.server.port=80 + + # Configure middleware for http to https redirection + - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https + - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true + - traefik.http.middlewares.https-redirect.redirectscheme.port=443 + + # HTTP router rules + - traefik.http.routers.cpad-http.entrypoints=http + - traefik.http.routers.cpad-http.rule=Host(`example.com`, `sandbox.example.com`) + - traefik.http.routers.cpad-http.middlewares=https-redirect + + # HTTPS router rules + - traefik.http.routers.cpad-https.entrypoints=https + - traefik.http.routers.cpad-https.rule=Host(`example.com`, `sandbox.example.com`) + - traefik.http.routers.cpad-https.tls=true + - traefik.http.routers.cpad-https.tls.certresolver=letsencrypt + - traefik.http.routers.cpad-https.service=cpad