From a604e904475ded74e4be5ef1135cdf3f82024f70 Mon Sep 17 00:00:00 2001 From: Jakub Filo Date: Sun, 28 Dec 2025 19:33:57 +0000 Subject: [PATCH 1/5] Add docker CI builds --- .github/workflows/docker-publish.yml | 79 ++++++++++++++++++++++++++++ Dockerfile | 31 +++++++++++ 2 files changed, 110 insertions(+) create mode 100644 .github/workflows/docker-publish.yml create mode 100644 Dockerfile diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..dcf0149 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,79 @@ +name: Docker + +on: + push: + # Publish `master` as Docker `latest` image. + branches: + - master + + # Publish `v1.2.3` tags as releases. + tags: + - '*' + + # Run tests for any PRs. + pull_request: + +jobs: + # Run tests. + # See also https://docs.docker.com/docker-hub/builds/automated-testing/ + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Run tests + run: docker build . --file Dockerfile + + # Push image to GitHub Packages. + # See also https://docs.docker.com/docker-hub/builds/ + push: + # Ensure test job passes before pushing image. + needs: test + + runs-on: ubuntu-latest + if: github.event_name == 'push' + + steps: + - uses: actions/checkout@v2 + + - name: Login to ghcr.io + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Compute tag + id: compute-tag + run: | + IMAGE_ID=ghcr.io/${{ github.repository }} + + # Change all uppercase to lowercase + IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') + + # Strip git ref prefix from version + VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') + + # Strip "v" prefix from tag name + [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') + + # Use Docker `latest` tag convention + [ "$VERSION" == "master" ] && VERSION=latest + + echo IMAGE_ID=$IMAGE_ID + echo VERSION=$VERSION + + echo "DOCKER_TAG=$IMAGE_ID:$VERSION" >> "$GITHUB_OUTPUT" + + - name: Push multi-arch image + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.compute-tag.outputs.DOCKER_TAG }} + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3f594d0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +# syntax=docker/dockerfile:1 +ARG NODE_VERSION=18.0.0 + +FROM node:${NODE_VERSION}-alpine + +# Use production node environment by default. +ENV NODE_ENV=production + + +WORKDIR /usr/src/app + +# Download dependencies as a separate step to take advantage of Docker's caching. +# Leverage a cache mount to /root/.npm to speed up subsequent builds. +# Leverage a bind mounts to package.json and package-lock.json to avoid having to copy them into +# into this layer. +RUN --mount=type=bind,source=package.json,target=package.json \ + --mount=type=bind,source=package-lock.json,target=package-lock.json \ + --mount=type=cache,target=/root/.npm \ + npm ci --omit=dev + +# Run the application as a non-root user. +USER node + +# Copy the rest of the source files into the image. +COPY . . + +# Expose the port that the application listens on. +EXPOSE 3000 + +# Run the application. +CMD ["node", "src/index.js"] From 78830142da0f46198ce150aae4c4a2c19345f911 Mon Sep 17 00:00:00 2001 From: Jakub Filo Date: Sun, 28 Dec 2025 19:37:46 +0000 Subject: [PATCH 2/5] Add docker-compose example with db initialization helper --- config/mongo-init.js | 12 ++++++++++++ docker-compose.yml | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 config/mongo-init.js create mode 100644 docker-compose.yml diff --git a/config/mongo-init.js b/config/mongo-init.js new file mode 100644 index 0000000..31733a4 --- /dev/null +++ b/config/mongo-init.js @@ -0,0 +1,12 @@ +db.createUser( + { + user: process.env.MONGO_USER, + pwd: process.env.MONGO_PASS, + roles: [ + { + role: "readWrite", + db: process.env.MONGO_INITDB_DATABASE + } + ] + } +); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..86c8adc --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,35 @@ +--- +services: + mongodb: + image: mongo:7 + restart: always + volumes: + - ./data/db:/data/db + - ./config/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro + networks: + - backend + env_file: .env + security_opt: + - apparmor=unconfined + + keyserver: + image: ghcr.io/plantroon/keyserver:latest + restart: always + depends_on: + - mongodb + networks: + - traefik-proxy + - backend + env_file: .env + security_opt: + - apparmor=unconfined + labels: + - "traefik.enable=true" + - "traefik.http.routers.keyserver.rule=Host(`keyserver.example.com`)" + - "traefik.http.routers.keyserver.entrypoints=websecure" + - "traefik.http.routers.keyserver.tls.certresolver=acme-le" + - "traefik.http.services.keyserver.loadbalancer.server.port=3000" + +networks: + backend: + traefik-proxy: From 050719cd6e3eaefbfaf9f24c21861a8b77132f34 Mon Sep 17 00:00:00 2001 From: Jakub Filo Date: Sun, 28 Dec 2025 19:38:17 +0000 Subject: [PATCH 3/5] Add docker-related documentation --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 25b5281..9a95f7f 100644 --- a/README.md +++ b/README.md @@ -338,6 +338,19 @@ The key server uses [nodemailer](https://nodemailer.com) to send out emails upon For production you should use a service like [Amazon SES](https://aws.amazon.com/ses/), [Mailgun](https://www.mailgun.com/) or [Sendgrid](https://sendgrid.com/use-cases/transactional-email/). Nodemailer supports all of these out of the box. +### Docker compose + +Docker images are built from this repository and available at ghcr. You can use the sample docker-compose.yml - review it and populate an .env file with the required [settings](#Settings) before running the server. To create the database automatically, the following parameters are needed in .env file: + +``` +MONGO_URI=mongodb:27017/keyserver_db +MONGO_USER=keyserver +MONGO_PASS=somepassword +MONGO_INITDB_DATABASE=keyserver_db +``` + +The sample docker-compose.yml also contains common traefik settings, but you may need to adjust them for your own reverse proxy. + ## Run tests ```shell From 61c6e258a9d6026c6fbe57d0d0fa82d1af3f0a64 Mon Sep 17 00:00:00 2001 From: Jakub Filo Date: Sun, 28 Dec 2025 20:19:09 +0000 Subject: [PATCH 4/5] Fix image url in sample docker-compose --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 86c8adc..6437de7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: - apparmor=unconfined keyserver: - image: ghcr.io/plantroon/keyserver:latest + image: ghcr.io/mailvelope/keyserver:latest restart: always depends_on: - mongodb From e907ee6af35dea9b0b6bcedffbacd7093c5deb75 Mon Sep 17 00:00:00 2001 From: Jakub Filo Date: Sun, 28 Dec 2025 20:22:11 +0000 Subject: [PATCH 5/5] Add example env.sample file --- env.sample | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 env.sample diff --git a/env.sample b/env.sample new file mode 100644 index 0000000..c0bdb75 --- /dev/null +++ b/env.sample @@ -0,0 +1,22 @@ +NODE_ENV=production +LOG_LEVEL=debug +PORT=3000 +PAPERTRAIL_HOST='' +PAPERTRAIL_PORT='' +MONGO_URI=mongodb:27017/keyserver_db +MONGO_USER=keyserver +MONGO_PASS=changeme +MONGO_INITDB_DATABASE=keyserver_db +SENDER_NAME=keyserver +SENDER_EMAIL=changeme +SMTP_HOST=changeme +SMTP_PORT=587 +SMTP_TLS=false +SMTP_STARTTLS=true +SMTP_PGP='' +SMTP_USER='' +SMTP_PASS='' +HTTPS_UPGRADE=true +HTTPS_KEY_PIN='' +HTTPS_KEY_PIN_BACKUP='' +PUBLIC_KEY_PURGE_TIME=30