2023-03-18 11:40:48 +01:00

9.8 KiB

sidebar_position, title
sidebar_position title
2 Docker

KleckRelay requires a total of 3 services to run (this will probably change in future):

  1. The database (a PostgreSQL database)
  2. The server (the backend)
  3. The maid (a cron job that cleans up content)

:::info This guide assumes you are using Docker and Docker Compose. :::

Creating docker-compose.yml

:::tip Use our Config Generator to generate everything you need. :::

We will use a separate .env file to store sensitive information. This will be shared by multiple services. Here's an example, you will need to change at least the passwords and the domain name:

# The domain of the API
API_DOMAIN=api.app.krl
# The domain of the app (that's the actual website)
APP_DOMAIN=app.krl
# The domain where you will receive emails
MAIL_DOMAIN=mail.app.krl
# A randomly generated string, this is used to generate all kind of tokens
KLECK_SECRET=secret_change_me
# The URL of the database
DB_URI=postgresql://user:PASSWORD_1@kleckrelay_database/mail
# A private key used to sign content
SERVER_PRIVATE_KEY=LS0tLS1CRUdJTiBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLQpWZXJzaW9uOiBPcGVuUEdQLmpzIHY0LjEwLjEwCkNvbW1lbnQ6IGh0dHBzOi8vb3BlbnBncGpzLm9yZwoKeGNMWUJHUEcyRmdCQ0FEVUVKVVpIYWtlS2ZxTEF6UU9tVTBBK1NuWFI2bUttbEttT2YwUzZDZVBka0VVCmtNUXJLUkFHOGxpT3FIU00ydGcyMW95T2xBQnFRSlJXSlhuSHBBcDMxVWRHTG1BQ3VVT3lVc3poYy83VgpYc1RTdWtCKzlIQ2dvQTFrTjJqbFVBK24xSGduOVRBdlV0bEhMMjZIYXNrcE95YlhTYWFFMUJVYVJRWngKNjRqd2J2ckU2RlV1Y0t4MmxUaG5KdGpyOHJyMEgwUkdYRFVSc21Zamc0ZEp3MFcrU2w1aVpYKzJZUzI2CityOTk1RDNwY2pienVxemZ0OW9QRnNwekNKS2pUdGJyUkpYRXg4bHNrR2J4ZUpaQVlzL2NDd1Bab05IRwo1eE1VR3dKNW9PZFl0dlB2VlBURnBwelU0QWMrTVdreHppTEE2TnJ4ZlYvcS9DVGFBQ2ozM3BmYkFCRUIKQUFFQUIvNHpFTmt1aHA5eVpZNXhDakR2Y1FnRGUzeVJYQzdkOHdLREI4VEMyRWVxZXNINk4xQWR5cElTCjhpblVGSW1ZWDV5Z08vTDE1SHJqR3pEOU82SURLcVBncm1tdTR6ejRldTlyMGhlSEZOMGhPV1J4RUN1Mgp4cHNXZXVRdXBVOHJwU2RYOVVpSDZybVRNOEtocXpEVkNDaHZ0dEJJR0hLeVdyWElNU1gzcWMyOGc3VEYKSW91dk1SeDdpV3F4ZmdtMUtXbWlpRm9mRFJFWkFsTDhXQU5zZUhmUkNCWkdqT0srdFZJVTJlM2dubHJZCnJRUm12U1k3ak0yMzJFOHFiMWZmQTk1SVlvTk51U2RFNzhkdllBaTEycWk1dHVLNTh5TTJNK1ByVVJnRwprN2NYdmxqcVVjTDVhK0l1UE9iWDN3aHdOcDJpMDhMMC85NjRjSkFwZk41Q1ZwNlZCQURvbGMwN3Vlb0gKZHd3cDhFaC9HRkt1UlRNL1dkQTZxRmZtczZrSTdjZG5STFVHTlhQaGZ5Q2c0Nk84VEZjUDhLQ01hNjhaCmhzV0ZBcHhhdkxpLzBEMkliSE1QTkwra3F0SFRCRmtkNFA1ZHA5a2lMTlh6UmtLdFE4akNQamk1M2w5bgp0SkJuTVhkY2NDRjQxZHNvWlFDRVBjdklkeUVZMk5Zc2oyRlZOUHFtM3dRQTZXbnRsOGJGdkQzQk1nb2oKMlVpMzQrK0taVVg1RndBd3pPcVQxQXFxeC9XZmNnbmV5Y1RqcTB0WEFDcmZYK2E3OWVKbDlsNVc5VVpDClJ2dnJFUkdiRm1HS3Uxb01HZ3lVNkNWYStDalZXTHoyLzVUL2FIWUlHZkU4QzlOZHhNOG1LcmdpQ29HRwpKZ29wZXFsYTFLZThjMzVjd05iQzFhdFcvVndoalczMDJvVUVBSldXRVg2VzYwV28vd2J3Szd1c1k5c2kKQjVkTjlWblpwSEF6Y0tZaGwwRGZaVUFRWlhwWnAzWHhHNmkzUkJobjFDQ25Yakh4cnBycVZrSUtxT3Q2CjFTOEJSRk1scFdRZ1JYVkU2Z2ZJMGY3SWZJZ01KLzVFK09kNW5JTUtncnB5c0xodjZ5alVEeGo5YksyWgpzeEF1M0FXNW8rUGprdlEyWmNQTUNsbUJXUzIzUXpUTkVXRWdQR0ZBWlhoaGJYQnNaUzVqYjIwK3dzQ04KQkJBQkNBQWdCUUpqeHRoWUJnc0pCd2dEQWdRVkNBb0NCQllDQVFBQ0dRRUNHd01DSGdFQUlRa1FENi9mCkpjb3djS2tXSVFUbXN0UWxSdm12SnRUa3hlTVByOThseWpCd3Flay9DQURRSDlNeUEzdWRuWGhWdm1DbAowa2E2aXRaWXA1R0lya2gvQmFHdWYva3MrVk55amZ6cm9jbUlnYmkvOWZPM3BWbzMwV3JWdlErb2xZV2IKYXIzc005SitGZUxiZ251Rm1HM2xtbGlZdU5RWlFZWEd4SWNtVXdQVDlDVXNKRGQ1YlV6bk9reXRNNmoxCmRkZWM2ODZEMm5IVktvbi9pRks0T3FsbUFSdHhrOW1SaTB3OUpDWTl0V0RrZ205R29GTzFROFNrZjRRNwo3U0syakplcktNUTNHSnplVXl0dEhXNEhLRUZZb1JRR3J2eGJ4UERQMXRLaXpaYS9GTlJCUEJJVHo0UWkKemdvdjRCZDRTZW1Tc0cyTVRDUVdFeUxaRUd6MVpMM0szd2xwbDFhb1JVVnpFRUhtYmJhVXBCclQyUzl5CnJqRHI0ZU03VHEwb29oRFlNMnZPYUhSQng4TFlCR1BHMkZnQkNBQ3d6TEs2eDdYbHRXOUFyUnVjeXBmNgpLTk1lWFNaR2tQcVc5VHVUMk9BZDl6K0hLVUYvYk45M0VuS1pSRTJaU3hPaEN6amtxT2hUbmVkMkp2dWcKNnc1R3N4VHZxVjBXYW9EV2hNU1A5MWd2Q1I3ajcvTURqQkFZSFI1YmREWGZzazljUVZTWDgwRE8zTEloCldPWm85amVOZ1NkMlRuUnREalZ1cXFod1VyZERQcHRTM0Jzb2E5VG1GNHNTN3pOdTNGVDZ1amNuUDd6TgpjbHZmcTBLZ0E5Z0s2b21VUDVNcWR6OTY3ci9BMnZ0cld0R3FicEJwaEZlbnZuNVNqMlV4eG1TYWRhQysKSnNUNGhWN0pncGZVclV6cE1XbkJQeEVLWjIrTGM1WFNaekxFenhjZ2cyMWxWVXJnTTdBZVpEaHNBMHVSCnc4WVVJbG4rWXZWVTk1TnJTaDNsQUJFQkFBRUFCLzBjZDFqdnFlZ25yQ2JWaXdtL0hQK0xUN2R1VkNFdAppM3BOZy82cnQyZWVhNGpYQWxXQlpzNDBKY3c5MFRtTlRRRkVGTUo4VHBYWm9McjcweHNBdGRmK21pYnMKejZBbFU5Q2F1WlhNZUU3Q2cvMXRSZDBpM1JKYVQ1WHJzN0pZNmlUTS9kZlkvMW1YOVFEWlRhOExoMWs2CmQya2JLMWFqbUg0UjYzaGpYVzRVYldONzBVbTkrY0tPSjhQRENxWGFlWXExdmllTGRnN3ZRZWEyc3dzWQpOaFJDU3E1OG1ubmh2ZnR5RWhwdkVpbGRROFhsL1RIVXZ3ZjM5TElHTXNhQjZCNlN3RnJtemhsTXJFNXAKTm1YVnQ0by83MmtGNEdQYlVVa0JtL2ZCWU4zdkhacXBwcFNZVlg5Y08wUHNaQW5IZGJ3aXFRUlBaamd1Cm1KK1VhMzl4WVdHaEJBREhEWXFSVkwrOHFLODhwUm43WjA5cFNGaHZ0ZEtJWU1xcGJ0ZkVFMGRTTnNGVwoybXVRTkMxTjk4aUJMdDFWTVpkbFgvZDNyeEdoSFFhWDRWTzJadkdXMUowRzdaZTk3TWNLcmVYcG16ZkQKdlpPM0VDMytGQWpZRG9oeEs4UlBKTEd2QjNBakwrcm9iTldsUlQ4YWt4UmVsZ0hPc1F4ZHNiMzhTUUR5Clh6Y21rd1FBNDJGWVkvOXphSmY5VVhkaHR6blZZaHRjbXNPVlVwS3MvSkV5S2p5K2pKemZPM29rKzN3RQpoMWlDaFRCeXJFR1lwYktkVmdNMXA5RGRUNUVrRll0bCtBT1hjZHB1em4vZGdHdDFmNHM3c3Vsa2ExVnMKY2x6cW5nUkZLb216eXBhMmYyZ0owbnZSYzY2eHNKczdleDQ3NUF1OTZsK0g3S2ZZY3pMbWJSdVV2S2NECi9qa05QYjdWdTJFak5GaWs1eHBsckUvalFMU3VXSGQzOFNNeTN3blRHeDJ3WFlmUERIa1llUDJZZ1NqcQpxd1dod21jRWdSMFBYY3N6RGFZMGhlTnFlWU1xQkZpMkNsaCtSQVNKQ1Y3aDFlNER5cnE4cGFIR01ZRGkKc0srcmJsL2pMa2x6ZFBNU2tuck54QUp6UXN6OEZjekpWaEcwRTNSMjRJUll4NWZkb3Rmc1FjN0N3SFlFCkdBRUlBQWtGQW1QRzJGZ0NHd3dBSVFrUUQ2L2ZKY293Y0trV0lRVG1zdFFsUnZtdkp0VGt4ZU1Qcjk4bAp5akJ3cVdkTUIvOVNKZGt5am9PVEdNVFRhOUJaNk0vOCt6RzFIS2FNRTVjQyt4b3F4OG5MUUpBTy9KV0oKMDB4SDkxcW03N0F0WnhyMUpIK2x0c2RrRERoUXMrZHdISWpVV1haTjd3SnNwREV6NGY2c2tRRWVySzVXCmhtSzJhdGdDMkQxRmVidnJuQjBMS2xDY2o4ZDQzZzREamxuaEVHNkFIenYwUWxBRHI1VlNGRTdkaSs5TgpBcHV6WDFxVWdXbUxxSHVMY3hUQkJtYUo4S09mTWhwNWdCVE9aU2w3elc5RTU3T3NHblVHRERPVWg2VDIKTFEzNGt4Wi93ZEt1ZzQrYWRGRFphODZVRk5KL0duR1BVak9kbkNYZXZHVzVieXU0RHhmalI1Zk93TENDCmJxVWFHeGgwd2cvL0x1Wkh3T0NidHFkb0YvRFNFeDFVU2pzY1l4WUllcE91QW94OUhiWDUKPWd3d0EKLS0tLS1FTkQgUEdQIFBSSVZBVEUgS0VZIEJMT0NLLS0tLS0K
# A private key for DKIM (used for signing emails), reduces your spam score
DKIM_PRIVATE_KEY=LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlDV3dJQkFBS0JnUUMvV3V5SWovWDAvMk1sdmVQQlVhai9KQXVIQzNCdlpwUWUrS1ZPTDBwdEF3RzZndm1kCkV6dmljL00zRGsxVzJtR3NLaFVpY0lSMHd1MVlpZEVCcGdWa0FFU2MxSE95TjAwbDJDbmhxQTZ2TU1Md0xlVkoKYVVDRmEwOU4xMUQ3TWVHbFdrdStXY1hNTEMva1B0TW5KNmo2YUZhbVFCbEZJdHJTSnk1dnN4VVV1UUlEQVFBQgpBb0dBUE5FTURoY2JCOFBIWWk1bzNYOHpvK3R6MG5iYlJEeW81UE1IcnNLdTk5aVZ5dzVuZ1BtazljTCtVTWcxCjRsM0QzekQ4eUpaVU1ydmxMVmVYMnR0R0tNYUlyRHBIQXd6N0NWYk0zK0ZsZzVYZy9McE1GRVJWNllUQkVkSysKQ01YNXJ1aUFVYnE5TDZ2Rk5WYkZVQkZxbWQ2UXY5YUl1Vm5vck1jaUhGQUZzeVVDUVFEaUUxSUJUbzgwT0VyaQpubHByN1I0R3grSEtwb054SWloejVDZ0NvSytDUWMxbzZCMmppaU1GYjRvdFNSOEpwUzhhbk05TG9ySStOa2NuCnJ6Z0Y0bG4vQWtFQTJLOFd6S285VFRlUFZsNE9uOVBIeEI4dTEvSklRWjBxcHkyMlpRZmNDZHNsbXN5bDB2SGcKSUtnZ05HKzFFc0svdjVwRnhvQjdQUUx6V09NMVBjdmhSd0pBSzljOVR0MlNMYmxBNUdONiszVDNIcStDWE04ZgpyRC9JZ25qYlBXODF1ZGZTNHFZb29UODNmV1ZjOFYwOXRKd2czMU5MYThwNE1GSk1TQ2pWZjJhZXR3SkFGQlE5CmY1K3k2SW5pZlhWZjA0MnpjRWdYZGlsY2FzQWVxTGxDc3FBRTB1RDgzaGhpc1daNmgyd3M5ODcyTDVQZVl1bnYKMTFJbW1XUEJteFlLNC93Vmx3SkFibDd1dUlJWDdmbFRuYTRlUHA0VWVoK3o2R0x1OFVsM1RQQU00MHl6MjVKSwpjUnFJZzZXRTRpRkF4U2h0MnpYemRrODg1T1lQRVJobGppL3RzeHp0Wnc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
# Whether admins should be able to change global settings through the web interface (we recommend to keep this enabled)
USE_GLOBAL_SETTINGS=yes
# A comma-separated list of admins (email addresses)
ADMINS=marvin@kleckrelay.example,sarah@kleckrelay.example

Here's an example docker-compose.yml file, you will need to change at least the passwords and the domain name. This file assumes that you have these folders in the same directory as the docker-compose.yml file:

  • db - To store database data
  • tutorial - To store tutorial files (used to explain how to set up your DNS records)
  • opendkim_keys - To store DKIM keys
  • certs - To store SSL certificates
  • letsencrypt - To store Let's Encrypt certificates
version: '3'

services:
  kleckrelay_database:
    image: 'postgres:latest'
    container_name: kleckrelay_database
    restart: on-failure:5

    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: PASSWORD_1
      POSTGRES_DB: mail

    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mail"]
      interval: 5s
      timeout: 5s
      retries: 5

    volumes:
      - ./db:/var/lib/postgresql/data

    ports:
      - "35432:5432"

  kleckrelay_server:
    image: myzel394/kleckrelay-server
    container_name: kleckrelay_server
    restart: on-failure:5

    depends_on:
      kleckrelay_database:
        condition: service_healthy

    cap_add:
      - NET_BIND_SERVICE
      - SYS_PTRACE

    ports:
      - "25:25"
      - "587:587"

    volumes:
      - ./tutorial:/tutorial
      - ./opendkim_keys:/etc/opendkim/keys
      - ./certs:/etc/ssl/certs

    env_file:
      - .env

 kleckrelay_maid:
    image: myzel394/kleckrelay-maid
    container_name: kleckrelay_maid
    restart: on-failure

    depends_on:
      kleckrelay_database:
        condition: service_healthy

    env_file:
      - .env

  nginx:
    container_name: nginx
    image: bunkerity/bunkerweb
    restart: on-failure:5
    ports:
      - 80:8080
      - 443:8443
    volumes:
      # Change to your own path where you would like to store your HTTPS certificates and
      #uncomment the line
      - ./letsencrypt:/etc/letsencrypt
    environment:
      - MULTISITE=yes
      # Specify your domains here (including subdomains)
      - SERVER_NAME=api.kleckrelay.com
      - USE_REVERSE_PROXY=yes
      - DISABLE_DEFAULT_SERVER=yes
      - AUTO_LETS_ENCRYPT=yes
      # If you want to receive a notification when your certificates are not automatically
      # renewed and will expire soon, enter an email here
      # - EMAIL_LETS_ENCRYPT=
      - USE_BAD_BEHAVIOR=no

      - api.kleckrelay.com_REVERSE_PROXY_URL=/
      - api.kleckrelay.com_REVERSE_PROXY_HOST=http://kleckrelay_server:80
      - api.kleckrelay.com_ALLOWED_METHODS=GET|POST|PUT|PATCH|DELETE|OPTIONS
      # Security is too strict
      - api.kleckrelay.com_BLOCK_ABUSERS=no