# This file is designed for production server deployment, not local development work # For a containerized local dev environment, see: https://github.com/mastodon/mastodon/blob/main/docs/DEVELOPMENT.md#docker
web: # You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes # build: . image:ghcr.io/mastodon/mastodon:v4.5.2 restart:always env_file:.env.production command:bundleexecpuma-Cconfig/puma.rb networks: -external_network -internal_network healthcheck: # prettier-ignore test: ['CMD-SHELL',"curl -s --noproxy localhost localhost:3000/health | grep -q 'OK' || exit 1"] ports: -'127.0.0.1:3000:3000' depends_on: -db -redis # - es volumes: -./public/system:/mastodon/public/system
streaming: # You can uncomment the following lines if you want to not use the prebuilt image, for example if you have local code changes # build: # dockerfile: ./streaming/Dockerfile # context: . image:ghcr.io/mastodon/mastodon-streaming:v4.5.2 restart:always env_file:.env.production command:node./streaming/index.js networks: -external_network -internal_network healthcheck: # prettier-ignore test: ['CMD-SHELL', "curl -s --noproxy localhost localhost:4000/api/v1/streaming/health | grep -q 'OK' || exit 1"] ports: -'127.0.0.1:4000:4000' depends_on: -db -redis
sidekiq: # You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes # build: . image:ghcr.io/mastodon/mastodon:v4.5.2 restart:always env_file:.env.production command:bundleexecsidekiq depends_on: -db -redis networks: -external_network -internal_network volumes: -./public/system:/mastodon/public/system healthcheck: test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 8' || false"]
## Uncomment to enable federation with tor instances along with adding the following ENV variables ## http_hidden_proxy=http://privoxy:8118 ## ALLOW_ACCESS_TO_HIDDEN_SERVICE=true # tor: # image: sirboops/tor # networks: # - external_network # - internal_network # # privoxy: # image: sirboops/privoxy # volumes: # - ./priv-config:/opt/config # networks: # - external_network # - internal_network
➜ mastodon git:(main) docker compose run -e RAILS_ENV=production --rm -- web bundle exec bin/rails mastodon:setup [+] Creating 4/4 ✔ Network mastodon_internal_network Created 0.0s ✔ Network mastodon_external_network Created 0.0s ✔ Container mastodon-redis-1 Created 0.1s ✔ Container mastodon-db-1 Created 0.1s [+] Running 2/2 ✔ Container mastodon-redis-1 Started 0.2s ✔ Container mastodon-db-1 Started 0.2s Your instance is identified by its domain name. Changing it afterward will break things. Domain name: example.com
Single user mode disables registrations and redirects the landing page to your public profile. Do you want to enable single user mode? No
Are you using Docker to run Mastodon? Yes
PostgreSQL host: db PostgreSQL port: 5432 Name of PostgreSQL database: postgres Name of PostgreSQL user: postgres Password of PostgreSQL user: Database configuration works! 🎆
Do you want to store uploaded files on the cloud? No
Do you want to send e-mails from localhost? No
SMTP server: smtp.mailgun.org SMTP port: 587 SMTP username: a SMTP password: SMTP authentication: plain SMTP OpenSSL verify mode: none Enable STARTTLS: auto E-mail address to send e-mails "from": Mastodon <notifications@codegeass.cc> Send a test e-mail with this configuration right now? no
Do you want Mastodon to periodically check for important updates and notify you? (Recommended) no
This configuration will be written to .env.production Save configuration? Yes Below is your configuration, save it to an .env.production file outside Docker:
It is also saved within this container so you can proceed with this wizard.
Now that configuration is saved, the database schema must be loaded. If the database already exists, this will erase its contents. Prepare the database now? Yes Running `RAILS_ENV=production rails db:setup` ...
I, [2025-11-21T09:01:07.354171 #76] INFO -- : [dotenv] Loaded .env.production Database 'postgres' already exists Done!
All done! You can now power on the Mastodon server 🐘
Do you want to create an admin user straight away? no
upstream streaming { # Instruct nginx to send connections to the server with the least number of connections # to ensure load is distributed evenly. least_conn;
server127.0.0.1:4000 fail_timeout=0; # Uncomment these lines for load-balancing multiple instances of streaming for scaling, # this assumes your running the streaming server on ports 4000, 4001, and 4002: # server 127.0.0.1:4001 fail_timeout=0; # server 127.0.0.1:4002 fail_timeout=0; }
# You can use https://ssl-config.mozilla.org/ to generate your cipher set. # We recommend their "Intermediate" level. ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
# Uncomment these lines once you acquire a certificate: ssl_certificate /path/to/cer/file; ssl_certificate_key /path/to/key/file; ssl_dhparam /path/to/dhparams.pem;
keepalive_timeout70; sendfileon; client_max_body_size99m; proxy_read_timeout120; ## Increase if you experience 504 errors uploading media
# If Docker is used for deployment and Rails serves static files, # then needed uncomment line with `try_files $uri @mastodon;`. location ^~ /assets/ { add_header Cache-Control "public, max-age=2419200, must-revalidate"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; try_files$uri@mastodon; }