First of all, thank you very much for the excellent work in the development of Mayan EDMS.
I am new to the EDMS world and I am trying to implement a test server to evaluate the possibility of using it in the institution where I work.
I have been able to carry out the initial deployment, however, I am trying to implement SSL access to the EDMS and I am not succeeding.
I can’t figure out how to properly configure Traefik to use Lets’Encrypt certificates.
Any help or comments would be welcome.
Thank you very much.
First off, Welcome to the Mayan forum! Good to hear your kicking the tires so to speak. I am using Mayan as a home files solution on a single server. May I asked what deployment strategy are you using for your test and what are you looking to do for a production?
I am running now a manual install (that I am in the processes of migration to a docker compose) and this SSL is one of my next issues as well.
Solutions I am looking at is either expose the app on local host and use Nginx to reverse proxy with SSL or using another container with Nginx and Lets Encrypt built in and expose the 443 port.
I have not used Traefik and have noticed it in the config files but do not have any experience with that Maybe someone else who knows can chime in on that.
Thanks for your answer.
I used Docker Compose for the installation.
I tried traefik because it already came with the options in the config files, but I think I’m going to try using nginx.
It is unfortunate that those options are poorly documented.
Hello, I share my config with SSL Traefik letsencrypt over Docker Compose - Debian.
Is a example.
docker-compose.yml
`version: '3.9'
x-mayan-container:
&mayan-container
env_file: .env
environment:
MAYAN_CELERY_BROKER_URL: amqp://${MAYAN_RABBITMQ_USER:-mayan}:${MAYAN_RABBITMQ_PASSWORD:-mayanrabbitpass}@rabbitmq:5672/${MAYAN_RABBITMQ_VHOST:-mayan}
MAYAN_CELERY_RESULT_BACKEND: redis://:${MAYAN_REDIS_PASSWORD:-mayanredispassword}@redis:6379/1
MAYAN_DATABASES: "{'default':{'ENGINE':'django.db.backends.postgresql','NAME':'${MAYAN_DATABASE_NAME:-mayan}','PASSWORD':'${MAYAN_DATABASE_PASSWORD:-mayandbpass}','USER':'${MAYAN_DATABASE_USER:-mayan}','HOST':'${MAYAN_DATABASE_HOST:-post>
MAYAN_LOCK_MANAGER_BACKEND: mayan.apps.lock_manager.backends.redis_lock.RedisLock
MAYAN_LOCK_MANAGER_BACKEND_ARGUMENTS: "{'redis_url':'redis://:${MAYAN_REDIS_PASSWORD:-mayanredispassword}@redis:6379/2'}"
image: registry.gitlab.com/example/example:latest
# ${MAYAN_DOCKER_IMAGE_NAME:-mayanedms/mayanedms}:${MAYAN_DOCKER_IMAGE_TAG:-v4.4.2}
networks:
- mayan
restart: unless-stopped
volumes:
- ${MAYAN_APP_VOLUME:-app}:/var/lib/mayan
# Optional volumes to access external data like staging or watch folders
# - /opt/staging_folder:/staging_folder
# - /opt/watch_folder:/watch_folder
x-mayan-traefik-labels:
&mayan-traefik-labels
labels:
- "traefik.enable=${MAYAN_TRAEFIK_FRONTEND_ENABLE:-false}"
- "traefik.http.middlewares.mayan_frontend_http_redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.mayan_frontend_http_redirect.redirectscheme.permanent=false"
- "traefik.http.routers.mayan_frontend_http.entrypoints=http"
- "traefik.http.routers.mayan_frontend_http.middlewares=mayan_frontend_http_redirect"
- "traefik.http.routers.mayan_frontend_http.rule=Host(`${MAYAN_TRAEFIK_EXTERNAL_DOMAIN}`)"
- "traefik.http.routers.mayan_frontend_https.entrypoints=https"
- "traefik.http.routers.mayan_frontend_https.rule=Host(`${MAYAN_TRAEFIK_EXTERNAL_DOMAIN}`)"
- "traefik.http.routers.mayan_frontend_https.service=mayan_frontend_http"
- "traefik.http.routers.mayan_frontend_https.tls=true"
- "traefik.http.routers.mayan_frontend_https.tls.certresolver=letsencrypt"
- "traefik.http.services.mayan_frontend_http.loadbalancer.server.port=8000"
x-mayan-frontend-ports:
&mayan-frontend-ports
# Disable ports if using Traefik. Set to an empty list `[]`.
ports:
# - "${MAYAN_FRONTEND_HTTP_PORT:-80}:8000"
[]
networks:
keycloak:
driver: bridge
# Change to true when using Traefik for increased security.
internal: false
mayan:
driver: bridge
# Change to true when using Traefik for increased security.
internal: false
traefik: {}`
services:
app:
<<: *mayan-container
<<: *mayan-traefik-labels
<<: *mayan-frontend-ports
profiles:
- all_in_one
elasticsearch:
environment:
- bootstrap.memory_lock=true
- discovery.type=single-node
- http.max_content_length=400mb
- xpack.security.enabled=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- ELASTIC_PASSWORD=${MAYAN_ELASTICSEARCH_PASSWORD:-mayanespassword}
image: ${MAYAN_DOCKER_ELASTICSEARCH_IMAGE:-elasticsearch}:${MAYAN_DOCKER_ELASTICSEARCH_TAG:-7.17.7}
networks:
- mayan
# Enable to allow external access to the database.
# ports:
# - "9200:9200"
profiles:
- elasticsearch
restart: unless-stopped
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- ${MAYAN_ELASTICSEARCH_VOLUME:-elasticsearch}:/usr/share/elasticsearch/data
keycloak:
command:
- start
environment:
KEYCLOAK_ADMIN: ${MAYAN_KEYCLOAK_ADMIN:-admin}
KEYCLOAK_ADMIN_PASSWORD: ${MAYAN_KEYCLOAK_ADMIN_PASSWORD:-admin}
KC_DB: postgres
KC_DB_PASSWORD: ${MAYAN_KEYCLOAK_DATABASE_PASSWORD:-keycloakdbpass}
KC_DB_URL_DATABASE: ${MAYAN_KEYCLOAK_DATABASE_NAME:-keycloak}
KC_DB_URL_HOST: keycloak-postgres
KC_DB_USERNAME: ${MAYAN_DATABASE_KEYCLOAK_USER:-keycloak}
KC_HOSTNAME_URL: https://subdomain.domain.com:8081/
KC_HOSTNAME_STRICT: false
KC_HTTP_ENABLED: true
image: ${MAYAN_DOCKER_KEYCLOAK_IMAGE:-keycloak/keycloak}:${MAYAN_DOCKER_KEYCLOAK_TAG:-20.0.1}
labels:
- "traefik.enable=${MAYAN_TRAEFIK_KEYCLOAK_ENABLE:-true}"
- "traefik.http.middlewares.keycloak_http_redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.keycloak_http_redirect.redirectscheme.permanent=false"
- "traefik.http.routers.keycloak_http.entrypoints=http"
- "traefik.http.routers.keycloak_http.middlewares=keycloak_http_redirect"
- "traefik.http.routers.keycloak_http.rule=Host(`${MAYAN_TRAEFIK_EXTERNAL_DOMAIN}`)"
- "traefik.http.routers.keycloak_https.entrypoints=https"
- "traefik.http.routers.keycloak_https.rule=Host(`${MAYAN_TRAEFIK_EXTERNAL_DOMAIN}`)"
- "traefik.http.routers.keycloak_https.service=keycloak_http"
- "traefik.http.routers.keycloak_https.tls=true"
- "traefik.http.routers.keycloak_https.tls.certresolver=letsencrypt"
- "traefik.http.services.keycloak_http.loadbalancer.server.port=${MAYAN_TRAEFIK_KEYCLOAK_HTTP_PORT:-8081}"
networks:
- keycloak
- mayan
# Disable ports if using Traefik.
# ports:
# - "${MAYAN_TRAEFIK_KEYCLOAK_HTTP_PORT:-8081}:${MAYAN_TRAEFIK_KEYCLOAK_HTTP_PORT:-8081}"
profiles:
- keycloak
restart: unless-stopped
keycloak-postgres:
image: postgres:13.2
restart: unless-stopped
environment:
POSTGRES_DB: ${MAYAN_KEYCLOAK_DATABASE_NAME:-keycloak}
POSTGRES_PASSWORD: ${MAYAN_KEYCLOAK_DATABASE_PASSWORD:-keycloakdbpass}
POSTGRES_USER: ${MAYAN_DATABASE_KEYCLOAK_USER:-keycloak}
image: postgres:${MAYAN_DOCKER_KEYCLOAK_POSTGRES_TAG:-13.8-alpine}
networks:
- keycloak
profiles:
- keycloak_postgresql
restart: unless-stopped
volumes:
- ${MAYAN_KEYCLOAK_POSTGRES_VOLUME:-keycloak-postgres}:/var/lib/postgresql/data
postgresql:
command:
- "postgres"
- "-c"
- "checkpoint_completion_target=0.6"
- "-c"
- "default_statistics_target=200"
- "-c"
- "maintenance_work_mem=128MB"
- "-c"
- "max_connections=150"
- "-c"
- "shared_buffers=256MB"
- "-c"
- "work_mem=8MB"
environment:
POSTGRES_DB: ${MAYAN_DATABASE_NAME:-mayan}
POSTGRES_PASSWORD: ${MAYAN_DATABASE_PASSWORD:-mayandbpass}
POSTGRES_USER: ${MAYAN_DATABASE_USER:-mayan}
image: ${MAYAN_DOCKER_POSTGRES_IMAGE:-postgres}:${MAYAN_DOCKER_POSTGRES_TAG:-13.8-alpine}
networks:
- mayan
# Enable to allow external access to the database.
# ports:
# - "5432:5432"
profiles:
- postgresql
restart: unless-stopped
volumes:
- ${MAYAN_POSTGRES_VOLUME:-postgres}:/var/lib/postgresql/data
redis:
command:
- redis-server
- --appendonly
- "no"
- --databases
- "3"
- --maxmemory
- "100mb"
- --maxclients
- "500"
- --maxmemory-policy
- "allkeys-lru"
- --save
- ""
- --tcp-backlog
- "256"
- --requirepass
- "${MAYAN_REDIS_PASSWORD:-mayanredispassword}"
image: ${MAYAN_DOCKER_REDIS_IMAGE:-redis}:${MAYAN_DOCKER_REDIS_TAG:-7.0.5-alpine}
networks:
- mayan
profiles:
- redis
restart: unless-stopped
volumes:
- ${MAYAN_REDIS_VOLUME:-redis}:/data
# Run a frontend gunicorn container
frontend:
<<: *mayan-container
<<: *mayan-traefik-labels
<<: *mayan-frontend-ports
command:
- run_frontend
profiles:
- extra_frontend
# Enable to run standalone workers
mountindex:
<<: *mayan-container
cap_add:
- SYS_ADMIN
devices:
- "/dev/fuse:/dev/fuse"
entrypoint:
- /bin/sh
- -c
- 'mkdir --parents /mnt/index && chown mayan:mayan /mnt/index && /usr/local/bin/entrypoint.sh run_command "mirroring_mount_index --allow-other creation_date /mnt/index"' # Replace "creation_date" with the index of your choice.
profiles:
- mountindex
security_opt:
- apparmor:unconfined
volumes:
- type: bind
source: /mnt/mayan_indexes/creation_date # Host location where the index will show up.
target: /mnt/index # Location inside the container where the index will be mounted. Must the same is in the "entrypoint" section.
bind:
propagation: shared
# Run a separate class A worker
worker_a:
<<: *mayan-container
command:
- run_worker
- worker_a
- "--prefetch-multiplier=1"
profiles:
- extra_worker_a
# Run a separate class B worker
worker_b:
<<: *mayan-container
command:
- run_worker
- worker_b
- "--prefetch-multiplier=1"
profiles:
- extra_worker_b
# Run a separate class C worker
worker_c:
<<: *mayan-container
command:
- run_worker
- worker_c
- "--prefetch-multiplier=1"
profiles:
- extra_worker_c
# Run a separate class D worker
worker_d:
<<: *mayan-container
command:
- run_worker
- worker_d
- "--concurrency=1 --prefetch-multiplier=1"
profiles:
- extra_worker_d
worker_custom_queue:
<<: *mayan-container
command:
- /bin/sh
- -c
- 'MAYAN_QUEUE_LIST=${MAYAN_WORKER_CUSTOM_QUEUE_LIST} /usr/local/bin/run_worker.sh --prefetch-multiplier=1'
profiles:
- extra_worker_custom
# Run a separate Celery beat container
celery_beat:
<<: *mayan-container
command:
- run_celery
- "beat --pidfile= --loglevel=ERROR"
profiles:
- extra_celery_beat
setup_or_upgrade:
<<: *mayan-container
command:
- run_initial_setup_or_perform_upgrade
profiles:
- extra_setup_or_upgrade
restart: "no"
rabbitmq:
image: ${MAYAN_DOCKER_RABBITMQ_IMAGE:-rabbitmq}:${MAYAN_DOCKER_RABBITMQ_TAG:-3.11.2-management-alpine}
environment:
RABBITMQ_DEFAULT_USER: ${MAYAN_RABBITMQ_USER:-mayan}
RABBITMQ_DEFAULT_PASS: ${MAYAN_RABBITMQ_PASSWORD:-mayanrabbitpass}
RABBITMQ_DEFAULT_VHOST: ${MAYAN_RABBITMQ_VHOST:-mayan}
labels:
- "traefik.enable=${MAYAN_TRAEFIK_RABBITMQ_ENABLE:-false}"
- "traefik.http.routers.rabbitmq_admin_http.entrypoints=rabbitmq_admin_http"
- "traefik.http.routers.rabbitmq_admin_http.rule=Host(`${MAYAN_TRAEFIK_EXTERNAL_DOMAIN}`)"
- "traefik.http.routers.rabbitmq_admin_http.service=rabbitmq_admin_http"
- "traefik.http.routers.rabbitmq_admin_http.tls=true"
- "traefik.http.routers.rabbitmq_admin_http.tls.certresolver=letsencrypt"
- "traefik.http.services.rabbitmq_admin_http.loadbalancer.server.port=15672"
networks:
- mayan
# Enable to allow access to the administration interface.
# ports:
# - "${MAYAN_RABBITMQ_ADMIN_PORT:-15672}:15672"
profiles:
- rabbitmq
restart: unless-stopped
volumes:
- ${MAYAN_RABBITMQ_VOLUME:-rabbitmq}:/var/lib/rabbitmq
traefik:
container_name: "traefik"
command:
# - "--log.level=DEBUG"
- "--api.dashboard=true"
- "--api.insecure=${MAYAN_TRAEFIK_API_INSECURE:-false}"
- "--certificatesresolvers.letsencrypt.acme.caserver=${MAYAN_TRAEFIK_LETS_ENCRYPT_SERVER:-https://acme-staging-v02.api.letsencrypt.org/directory}"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge=${MAYAN_TRAEFIK_LETS_ENCRYPT_DNS_CHALLENGE:-false}"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=${MAYAN_TRAEFIK_LETS_ENCRYPT_DNS_CHALLENGE_PROVIDER}"
- "--certificatesresolvers.letsencrypt.acme.email=${MAYAN_TRAEFIK_LETS_ENCRYPT_EMAIL}"
- "--certificatesresolvers.letsencrypt.acme.storage=/traefik-certificates-letsencrypt/acme.json"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=${MAYAN_TRAEFIK_LETS_ENCRYPT_TLS_CHALLENGE:-false}"
- "--entrypoints.http.address=:80"
- "--entrypoints.https.address=:443"
- "--entrypoints.keycloak_http.address=:${MAYAN_TRAEFIK_KEYCLOAK_HTTP_PORT:-8081}"
- "--entrypoints.rabbitmq_admin_http.address=:15672"
- "--entrypoints.traefik_dashboard_http.address=:8088"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
# - Add DNS provider variables (https://doc.traefik.io/traefik/https/acme/#providers)
# environment:
image: ${MAYAN_DOCKER_TRAEFIK_IMAGE:-traefik}:${MAYAN_DOCKER_TRAEFIK_TAG:-v2.5}
labels:
- "traefik.enable=${MAYAN_TRAEFIK_DASHBOARD_ENABLE:-false}"
- "traefik.http.middlewares.basic-auth-global.basicauth.users=${MAYAN_TRAEFIK_DASHBOARD_AUTHENTICATION}"
- "traefik.http.routers.traefik_https.entrypoints=traefik_dashboard_http"
- "traefik.http.routers.traefik_https.middlewares=basic-auth-global"
- "traefik.http.routers.traefik_https.rule=Host(`${MAYAN_TRAEFIK_EXTERNAL_DOMAIN}`)"
- "traefik.http.routers.traefik_https.service=api@internal"
- "traefik.http.routers.traefik_https.tls=true"
- "traefik.http.routers.traefik_https.tls.certresolver=letsencrypt"
networks:
- mayan
- traefik
ports:
- "${MAYAN_RABBITMQ_ADMIN_HTTP_PORT:-15672}:15672"
- "${MAYAN_TRAEFIK_DASHBOARD_HTTP_PORT:-8080}:8080"
- "${MAYAN_TRAEFIK_KEYCLOAK_HTTP_PORT:-8081}:8081"
- "${MAYAN_TRAEFIK_HTTP_PORT:-80}:80"
- "${MAYAN_TRAEFIK_HTTPS_PORT:-443}:443"
profiles:
- traefik
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ${MAYAN_TRAEFIK_LETSENCRYPT_VOLUME:-traefik-certificates-letsencrypt}:/traefik-certificates-letsencrypt
volumes:
app:
elasticsearch:
keycloak-postgres:
postgres:
mountindex:
rabbitmq:
redis:
traefik-certificates-letsencrypt:
.env
# Default project name. Can also change this using the
# docker-compose `-p, --project-name NAME` option.
COMPOSE_PROJECT_NAME=mayan
# Default profiles.
COMPOSE_PROFILES=all_in_one,extra_frontend,postgresql,rabbitmq,redis,traefik
# User alternate Mayan EDMS Docker image or tag.
# MAYAN_DOCKER_IMAGE_NAME=registry.gitlab.com/custom/custom
# MAYAN_DOCKER_IMAGE_TAG=latest
# Modify this to your database server if not using the database deployed
# by the Docker Compose file.
# MAYAN_DATABASE_HOST=
# Security. Change these before the first run.
# Once these are set do not change them here. If you wish to change the
# passwords or usernames after the installation has completed, follow the
# documentation of each component individually and then update the password
# or username in this file. _PASSWORD_START_MARKER
# MAYAN_DATABASE_NAME=
# MAYAN_DATABASE_PASSWORD=
# MAYAN_DATABASE_USER=
# MAYAN_ELASTICSEARCH_PASSWORD=
# MAYAN_RABBITMQ_USER=
# MAYAN_RABBITMQ_PASSWORD=
# MAYAN_RABBITMQ_VHOST=
# MAYAN_REDIS_PASSWORD=
# MAYAN_FRONTEND_HTTP_PORT=80
MAYAN_WORKER_CUSTOM_QUEUE_LIST=
# Change if you use external services.
MAYAN_DOCKER_WAIT="postgresql:5432 rabbitmq:5672 redis:6379"
# RabbitMQ
# MAYAN_RABBITMQ_ADMIN_HTTP_PORT=15672
# Allows running an additional worker with a custom list of queues.
MAYAN_WORKER_CUSTOM_QUEUE_LIST=
# Traefik
# Enable to use production Let's Encrypt server.
MAYAN_TRAEFIK_LETS_ENCRYPT_SERVER=https://acme-v02.api.letsencrypt.org/directory
# Enable to launch the Let's Encrypt TLS challenge.
MAYAN_TRAEFIK_LETS_ENCRYPT_TLS_CHALLENGE=true
# Enable to activate the Traefik UI.
MAYAN_TRAEFIK_API_INSECURE=true
# Configure the administrative email for the domain.
MAYAN_TRAEFIK_LETS_ENCRYPT_EMAIL=youremail@domain.com
MAYAN_TRAEFIK_EXTERNAL_DOMAIN=yourdomain.com
# Expose the Traefik secure dashboard.
MAYAN_TRAEFIK_DASHBOARD_ENABLE=false
# Traefik secure dashboard username and password.
# Obtained using: echo $(htpasswd -nB your_username_of_choice)
# Enclose in single quotes.
MAYAN_TRAEFIK_DASHBOARD_AUTHENTICATION=''
# Insecure value of admin:admin
# MAYAN_TRAEFIK_DASHBOARD_AUTHENTICATION='admin:secret'
# Expose the frontend through Traefik.
MAYAN_TRAEFIK_FRONTEND_ENABLE=true
# Expose the RabbitMQ administrative interface through Traefik.
MAYAN_TRAEFIK_RABBITMQ_ENABLE=false
MAYAN_TRAEFIK_DASHBOARD_HTTP_PORT=8080
MAYAN_TRAEFIK_LETSENCRYPT_VOLUME=traefik-certificates-letsencrypt
MAYAN_TRAEFIK_HTTP_PORT=80
MAYAN_TRAEFIK_HTTPS_PORT=443
MAYAN_TRAEFIK_LETS_ENCRYPT_DNS_CHALLENGE_PROVIDER=
Thanks for your reply and for sharing the configuration. I will compare my configuration files and try to see what I am doing wrong.
in the .evn file, in the variable MAYAN_TRAEFIK_LETS_ENCRYPT_DNS_CHALLENGE_PROVIDER should I specify a value?
I think if you use MAYAN TRAEFIK LETS_ENCRYPT_TLS_CHALLENGE=true then MAYAN_TRAEFIK_LETS_ENCRYPT_DNS_CHALLENGE_PROVIDER is not needed, I don’t use it
scv1503
After making the changes to the configuration files and performing the docker compose up, I get the following warning “services.app.ports must be a list”. However, I have checked both files and they are similar to the example. I can’t find a list of ports that I need to add.
I see the “[ ]” commented. I uncommented the lines in traefik section and add “[]” in keycloak port section.
Still does not work. Thanks for your patience. I will try another approach.
Yeah, didnt work for me either, I mean the Traefik container doesnt start with the other containers either. I started a Traefik container on a different docker-compose file and assigned the same network and ports needed, that did the trick for me
are you able to show your config ?
depending on your needs this can do the job:
setup a reverse proxy with nginx, and Nginx will do the ssl with letsencrypt…
@smeyer - You a Turnkey Linux user? I ask cause I help out over they from time to time, and I brought Mayan to TKL back in 2017 I think, I have to look at the commit logs.
no, I don t
regards,