Skip to content

Instantly share code, notes, and snippets.

@smashnet
Last active December 7, 2023 05:50
Show Gist options
  • Save smashnet/38cf7c30cb06427bab78ae5ab0fd2ae3 to your computer and use it in GitHub Desktop.
Save smashnet/38cf7c30cb06427bab78ae5ab0fd2ae3 to your computer and use it in GitHub Desktop.
Docker-Compose: Mastodon v3.5.3 with Traefik v2.9
version: "3.5"
# Variables to fill in:
# Line 23: <LETSENCRYPT_MAIL_ADDRESS> - your mail address for contact with Let's Encrypt
# Line 36: <TRAEFIK_DASHBOARD_ADMIN_PASSWORD> - MD5 hash of your password (use http://www.htaccesstools.com/htpasswd-generator/)
# Line 54: <POSTGRES_PASSWORD> - the password for the postgres db. Use the same during mastodon:setup!
# Lines 31, 86, 111: <DOMAIN> - e.g. social.yourdomain.com (Must have an A record pointing to your box' IP) (AAAA for IPv6 ;)
services:
traefik:
image: traefik:v2.9
container_name: "traefik"
restart: always
command:
# - "--log.level=DEBUG"
- "--api.dashboard=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=<LETSENCRYPT_MAIL_ADDRESS>"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
labels:
- "traefik.enable=true"
# Dashboard
- "traefik.http.routers.traefik.rule=(Host(`<DOMAIN>`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`)))"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.middlewares=dashboardauth"
- "traefik.http.middlewares.dashboardauth.basicauth.users=admin:<TRAEFIK_DASHBOARD_ADMIN_PASSWORD>"
# HTTPS Redirect
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https@docker"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./letsencrypt:/letsencrypt
networks:
- external_network
db:
restart: always
image: postgres:14-alpine
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
environment:
- POSTGRES_PASSWORD=<POSTGRES_PASSWORD>
volumes:
- ./postgres:/var/lib/postgresql/data
networks:
- internal_network
redis:
restart: always
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
volumes:
- ./redis:/data
networks:
- internal_network
web:
image: tootsuite/mastodon:v3.5.3
restart: always
env_file: .env.production
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider --proxy=off localhost:3000/health || exit 1"]
expose:
- "3000"
depends_on:
- db
- redis
- traefik
labels:
- "traefik.enable=true"
- "traefik.docker.network=mastodon_external_network"
- "traefik.http.services.mastodon-web.loadbalancer.server.port=3000"
- "traefik.http.routers.mastodon-web.rule=Host(`<DOMAIN>`)"
- "traefik.http.routers.mastodon-web.entrypoints=websecure"
- "traefik.http.routers.mastodon-web.tls.certresolver=letsencrypt"
volumes:
- ./public/system:/mastodon/public/system
networks:
- external_network
- internal_network
streaming:
image: tootsuite/mastodon:v3.5.3
restart: always
env_file: .env.production
command: node ./streaming
healthcheck:
test: ["CMD-SHELL", "wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1"]
expose:
- "4000"
depends_on:
- db
- redis
- traefik
labels:
- "traefik.enable=true"
- "traefik.docker.network=mastodon_external_network"
- "traefik.http.services.mastodon-streaming.loadbalancer.server.port=4000"
- "traefik.http.routers.mastodon-streaming.rule=(Host(`<DOMAIN>`) && PathPrefix(`/api/v1/streaming`))"
- "traefik.http.routers.mastodon-streaming.entrypoints=websecure"
- "traefik.http.routers.mastodon-streaming.tls.certresolver=letsencrypt"
networks:
- external_network
- internal_network
sidekiq:
image: tootsuite/mastodon:v3.5.3
restart: always
env_file: .env.production
command: bundle exec sidekiq
depends_on:
- db
- redis
- traefik
volumes:
- ./public/system:/mastodon/public/system
networks:
- external_network
- internal_network
networks:
external_network:
name: mastodon_external_network
internal_network:
internal: true
@ansorg
Copy link

ansorg commented Apr 14, 2020

regarding <TRAEFIK_DASHBOARD_ADMIN_PASSWORD>
You can also use htpasswd on the machine where you work or somewhere else to generate this. install httpd-tools if not yet available. Full httpd (apache) not required

@smashnet
Copy link
Author

smashnet commented Apr 14, 2020

... and please don't forget to double the $ symbols (to $$) in the MD5 password hash to avoid syntax errors.

@ansorg
Copy link

ansorg commented Apr 15, 2020

yea, right.
Thanks for this compose file by the way :-)

I used it to set up a Mastodon 3.1.3 instance.

I had to add this to the db container in order to have it start properly. Postgress seems to need this for initial setup. Password is the one to be used later when setting up env for Mastodon

environment:
      - POSTGRES_PASSWORD=xyz

With that in place it worked.

Although there is a clash between path /api for Traefik and Mastodon itself. Any suggestion how to deal with that? Moving Traefik to a different (sub) domain?

@smashnet
Copy link
Author

yea, right.
Thanks for this compose file by the way :-)

I used it to set up a Mastodon 3.1.3 instance.

I had to add this to the db container in order to have it start properly. Postgress seems to need this for initial setup. Password is the one to be used later when setting up env for Mastodon

environment:
      - POSTGRES_PASSWORD=xyz

With that in place it worked.

Although there is a clash between path /api for Traefik and Mastodon itself. Any suggestion how to deal with that? Moving Traefik to a different (sub) domain?

Thanks! I updated the gist accordingly.

For the /api path I use a different domain for Traefik. My main domain meinungsschubla.de is for Mastodon and Traefik is accessible via the vServers own domain like customer1234567.vserv-hoster.tld.

@peterrus
Copy link

hi @smashnet, is the streaming backend working for you? My healthcheck passes, and I get a reply from the health endpoint from inside the streaming container. When I try to access it through traefik I get a 502 bad gateway however.

@peterrus
Copy link

I have been so free as to check if streaming was working at your personal instance, and it seems it also defective, so something is wrong with the traefik configuration we are both using, I suppose.

(I checked https://meinungsschubla.de/api/v1/streaming/health and received a 502, this is working correctly at https://mastodon.social/api/v1/streaming/health)

@peterrus
Copy link

peterrus commented Apr 24, 2020

I added - "traefik.http.services.streaming.loadbalancer.server.port=4000" to the streaming service, and that seems to fix it, but it is not playing along nicely with the web service. Will have a look at it this weekend probably, will report back ;)

(traefik tried to connect to the streaming service on port 3000, while it is running on 4000)

@peterrus
Copy link

Alright, I have forked your gist @ https://gist.github.com/peterrus/0753fc3cf09b33a6253924cfc9f9b32f and made some changes:

  • The streaming service was not working because traefik was trying to connect to port 3000 instead of the exposed 4000. I corrected this with an explicit configuration.
  • This explicit configuration (for traefik) had to be applied on a traefik service. Traefik instantiates new services with names based on docker-compose project name. We can't guess this in advance (if we want to keep the docker-compose file universal) so we have to specify that through an environment variable. I added instructions on how to create an .env file that gets loaded by docker-compose automatically
  • this .env file now also contains other configuration parameters, so as to keep them out of git and to keep the docker-compose file universal.
  • Traefik was trying to connect to the web and streaming through the 'internal_network' network. This does not seem to be correct nor desirable. I have created an explicit configuration to use the 'external_network' network. Again, I needed to refer to the docker-compose project name.

Feel free to port any of my changes back to your file as you see fit and thank you for setting up the initial example! You have saved me quite some headaches ;)

@encryptblockr
Copy link

encryptblockr commented Jun 20, 2020

where did you get the documentation for using these labels?
i can't find documentation on using these labels anywhere on the traefik website

    labels:
      - "traefik.enable=true"
      # Dashboard
      - "traefik.http.routers.traefik.rule=(Host(`<DOMAIN>`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`)))"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.middlewares=dashboardauth"
      - "traefik.http.middlewares.dashboardauth.basicauth.users=admin:<TRAEFIK_DASHBOARD_ADMIN_PASSWORD>"
      # HTTPS Redirect
      - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
      - "traefik.http.routers.http-catchall.entrypoints=web"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https@docker"
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"

i am looking for the v2 replacement for targeting network

   labels:
     - "traefik.docker.network=traefiknetwork"

@smashnet
Copy link
Author

where did you get the documentation for using these labels?
i can't find documentation on using these labels anywhere on the traefik website

You may have a look at this section of the Traefik docs: Traefik & Docker

... but especially here: Docker network

There it says that traefik.docker.network is still a valid label in v2.

@dweipert-3138720606
Copy link

I created a set of scripts with the help of your gist and @peterrus project.
It builds a docker-compose.yml from the official project's file and modifies it to include the traefik labels with some tweaks, so you can use an external running traefik container instead.

https://gitlab.com/dweipert.de/devops/mastodon-docker-traefik

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment