refactor!(mastodon): Migrate to podman quadlet

This commit is contained in:
Saibotk 2025-01-18 17:10:42 +01:00
parent 2e271b6c96
commit 476660fd65
Signed by: saibotk
GPG key ID: 67585F0065E261D5
26 changed files with 1473 additions and 732 deletions

View file

@ -1,25 +1,17 @@
---
# Infrastructure
# Ansible instructions to deploy the infrastructure
# Copyright (C) 2019-2020 Christoph (Sheogorath) Kern
# Copyright (C) 2020 Saibotk
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
- name: Install Mastodon.
- name: Install & configure Mastodon
hosts: mastodon
roles:
- docker
- docker_cleanup
- traefik
- mastodon
- role: podman
become: true
tags:
- always
- podman
- role: caddy
become: true
tags:
- always
- caddy
- role: mastodon
become: true

View file

@ -1,37 +0,0 @@
Mastodon
=========
This will setup a Mastodon instance using their official docker container and traefik as a reverse proxy.
**Note: This role will also care about migrations etc, when upgrading to a new version!**
Requirements
------------
You will need to have docker, docker-compose and traefik installed or declared as dependencies with their respective roles.
**This role assumes that you have setup traefik with an endpoint called `websecure`.**
Role Variables
--------------
**Please look at the [defaults/main.yml](defaults/main.yml) for all available variables and their description.**
**Note: Lines that are commented out via `#` are usually still valid/used variables, but they are not defined by default, so they might enable a feature, when uncommenting/defining them!**
### Global variables, that are used:
- `proxy_network`: Defined by the local traefik installation, this is the shared proxy network used by traefik to reach the containers. (optional)
- `proxy_hiddenservice`: Defined by the local traefik installation, this is used to generate the alt-svc header for the alternative Tor domain. (optional)
Dependencies
------------
- docker
- docker-compose
- traefik
License
-------
GPL-3.0-only

View file

@ -1,39 +1,10 @@
---
# Default variables for the mastodon role
# Infrastructure
# Ansible instructions to deploy the infrastructure
# Copyright (C) 2019-2020 Christoph (Sheogorath) Kern
# Copyright (C) 2020 Saibotk
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# The install location
mastodon_install_location: /srv/mastodon
# The container data volume mount locations
mastodon_database_location: "{{ mastodon_install_location }}/postgres"
mastodon_public_location: "{{ mastodon_install_location }}/public"
mastodon_redis_location: "{{ mastodon_install_location }}/redis"
mastodon_elastic_location: "{{ mastodon_install_location }}/elasticsearch"
mastodon_nginx_location: "{{ mastodon_install_location }}/nginx"
# The certresolver that is used by traefik for this domain
mastodon_traefik_certresolver: letsencrypt_http
# The domain that traefik will server mastodon under
mastodon_domain: mastodon.example.com
mastodon_postgres_password: "{{ lookup('passwordstore', 'mastodon.example.com/database create=true') }}"
# The mastodon configuration (see mastodon documentation for a reference / the `templates/.env.production` file)
mastodon_config:
local_domain: "{{ mastodon_domain }}"
@ -48,23 +19,66 @@ mastodon_config:
smtp_login: undef
smtp_password: undef
smtp_from_address: mastodon@example.com
enable_elasticsearch: false
# Should we automatically adjust the needed sysctl setting for vm.max_map_count?
mastodon_elasticsearch_adjust_sysctl: true
# Container versions
mastodon_streaming_containerimage: ghcr.io/mastodon/mastodon-streaming
mastodon_containerimage: ghcr.io/mastodon/mastodon
# renovate: depName=ghcr.io/mastodon/mastodon
mastodon_version: 4.3.2
# renovate: depName=docker.io/library/postgres
mastodon_database_version: 15.8
# renovate: depName=docker.io/library/redis
mastodon_redis_version: 7.4
# renovate: depName=docker.elastic.co/elasticsearch/elasticsearch
mastodon_elasticsearch_version: 7.17.25
mastodon_image_tag: "v4.3.3"
# Container tag definitions
mastodon_image_version: "v{{ mastodon_version }}"
mastodon_database_image_version: "{{ mastodon_database_version }}-alpine"
mastodon_redis_image_version: "{{ mastodon_redis_version }}-alpine"
mastodon_elasticsearch_image_version: "{{ mastodon_elasticsearch_version }}"
mastodon_nginx_containerimage: docker.io/nginxinc/nginx-unprivileged
# renovate: depName=docker.io/nginxinc/nginx-unprivileged
mastodon_nginx_image_tag: "1.27.3-alpine"
mastodon_postgres_containerimage: docker.io/library/postgres
# renovate: depName=docker.io/library/postgres
mastodon_postgres_image_tag: "17.2-alpine"
mastodon_redis_containerimage: docker.io/library/redis
# renovate: depName=docker.io/library/redis
mastodon_redis_image_tag: "7.4-alpine"
mastodon_elasticsearch_containerimage: docker.io/library/elasticsearch
# renovate: depName=docker.io/library/elasticsearch
mastodon_elasticsearch_image_tag: "7.17.26"
mastodon_selinux_level: "{{ omit }}"
mastodon_nginx_selinux_level: "{{ omit }}"
mastodon_postgres_selinux_level: "{{ omit }}"
mastodon_redis_selinux_level: "{{ omit }}"
mastodon_elasticsearch_selinux_level: "{{ omit }}"
## This will be used for the `mastodon_public_location` which will need to
## be accessed by the main mastodon containers and by nginx.
## Make sure it is accessible/compatible with `mastodon_selinux_level`
## and `mastodon_nginx_selinux_level`.
mastodon_public_selinux_level: "{{ omit }}"
mastodon_memory_low: 512m
mastodon_memory_high: 0
mastodon_swap_max: -1
mastodon_sidekiq_memory_low: 512m
mastodon_sidekiq_memory_high: 0
mastodon_sidekiq_swap_max: -1
mastodon_streaming_memory_low: 64m
mastodon_streaming_memory_high: 256m
mastodon_streaming_swap_max: -1
mastodon_nginx_memory_low: 32m
mastodon_nginx_memory_high: 64m
mastodon_nginx_swap_max: -1
mastodon_redis_memory_low: 128m
mastodon_redis_memory_high: 512m
mastodon_redis_swap_max: -1
mastodon_elasticsearch_low: 1024m
mastodon_elasticsearch_memory_high: 1536m
mastodon_elasticsearch_swap_max: -1
mastodon_postgres_memory_low: 512m
mastodon_postgres_memory_high: 0
mastodon_postgres_swap_max: -1

View file

@ -1,14 +1,84 @@
---
# Handlers file for the mastodon role
- name: Pull mastodon image
community.docker.docker_image:
name: "docker.io/tootsuite/mastodon:{{ mastodon_image_version }}"
source: pull
- name: Apply new SELinux file context to filesystem.
ansible.builtin.command: "restorecon -irF {{ mastodon_install_location }}"
become: true
listen: "mastodon selinux context changed"
changed_when: false
- name: Stop mastodon for upgrade
community.docker.docker_compose_v2:
state: stopped
project_src: "{{ mastodon_install_location }}"
- name: Restart mastodon web service.
ansible.builtin.systemd:
state: restarted
name: mastodon-web.service
daemon_reload: true
become: true
listen:
- "mastodon web service changed"
- "mastodon selinux context changed"
- "mastodon postgres socket changed"
- "mastodon redis socket changed"
- "mastodon env changed"
- name: Restart mastodon streaming service.
ansible.builtin.systemd:
state: restarted
name: mastodon-streaming.service
daemon_reload: true
become: true
listen:
- "mastodon streaming service changed"
- "mastodon selinux context changed"
- "mastodon postgres socket changed"
- "mastodon redis socket changed"
- "mastodon env changed"
- name: Restart mastodon sidekiq service.
ansible.builtin.systemd:
state: restarted
name: mastodon-sidekiq.service
daemon_reload: true
become: true
listen:
- "mastodon sidekiq service changed"
- "mastodon selinux context changed"
- "mastodon postgres socket changed"
- "mastodon redis socket changed"
- "mastodon env changed"
- name: Restart mastodon postgres service.
ansible.builtin.systemd:
state: restarted
name: mastodon-postgres.service
daemon_reload: true
become: true
listen:
- "mastodon postgres service changed"
- "mastodon selinux context changed"
- name: Restart mastodon redis service.
ansible.builtin.systemd:
state: restarted
name: mastodon-redis.service
daemon_reload: true
become: true
listen:
- "mastodon redis service changed"
- "mastodon selinux context changed"
- name: Restart mastodon nginx service.
ansible.builtin.systemd:
state: restarted
name: mastodon-nginx.service
daemon_reload: true
become: true
listen:
- "mastodon nginx service changed"
- "mastodon selinux context changed"
- name: Restart mastodon elasticsearch service.
ansible.builtin.systemd:
state: restarted
name: mastodon-elasticsearch.service
daemon_reload: true
become: true
listen:
- "mastodon elasticsearch service changed"
- "mastodon selinux context changed"

View file

@ -1,44 +1,20 @@
galaxy_info:
author: saibotk
description: "Deploys a mastodon server via docker using traefik."
description: Deploy mastodon with podman and systemd.
issue_tracker_url: https://git.saibotk.de/saibotk.de/infrastructure/-/issues
license: GPL-3.0-only
min_ansible_version: "2.9"
standalone: true
min_ansible_version: "2.10"
platforms:
- name: EL
versions:
- all
- name: GenericUNIX
versions:
- all
- name: Fedora
versions:
- all
- name: opensuse
versions:
- all
- name: GenericBSD
versions:
- all
- name: FreeBSD
versions:
- all
- name: Ubuntu
versions:
- all
- name: SLES
versions:
- all
- name: GenericLinux
versions:
- all
- name: Debian
versions:
- all
- "41"
standalone: true
galaxy_tags: []
dependencies:
- role: docker
- role: traefik
dependencies: []

View file

@ -1,69 +1,80 @@
---
# Tasks file for the mastodon role
# Infrastructure
# Ansible instructions to deploy the infrastructure
# Copyright (C) 2019-2020 Christoph (Sheogorath) Kern
# Copyright (C) 2020 Alexander Wellbrock
# Copyright (C) 2020 Saibotk
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
- name: Update default SELinux contexts
community.general.sefcontext:
target: "{{ item }}(/.*)?"
target: "{{ item.target }}"
setype: "container_file_t"
selevel: "{{ item.selevel }}"
state: present
with_items:
- "{{ mastodon_database_location }}"
- "{{ mastodon_public_location }}"
- "{{ mastodon_redis_location }}"
- "{{ mastodon_elastic_location }}"
- "{{ mastodon_nginx_location }}"
loop:
- target: "{{ mastodon_public_location }}(/.*)?"
selevel: "{{ mastodon_public_selinux_level }}"
- target: "{{ mastodon_postgres_location }}(/.*)?"
selevel: "{{ mastodon_postgres_selinux_level }}"
- target: "{{ mastodon_redis_location }}(/.*)?"
selevel: "{{ mastodon_redis_selinux_level }}"
- target: "{{ mastodon_install_location }}/redis.conf"
selevel: "{{ mastodon_redis_selinux_level }}"
- target: "{{ mastodon_elasticsearch_location }}(/.*)?"
selevel: "{{ mastodon_elasticsearch_selinux_level }}"
- target: "{{ mastodon_install_location }}/default.conf"
selevel: "{{ mastodon_nginx_selinux_level }}"
become: true
notify: "mastodon selinux context changed"
- name: Create install directory
- name: Create mastodon directories.
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: "0700"
path: "{{ mastodon_install_location }}"
owner: "root"
group: "root"
with_items:
- "{{ mastodon_install_location }}"
become: true
- name: Create data directories
ansible.builtin.file: # noqa risky-file-permissions # Container manages permissions on its own
path: "{{ item }}"
mode: "0700"
state: directory
setype: "container_file_t"
with_items:
- "{{ mastodon_database_location }}"
- "{{ mastodon_public_location }}"
- "{{ mastodon_redis_location }}"
- "{{ mastodon_elastic_location }}"
- "{{ mastodon_nginx_location }}"
become: true
- name: Adjust elasticsearch directory permissions
- name: Ensure mastodon data directories exist.
block:
- name: Stat mastodon public dir.
ansible.builtin.stat:
path: "{{ mastodon_public_location }}"
become: true
register: mastodon_stat_public_dir
- name: Stat mastodon postgres dir.
ansible.builtin.stat:
path: "{{ mastodon_postgres_location }}"
become: true
register: mastodon_stat_postgres_dir
- name: Stat mastodon redis dir.
ansible.builtin.stat:
path: "{{ mastodon_redis_location }}"
become: true
register: mastodon_stat_redis_dir
- name: Stat mastodon elasticsearch dir.
ansible.builtin.stat:
path: "{{ mastodon_elasticsearch_location }}"
become: true
register: mastodon_stat_elasticsearch_dir
- name: Create mastodon data directories.
ansible.builtin.file:
path: "{{ mastodon_elastic_location }}"
path: "{{ item.path }}"
state: directory
setype: "container_file_t"
mode: "0750"
owner: 1000
group: "root"
mode: "0700"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
loop:
- path: "{{ mastodon_public_location }}"
owner: "{{ mastodon_stat_public_dir.stat.uid | default('root') }}"
group: "{{ mastodon_stat_public_dir.stat.gid | default('root') }}"
- path: "{{ mastodon_postgres_location }}"
owner: "{{ mastodon_stat_postgres_dir.stat.uid | default('root') }}"
group: "{{ mastodon_stat_postgres_dir.stat.gid | default('root') }}"
- path: "{{ mastodon_redis_location }}"
owner: "{{ mastodon_stat_redis_dir.stat.uid | default('root') }}"
group: "{{ mastodon_stat_redis_dir.stat.gid | default('root') }}"
- path: "{{ mastodon_elasticsearch_location }}"
owner: "{{ mastodon_stat_elasticsearch_dir.stat.uid | default('root') }}"
group: "{{ mastodon_stat_elasticsearch_dir.stat.gid | default('root') }}"
become: true
- name: Adjust sysctl settings for elasticsearch
@ -71,102 +82,228 @@
name: vm.max_map_count
value: "262144"
state: present
when:
- mastodon_config.enable_elasticsearch is defined and mastodon_config.enable_elasticsearch
- mastodon_elasticsearch_adjust_sysctl
become: true
- name: Create public data directory
ansible.builtin.file:
path: "{{ mastodon_public_location }}/system"
mode: "0755"
owner: "991"
group: "991"
state: directory
- name: Deploy redis config file.
ansible.builtin.template:
src: redis.conf.j2
dest: "{{ mastodon_install_location }}/redis.conf"
owner: "{{ mastodon_stat_redis_dir.stat.uid | default('root') }}"
group: "{{ mastodon_stat_redis_dir.stat.gid | default('root') }}"
mode: "0600"
become: true
notify: "mastodon redis service changed"
- name: Deploy mastodon environment file.
ansible.builtin.template:
src: mastodon.env.j2
dest: "{{ mastodon_install_location }}/mastodon.env"
mode: "0600"
owner: "root"
group: "root"
become: true
notify: "mastodon env changed"
- name: Deploy postgres environment file.
ansible.builtin.template:
src: mastodon-postgres.env.j2
dest: "{{ mastodon_install_location }}/mastodon-postgres.env"
mode: "0600"
owner: "root"
group: "root"
become: true
- name: Deploy elasticsearch environment file.
ansible.builtin.template:
src: mastodon-elasticsearch.env.j2
dest: "{{ mastodon_install_location }}/mastodon-elasticsearch.env"
mode: "0600"
owner: "root"
group: "root"
become: true
- name: Add caddy config file.
block:
- name: Check caddy config dir.
ansible.builtin.stat:
path: "{{ caddy_install_dir }}/config"
become: true
register: caddy_stat_config_dir
- name: Template caddy config for mastodon.
ansible.builtin.template:
src: mastodon.caddy.j2
dest: "{{ caddy_install_dir }}/config/mastodon.caddy"
mode: "0600"
setype: "container_file_t"
selevel: "{{ caddy_selinux_level }}"
owner: "{{ caddy_stat_config_dir.stat.uid }}"
group: "{{ caddy_stat_config_dir.stat.gid }}"
notify: "caddy config changed"
become: true
- name: Deploy nginx proxy config file
- name: Ensure mastodon nginx config exists.
block:
- name: Stat mastodon nginx config.
ansible.builtin.stat:
path: "{{ mastodon_install_location }}/default.conf"
become: true
register: mastodon_stat_nginx_config
- name: Deploy mastodon nginx config.
ansible.builtin.template:
src: "default.conf"
dest: "{{ mastodon_nginx_location }}/default.conf"
src: default.conf.j2
dest: "{{ mastodon_install_location }}/default.conf"
mode: "0600"
owner: "{{ mastodon_stat_nginx_config.stat.uid | default('root') }}"
group: "{{ mastodon_stat_nginx_config.stat.gid | default('root') }}"
setype: "container_file_t"
selevel: "{{ mastodon_nginx_selinux_level }}"
become: true
notify: "mastodon nginx service changed"
- name: Create mastodon postgres socket volume.
ansible.builtin.template:
src: mastodon-postgres-socket.volume
dest: /etc/containers/systemd/mastodon-postgres-socket.volume
owner: "root"
group: "root"
mode: "0644"
become: true
notify:
- "mastodon postgres socket changed"
- name: Check if migration is needed
ansible.builtin.command: "grep -q 'mastodon/mastodon:{{ mastodon_image_version }}' '{{ mastodon_install_location }}/docker-compose.yml'"
register: mastodon_version_fact
ignore_errors: true
changed_when: mastodon_version_fact.rc > 0
failed_when: false
become: true
notify: ["Pull mastodon image", "Stop mastodon for upgrade"]
- name: Immediately run / flush Ansible handlers
ansible.builtin.meta: "flush_handlers"
- name: Deploy config
- name: Create mastodon redis socket volume.
ansible.builtin.template:
src: ".env.production"
dest: "{{ mastodon_install_location }}/.env.production"
mode: "0600"
src: mastodon-redis-socket.volume
dest: /etc/containers/systemd/mastodon-redis-socket.volume
owner: "root"
group: "root"
tags:
- mastodon
mode: "0644"
become: true
notify:
- "mastodon redis socket changed"
- name: Deploy docker-compose.yml
- name: Create mastodon web container file.
ansible.builtin.template:
src: "docker-compose.yml"
dest: "{{ mastodon_install_location }}/docker-compose.yml"
mode: "0600"
src: mastodon-web.container.j2
dest: /etc/containers/systemd/mastodon-web.container
owner: "root"
group: "root"
validate: docker compose -f %s config -q
tags:
- mastodon
mode: "0644"
become: true
notify: "mastodon web service changed"
- name: Create mastodon streaming container file.
ansible.builtin.template:
src: mastodon-streaming.container.j2
dest: /etc/containers/systemd/mastodon-streaming.container
owner: "root"
group: "root"
mode: "0644"
become: true
notify: "mastodon streaming service changed"
- name: Create mastodon sidekiq container file.
ansible.builtin.template:
src: mastodon-sidekiq.container.j2
dest: /etc/containers/systemd/mastodon-sidekiq.container
owner: "root"
group: "root"
mode: "0644"
become: true
notify: "mastodon sidekiq service changed"
- name: Create mastodon postgres container file.
ansible.builtin.template:
src: mastodon-postgres.container.j2
dest: /etc/containers/systemd/mastodon-postgres.container
owner: "root"
group: "root"
mode: "0644"
become: true
notify: "mastodon postgres service changed"
- name: Create mastodon redis container file.
ansible.builtin.template:
src: mastodon-redis.container.j2
dest: /etc/containers/systemd/mastodon-redis.container
owner: "root"
group: "root"
mode: "0644"
become: true
notify: "mastodon redis service changed"
- name: Create mastodon elasticsearch container file.
ansible.builtin.template:
src: mastodon-elasticsearch.container.j2
dest: /etc/containers/systemd/mastodon-elasticsearch.container
owner: "root"
group: "root"
mode: "0644"
become: true
notify: "mastodon elasticsearch service changed"
- name: Create mastodon nginx container file.
ansible.builtin.template:
src: mastodon-nginx.container.j2
dest: /etc/containers/systemd/mastodon-nginx.container
owner: "root"
group: "root"
mode: "0644"
become: true
notify: "mastodon nginx service changed"
# TODO: Quadlet does not change networks when their definition changes
# We need to find a solution to recreate the network
- name: Create mastodon frontend network definition file.
ansible.builtin.template:
src: mastodon-frontend.network.j2
dest: "/etc/containers/systemd/mastodon-frontend.network"
owner: "root"
group: "root"
mode: "0644"
become: true
- name: Migrate database
ansible.builtin.command: "docker-compose run --rm web rails db:migrate"
args:
chdir: "{{ mastodon_install_location }}"
when:
# noqa no-handler
- mastodon_version_fact is changed
tags:
- docker
- mastodon
# TODO: Quadlet does not change networks when their definition changes
# We need to find a solution to recreate the network
- name: Create mastodon backend network definition file.
ansible.builtin.template:
src: mastodon-backend.network.j2
dest: "/etc/containers/systemd/mastodon-backend.network"
owner: "root"
group: "root"
mode: "0644"
become: true
changed_when: true
environment:
PYTHONPATH: ""
- name: Clear cache
ansible.builtin.command: docker-compose run --rm web bin/tootctl cache clear
args:
chdir: "{{ mastodon_install_location }}"
when:
# noqa no-handler
- mastodon_version_fact is changed
tags:
- docker
- mastodon
- name: Ensure mastodon services are enabled.
ansible.builtin.systemd:
enabled: true
name: "{{ item }}"
daemon_reload: true
loop:
- mastodon-postgres.service
- mastodon-redis.service
- mastodon-elasticsearch.service
- mastodon-web.service
- mastodon-streaming.service
- mastodon-sidekiq.service
- mastodon-nginx.service
become: true
changed_when: true
environment:
PYTHONPATH: ""
- name: Compose mastodon
community.docker.docker_compose_v2:
state: present
project_src: "{{ mastodon_install_location }}"
pull: always
remove_orphans: true
tags:
- docker
- mastodon
- name: Flush handlers
ansible.builtin.meta: flush_handlers
- name: Ensure mastodon services are started.
ansible.builtin.systemd:
state: started
name: "{{ item }}"
loop:
- mastodon-postgres.service
- mastodon-redis.service
- mastodon-elasticsearch.service
- mastodon-web.service
- mastodon-streaming.service
- mastodon-sidekiq.service
- mastodon-nginx.service
become: true

View file

@ -1,266 +0,0 @@
{{ ansible_managed | comment }}
# Service dependencies
# You may set REDIS_URL instead for more advanced options
# You may also set REDIS_NAMESPACE to share Redis between multiple Mastodon servers
REDIS_HOST=redis
REDIS_PORT=6379
# You may set DATABASE_URL instead for more advanced options
DB_HOST=db
DB_USER=postgres
DB_NAME=postgres
DB_PASS=
DB_PORT=5432
{% if mastodon_config.enable_elasticsearch is defined %}
# Optional ElasticSearch configuration
# You may also set ES_PREFIX to share the same cluster between multiple Mastodon servers (falls back to REDIS_NAMESPACE if not set)
ES_ENABLED={{ mastodon_config.enable_elasticsearch | bool | lower }}
ES_HOST=es
ES_PORT=9200
{% endif %}
# Federation
# Note: Changing LOCAL_DOMAIN at a later time will cause unwanted side effects, including breaking all existing federation.
# LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com.
LOCAL_DOMAIN={{ mastodon_config.local_domain }}
# Changing LOCAL_HTTPS in production is no longer supported. (Mastodon will always serve https:// links)
{% if mastodon_config.web_domain is defined %}
# Use this only if you need to run mastodon on a different domain than the one used for federation.
# You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md
# DO *NOT* USE THIS UNLESS YOU KNOW *EXACTLY* WHAT YOU ARE DOING.
WEB_DOMAIN={{ mastodon_config.web_domain }}
{% endif %}
# Use this if you want to have several aliases handler@example1.com
# handler@example2.com etc. for the same user. LOCAL_DOMAIN should not
# be added. Comma separated values
# ALTERNATE_DOMAINS=example1.com,example2.com
# Application secrets
# Generate each with the `RAILS_ENV=production bundle exec rails secret` task (`docker-compose run --rm web rails secret` if you use docker compose)
SECRET_KEY_BASE={{ mastodon_config.secret_key_base }}
OTP_SECRET={{ mastodon_config.otp_secret }}
# DB encryption secrets
# Generate them yourself, each 32 alphanumeric or
# Generate them with `RAILS_ENV=production bundle exec rails db:encryption:init` task (`docker-compose run --rm web rails db:encryption:init` if you use docker compose)
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY={{ mastodon_config.ar_enc_deterministic_key }}
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT={{ mastodon_config.ar_enc_derivation_salt }}
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY={{ mastodon_config.ar_enc_primary_key }}
# VAPID keys (used for push notifications
# You can generate the keys using the following command (first is the private key, second is the public one)
# You should only generate this once per instance. If you later decide to change it, all push subscription will
# be invalidated, requiring the users to access the website again to resubscribe.
#
# Generate with `RAILS_ENV=production bundle exec rails mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rails mastodon:webpush:generate_vapid_key` if you use docker compose)
#
# For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html
VAPID_PRIVATE_KEY={{ mastodon_config.vapid_private_key }}
VAPID_PUBLIC_KEY={{ mastodon_config.vapid_public_key }}
# Registrations
{% if mastodon_config.single_user_mode is defined %}
# Single user mode will disable registrations and redirect frontpage to the first profile
SINGLE_USER_MODE={{ mastodon_config.single_user_mode | bool | lower }}
{% endif %}
# Prevent registrations with following e-mail domains
# EMAIL_DOMAIN_BLACKLIST=example1.com|example2.de|etc
# Only allow registrations with the following e-mail domains
# EMAIL_DOMAIN_WHITELIST=example1.com|example2.de|etc
# Optionally change default language
# DEFAULT_LOCALE=de
# E-mail configuration
# Note: Mailgun and SparkPost (https://sparkpo.st/smtp) each have good free tiers
# If you want to use an SMTP server without authentication (e.g local Postfix relay)
# then set SMTP_AUTH_METHOD and SMTP_OPENSSL_VERIFY_MODE to 'none' and
# *comment* SMTP_LOGIN and SMTP_PASSWORD (leaving them blank is not enough).
SMTP_SERVER={{ mastodon_config.smtp_server }}
SMTP_PORT={{ mastodon_config.smtp_port | default(587) }}
SMTP_LOGIN={{ mastodon_config.smtp_login }}
SMTP_PASSWORD={{ mastodon_config.smtp_password }}
SMTP_FROM_ADDRESS={{ mastodon_config.smtp_from_address }}
#SMTP_REPLY_TO=
#SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
#SMTP_AUTH_METHOD=plain
#SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt
#SMTP_OPENSSL_VERIFY_MODE=peer
#SMTP_ENABLE_STARTTLS_AUTO=true
#SMTP_TLS=true
# Optional user upload path and URL (images, avatars). Default is :rails_root/public/system. If you set this variable, you are responsible for making your HTTP server (eg. nginx) serve these files.
# PAPERCLIP_ROOT_PATH=/var/lib/mastodon/public-system
# PAPERCLIP_ROOT_URL=/system
# Optional asset host for multi-server setups
# The asset host must allow cross origin request from WEB_DOMAIN or LOCAL_DOMAIN
# if WEB_DOMAIN is not set. For example, the server may have the
# following header field:
# Access-Control-Allow-Origin: https://example.com/
# CDN_HOST=https://assets.example.com
# S3 (optional)
# The attachment host must allow cross origin request from WEB_DOMAIN or
# LOCAL_DOMAIN if WEB_DOMAIN is not set. For example, the server may have the
# following header field:
# Access-Control-Allow-Origin: https://192.168.1.123:9000/
# S3_ENABLED=true
# S3_BUCKET=
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# S3_REGION=
# S3_PROTOCOL=http
# S3_HOSTNAME=192.168.1.123:9000
# S3 (Minio Config (optional) Please check Minio instance for details)
# The attachment host must allow cross origin request - see the description
# above.
# S3_ENABLED=true
# S3_BUCKET=
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# S3_REGION=
# S3_PROTOCOL=https
# S3_HOSTNAME=
# S3_ENDPOINT=
# S3_SIGNATURE_VERSION=
# Google Cloud Storage (optional)
# Use S3 compatible API. Since GCS does not support Multipart Upload,
# increase the value of S3_MULTIPART_THRESHOLD to disable Multipart Upload.
# The attachment host must allow cross origin request - see the description
# above.
# S3_ENABLED=true
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# S3_REGION=
# S3_PROTOCOL=https
# S3_HOSTNAME=storage.googleapis.com
# S3_ENDPOINT=https://storage.googleapis.com
# S3_MULTIPART_THRESHOLD=52428801 # 50.megabytes
# Swift (optional)
# The attachment host must allow cross origin request - see the description
# above.
# SWIFT_ENABLED=true
# SWIFT_USERNAME=
# For Keystone V3, the value for SWIFT_TENANT should be the project name
# SWIFT_TENANT=
# SWIFT_PASSWORD=
# Some OpenStack V3 providers require PROJECT_ID (optional)
# SWIFT_PROJECT_ID=
# Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid
# issues with token rate-limiting during high load.
# SWIFT_AUTH_URL=
# SWIFT_CONTAINER=
# SWIFT_OBJECT_URL=
# SWIFT_REGION=
# Defaults to 'default'
# SWIFT_DOMAIN_NAME=
# Defaults to 60 seconds. Set to 0 to disable
# SWIFT_CACHE_TTL=
# Optional alias for S3 (e.g. to serve files on a custom domain, possibly using Cloudfront or Cloudflare)
# S3_ALIAS_HOST=
# Streaming API integration
# STREAMING_API_BASE_URL=
# Advanced settings
# If you need to use pgBouncer, you need to disable prepared statements:
# PREPARED_STATEMENTS=false
# Cluster number setting for streaming API server.
# If you comment out following line, cluster number will be `numOfCpuCores - 1`.
STREAMING_CLUSTER_NUM=1
# Docker mastodon user
# If you use Docker, you may want to assign UID/GID manually.
{% if mastodon_config.docker_uid is defined %}
UID={{ mastodon_config.docker_uid }}
{% endif %}
{% if mastodon_config.docker_gid is defined %}
GID={{ mastodon_config.docker_gid }}
{% endif %}
# LDAP authentication (optional)
# LDAP_ENABLED=true
# LDAP_HOST=localhost
# LDAP_PORT=389
# LDAP_METHOD=simple_tls
# LDAP_BASE=
# LDAP_BIND_DN=
# LDAP_PASSWORD=
# LDAP_UID=cn
# LDAP_SEARCH_FILTER=%{uid}=%{email}
# PAM authentication (optional)
# PAM authentication uses for the email generation the "email" pam variable
# and optional as fallback PAM_DEFAULT_SUFFIX
# The pam environment variable "email" is provided by:
# https://github.com/devkral/pam_email_extractor
# PAM_ENABLED=true
# Fallback email domain for email address generation (LOCAL_DOMAIN by default)
# PAM_EMAIL_DOMAIN=example.com
# Name of the pam service (pam "auth" section is evaluated)
# PAM_DEFAULT_SERVICE=rpam
# Name of the pam service used for checking if an user can register (pam "account" section is evaluated) (nil (disabled) by default)
# PAM_CONTROLLED_SERVICE=rpam
# Global OAuth settings (optional) :
# If you have only one strategy, you may want to enable this
# OAUTH_REDIRECT_AT_SIGN_IN=true
# Optional CAS authentication (cf. omniauth-cas) :
# CAS_ENABLED=true
# CAS_URL=https://sso.myserver.com/
# CAS_HOST=sso.myserver.com/
# CAS_PORT=443
# CAS_SSL=true
# CAS_VALIDATE_URL=
# CAS_CALLBACK_URL=
# CAS_LOGOUT_URL=
# CAS_LOGIN_URL=
# CAS_UID_FIELD='user'
# CAS_CA_PATH=
# CAS_DISABLE_SSL_VERIFICATION=false
# CAS_UID_KEY='user'
# CAS_NAME_KEY='name'
# CAS_EMAIL_KEY='email'
# CAS_NICKNAME_KEY='nickname'
# CAS_FIRST_NAME_KEY='firstname'
# CAS_LAST_NAME_KEY='lastname'
# CAS_LOCATION_KEY='location'
# CAS_IMAGE_KEY='image'
# CAS_PHONE_KEY='phone'
# Optional SAML authentication (cf. omniauth-saml)
#SAML_ENABLED=true
#SAML_ACS_URL=https://flausch.social/auth/auth/saml/callback
#SAML_ISSUER=mastodon
#SAML_IDP_SSO_TARGET_URL=https://auth.the-rainbow-unicorns.de/auth/realms/unicorns/protocol/saml/clients/mastodon
#SAML_IDP_CERT=
#SAML_IDP_CERT_FINGERPRINT=
#SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
#SAML_CERT=
#SAML_PRIVATE_KEY=
#SAML_SECURITY_WANT_ASSERTION_SIGNED=true
#SAML_SECURITY_WANT_ASSERTION_ENCRYPTED=true
#SAML_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true
#SAML_ATTRIBUTES_STATEMENTS_UID=name
#SAML_ATTRIBUTES_STATEMENTS_EMAIL=email
#SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.16.840.1.113730.3.1.241"
#SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME="urn:oid:2.5.4.42"
#SAML_ATTRIBUTES_STATEMENTS_LAST_NAME="urn:oid:2.5.4.4"
#SAML_UID_ATTRIBUTE=name
#SAML_ATTRIBUTES_STATEMENTS_VERIFIED=
#SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL=
# Use HTTP proxy for outgoing request (optional)
# http_proxy=http://gateway.local:8118
# Access control for hidden service.
# ALLOW_ACCESS_TO_HIDDEN_SERVICE=true

View file

@ -3,12 +3,29 @@ map $http_upgrade $connection_upgrade {
'' close;
}
upstream backend {
server backend-mastodon-web:3000 fail_timeout=0;
}
upstream streaming {
# Instruct nginx to send connections to the server with the least number of connections
# to ensure load is distributed evenly.
least_conn;
server backend-mastodon-streaming: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;
}
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g;
server {
listen 80;
listen [::]:80;
listen 8080;
listen [::]:8080;
server_name {{ mastodon_domain }};
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
@ -29,6 +46,7 @@ server {
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml image/x-icon;
gzip_static on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
@ -60,7 +78,7 @@ server {
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Proxy "";
proxy_pass http://streaming:4000;
proxy_pass http://streaming;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
@ -78,7 +96,7 @@ server {
proxy_set_header Proxy "";
proxy_pass_header Server;
proxy_pass http://web:3000;
proxy_pass http://backend;
proxy_buffering on;
proxy_redirect off;
proxy_http_version 1.1;
@ -94,7 +112,5 @@ server {
tcp_nodelay on;
}
error_page 404 500 501 502 503 504 /500.html;
}

View file

@ -1,179 +0,0 @@
{{ ansible_managed | comment }}
# Infrastructure
# Ansible instructions to deploy the infrastructure
# Copyright (C) 2019-2020 Christoph (Sheogorath) Kern
# Copyright (C) 2020 Saibotk
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
version: '2.1'
services:
nginx:
image: docker.io/library/nginx:alpine
mem_limit: 32mb
memswap_limit: 64mb
labels:
- "traefik.http.routers.mastodon.rule=Host(`{{ mastodon_domain }}`) && PathPrefix(`/`)"
- "traefik.http.routers.mastodon.entrypoints=websecure"
- "traefik.http.routers.mastodon.tls.certresolver={{ mastodon_traefik_certresolver }}"
- "traefik.http.routers.mastodon.middlewares=mastodon,compress"
- "traefik.http.middlewares.mastodon.headers.sslredirect=true"
- "traefik.http.middlewares.mastodon.headers.stsSeconds=63072000"
- "traefik.http.middlewares.mastodon.headers.referrerPolicy=same-origin"
- "traefik.enable=true"
{% if proxy_network is defined %}
- "traefik.docker.network={{ proxy_network }}"
{% endif %}
networks:
frontend:
{% if proxy_network is defined %}
{{ proxy_network }}:
{% endif %}
volumes:
- "{{ mastodon_nginx_location }}/default.conf:/etc/nginx/conf.d/default.conf:ro"
- "{{ mastodon_public_location }}:/usr/share/nginx/html:ro"
depends_on:
- web
- streaming
restart: always
db:
image: docker.io/library/postgres:{{ mastodon_database_image_version }}
mem_limit: 512mb
memswap_limit: 768mb
read_only: true
tmpfs:
- /run/postgresql:size=512K
- /tmp:size=128K
environment:
- "POSTGRES_HOST_AUTH_METHOD=trust"
stop_grace_period: 2m
stop_signal: SIGINT
networks:
backend:
healthcheck:
test: ['CMD', 'pg_isready', '-U', 'postgres']
volumes:
- {{ mastodon_database_location }}:/var/lib/postgresql/data
restart: always
redis:
image: docker.io/library/redis:{{ mastodon_redis_image_version }}
mem_limit: 512mb
memswap_limit: 768mb
networks:
backend:
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
volumes:
- {{ mastodon_redis_location }}:/data
restart: always
{% if mastodon_config.enable_elasticsearch is defined and mastodon_config.enable_elasticsearch %}
es:
restart: always
image: docker.elastic.co/elasticsearch/elasticsearch:{{ mastodon_elasticsearch_image_version }}
mem_limit: 1124mb
memswap_limit: 1280mb
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx512m -Des.enforce.bootstrap.checks=true"
- "xpack.license.self_generated.type=basic"
- "xpack.security.enabled=false"
- "xpack.watcher.enabled=false"
- "xpack.graph.enabled=false"
- "xpack.ml.enabled=false"
- "bootstrap.memory_lock=true"
- "cluster.name=es-mastodon"
- "discovery.type=single-node"
- "thread_pool.write.queue_size=1000"
- "ingest.geoip.downloader.enabled=false"
networks:
backend:
healthcheck:
test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"]
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
- {{ mastodon_elastic_location }}:/usr/share/elasticsearch/data
{% endif %}
web:
image: ghcr.io/mastodon/mastodon:{{ mastodon_image_version }}
mem_limit: 1024mb
memswap_limit: 1280mb
env_file: {{ mastodon_install_location }}/.env.production
depends_on:
- db
- redis
{% if mastodon_config.enable_elasticsearch is defined and mastodon_config.enable_elasticsearch %}
- es
{% endif %}
volumes:
- {{ mastodon_public_location }}/system:/mastodon/public/system
networks:
frontend:
backend:
healthcheck:
test: ['CMD-SHELL',"curl -s --noproxy localhost localhost:3000/health | grep -q 'OK' || exit 1"]
restart: always
command: bundle exec puma -C config/puma.rb
streaming:
image: ghcr.io/mastodon/mastodon-streaming:{{ mastodon_image_version }}
mem_limit: 1024mb
memswap_limit: 1280mb
env_file: {{ mastodon_install_location }}/.env.production
networks:
frontend:
backend:
healthcheck:
test: ['CMD-SHELL', "curl -s --noproxy localhost localhost:4000/api/v1/streaming/health | grep -q 'OK' || exit 1"]
depends_on:
- db
- redis
restart: always
command: node ./streaming/index.js
sidekiq:
image: ghcr.io/mastodon/mastodon:{{ mastodon_image_version }}
mem_limit: 1024mb
memswap_limit: 1280mb
env_file: {{ mastodon_install_location }}/.env.production
depends_on:
- db
- redis
volumes:
- {{ mastodon_public_location }}/system:/mastodon/public/system
networks:
frontend:
backend:
healthcheck:
test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"]
restart: always
command: bundle exec sidekiq
networks:
frontend:
backend:
internal: true
{% if proxy_network is defined %}
{{ proxy_network }}:
external: true
{% endif %}

View file

@ -0,0 +1,8 @@
{{ ansible_managed | comment }}
[Network]
NetworkName = mastodon_backend
Driver = bridge
Internal = true
# Most containers expect ipv4 here
IPv6 = false

View file

@ -0,0 +1,43 @@
{{ ansible_managed | comment }}
[Unit]
Description = ElasticSearch for Mastodon
[Service]
Restart = always
RestartSec = 5s
[Container]
Image = {{ mastodon_elasticsearch_containerimage }}:{{ mastodon_elasticsearch_image_tag }}
ContainerName = mastodon-elasticsearch
# To prevent it from using chroot
User = 1000
HealthCmd = CMD-SHELL curl --silent --fail localhost:9200/_cluster/health || exit 1
# AutoUpdate = registry
LogDriver = journald
NoNewPrivileges = true
DropCapability = all
UserNS = auto:size=65535
{% if mastodon_elasticsearch_selinux_level != omit %}
SecurityLabelLevel = {{ mastodon_elasticsearch_selinux_level }}
{% endif %}
EnvironmentFile = {{ mastodon_install_location }}/mastodon-elasticsearch.env
Network = mastodon-backend.network:alias=backend-mastodon-elasticsearch
Volume = {{ mastodon_elasticsearch_location }}:/usr/share/elasticsearch/data:U
Ulimit = nofile=65536:65536
Ulimit = memlock=-1:-1
PodmanArgs = --memory={{ mastodon_memory_high }}
PodmanArgs = --memory-swap={{ mastodon_swap_max }}
PodmanArgs = --memory-reservation={{ mastodon_memory_low }}
[Install]
WantedBy = default.target

View file

@ -0,0 +1,13 @@
{{ ansible_managed | comment }}
ES_JAVA_OPTS=-Xms512m -Xmx512m -Des.enforce.bootstrap.checks=true
xpack.license.self_generated.type=basic
xpack.security.enabled=false
xpack.watcher.enabled=false
xpack.graph.enabled=false
xpack.ml.enabled=false
bootstrap.memory_lock=true
cluster.name=es-mastodon
discovery.type=single-node
thread_pool.write.queue_size=1000
ingest.geoip.downloader.enabled=false

View file

@ -0,0 +1,6 @@
{{ ansible_managed | comment }}
[Network]
NetworkName = mastodon_frontend
Driver = bridge
IPv6 = true

View file

@ -0,0 +1,45 @@
{{ ansible_managed | comment }}
[Unit]
Description = Nginx for Mastodon
Requires = mastodon-web.service mastodon-streaming.service
After = mastodon-web.service mastodon-streaming.service
[Service]
Restart = always
RestartSec = 5s
[Container]
Image = {{ mastodon_nginx_containerimage }}:{{ mastodon_nginx_image_tag }}
ContainerName = mastodon-nginx
# AutoUpdate = registry
LogDriver = journald
ReadOnly = true
NoNewPrivileges = true
DropCapability = all
UserNS = container:mastodon-web
{% if mastodon_nginx_selinux_level != omit %}
SecurityLabelLevel = {{ mastodon_nginx_selinux_level }}
{% endif %}
Network = mastodon-backend.network
Network = caddy.network:alias=caddy-mastodon-nginx
ExposeHostPort = 8080
# Equal to mastodon user, so it can stat the public folder
User = 991
Volume = {{ mastodon_public_location }}:/usr/share/nginx/html/system:ro
Volume = {{ mastodon_install_location }}/default.conf:/etc/nginx/conf.d/default.conf:U,ro
Tmpfs = /var/cache/nginx:rw,noexec,nosuid,nodev,size=1g
Tmpfs = /tmp:rw,noexec,nosuid,nodev,size=100m
PodmanArgs = --memory={{ mastodon_nginx_memory_high }}
PodmanArgs = --memory-swap={{ mastodon_nginx_swap_max }}
PodmanArgs = --memory-reservation={{ mastodon_nginx_memory_low }}
[Install]
WantedBy = default.target

View file

@ -0,0 +1,5 @@
{{ ansible_managed | comment }}
[Volume]
VolumeName = mastodon-postgres-socket

View file

@ -0,0 +1,48 @@
{{ ansible_managed | comment }}
[Unit]
Description = Postgres for Mastodon
[Service]
Restart = always
RestartSec = 5s
[Container]
Image = {{ mastodon_postgres_containerimage }}:{{ mastodon_postgres_image_tag }}
ContainerName = mastodon-postgres
HealthCmd = CMD pg_isready -U postgres
# AutoUpdate = registry
LogDriver = journald
# User = 70
# Group = 70
# TODO: Investigate necessary capabilities
# NoNewPrivileges = true
ReadOnly = true
DropCapability = all
AddCapability = CHOWN DAC_OVERRIDE SETUID SETGID
UserNS = auto:size=65535
{% if mastodon_postgres_selinux_level != omit %}
SecurityLabelLevel = {{ mastodon_postgres_selinux_level }}
{% endif %}
EnvironmentFile = {{ mastodon_install_location }}/mastodon-postgres.env
Volume = mastodon-postgres-socket:/var/run/postgresql:U,z
Volume = {{ mastodon_postgres_location }}:/var/lib/postgresql/data:U
Tmpfs = /run/postgresql:rw,noexec,nosuid,nodev,size=1m
Tmpfs = /tmp:rw,noexec,nosuid,nodev,size=50m
ExposeHostPort = 5432
PodmanArgs = --memory={{ mastodon_postgres_memory_high }}
PodmanArgs = --memory-swap={{ mastodon_postgres_swap_max }}
PodmanArgs = --memory-reservation={{ mastodon_postgres_memory_low }}
PodmanArgs = --stop-signal=SIGINT
[Install]
WantedBy = default.target

View file

@ -0,0 +1,3 @@
{{ ansible_managed | comment }}
POSTGRES_PASSWORD={{ mastodon_postgres_password }}

View file

@ -0,0 +1,5 @@
{{ ansible_managed | comment }}
[Volume]
VolumeName = mastodon-redis-socket

View file

@ -0,0 +1,46 @@
{{ ansible_managed | comment }}
[Unit]
Description = Redis for Mastodon
[Service]
Restart = always
RestartSec = 5s
[Container]
Image = {{ mastodon_redis_containerimage }}:{{ mastodon_redis_image_tag }}
ContainerName = mastodon-redis
HealthCmd = CMD redis-cli -s /run/redis/redis.sock ping
Exec = redis-server /usr/lib/redis/redis.conf
# AutoUpdate = registry
LogDriver = journald
NoNewPrivileges = true
ReadOnly = true
DropCapability = all
AddCapability = CHOWN DAC_OVERRIDE SETUID SETGID
UserNS = auto:size=65535
{% if mastodon_redis_selinux_level != omit %}
SecurityLabelLevel = {{ mastodon_redis_selinux_level }}
{% endif %}
User = redis
Group = redis
# Sysctl = vm.overcommit_memory=1
Volume = mastodon-redis-socket:/run/redis:U,z
Volume = {{ mastodon_install_location }}/redis.conf:/usr/lib/redis/redis.conf:U,ro
Volume = {{ mastodon_redis_location }}:/data:U
Tmpfs = /run:rw,noexec,nosuid,nodev,size=1m
PodmanArgs = --memory={{ mastodon_redis_memory_high }}
PodmanArgs = --memory-swap={{ mastodon_redis_swap_max }}
PodmanArgs = --memory-reservation={{ mastodon_redis_memory_low }}
[Install]
WantedBy = default.target

View file

@ -0,0 +1,45 @@
{{ ansible_managed | comment }}
[Unit]
Description = Mastodon Sidekiq Server
Requires = mastodon-postgres.service mastodon-redis.service
After = mastodon-postgres.service mastodon-redis.service
[Service]
Restart = always
RestartSec = 5s
[Container]
Image = {{ mastodon_containerimage }}:{{ mastodon_image_tag }}
ContainerName = mastodon-sidekiq
HealthCmd = CMD-SHELL ps aux | grep '[s]idekiq\ 6' || false
Exec = bundle exec sidekiq
# AutoUpdate = registry
LogDriver = journald
NoNewPrivileges = true
DropCapability = all
UserNS = container:mastodon-web
{% if mastodon_selinux_level != omit %}
SecurityLabelLevel = {{ mastodon_selinux_level }}
{% endif %}
Network = mastodon-frontend.network
Network = mastodon-backend.network
EnvironmentFile = {{ mastodon_install_location }}/mastodon.env
Volume = {{ mastodon_public_location }}:/mastodon/public/system
Volume = mastodon-postgres-socket:/var/run/postgresql:z
Volume = mastodon-redis-socket:/run/redis:z
PodmanArgs = --memory={{ mastodon_memory_high }}
PodmanArgs = --memory-swap={{ mastodon_swap_max }}
PodmanArgs = --memory-reservation={{ mastodon_memory_low }}
[Install]
WantedBy = default.target

View file

@ -0,0 +1,44 @@
{{ ansible_managed | comment }}
[Unit]
Description = Mastodon Streaming Server
Requires = mastodon-postgres.service mastodon-redis.service
After = mastodon-postgres.service mastodon-redis.service
[Service]
Restart = always
RestartSec = 5s
[Container]
Image = {{ mastodon_streaming_containerimage }}:{{ mastodon_image_tag }}
ContainerName = mastodon-streaming
HealthCmd = CMD-SHELL curl -s --noproxy localhost localhost:4000/api/v1/streaming/health | grep -q 'OK' || exit 1
Exec = node ./streaming/index.js
AutoUpdate = registry
LogDriver = journald
NoNewPrivileges = true
DropCapability = all
UserNS = auto:size=65535
{% if mastodon_selinux_level != omit %}
SecurityLabelLevel = {{ mastodon_selinux_level }}
{% endif %}
Network = mastodon-backend.network:alias=backend-mastodon-streaming
ExposeHostPort = 4000
EnvironmentFile = {{ mastodon_install_location }}/mastodon.env
Volume = mastodon-postgres-socket:/var/run/postgresql:z
Volume = mastodon-redis-socket:/run/redis:z
PodmanArgs = --memory={{ mastodon_memory_high }}
PodmanArgs = --memory-swap={{ mastodon_swap_max }}
PodmanArgs = --memory-reservation={{ mastodon_memory_low }}
[Install]
WantedBy = default.target

View file

@ -0,0 +1,45 @@
{{ ansible_managed | comment }}
[Unit]
Description = Mastodon Web Server
Requires = mastodon-postgres.service mastodon-redis.service mastodon-elasticsearch.service
After = mastodon-postgres.service mastodon-redis.service mastodon-elasticsearch.service
[Service]
Restart = always
RestartSec = 5s
[Container]
Image = {{ mastodon_containerimage }}:{{ mastodon_image_tag }}
ContainerName = mastodon-web
HealthCmd = CMD-SHELL curl -s --noproxy localhost localhost:3000/health | grep -q 'OK' || exit 1
Exec = bundle exec puma -C config/puma.rb
# AutoUpdate = registry
LogDriver = journald
NoNewPrivileges = true
DropCapability = all
UserNS = auto:size=65535
{% if mastodon_selinux_level != omit %}
SecurityLabelLevel = {{ mastodon_selinux_level }}
{% endif %}
Network = mastodon-frontend.network
Network = mastodon-backend.network:alias=backend-mastodon-web
EnvironmentFile = {{ mastodon_install_location }}/mastodon.env
Volume = {{ mastodon_public_location }}:/mastodon/public/system:U
Volume = mastodon-postgres-socket:/var/run/postgresql:z
Volume = mastodon-redis-socket:/run/redis:z
PodmanArgs = --memory={{ mastodon_memory_high }}
PodmanArgs = --memory-swap={{ mastodon_swap_max }}
PodmanArgs = --memory-reservation={{ mastodon_memory_low }}
[Install]
WantedBy = default.target

View file

@ -0,0 +1,31 @@
{{ ansible_managed | comment }}
{{ mastodon_domain }} {
encode gzip
header {
# enable HSTS
Strict-Transport-Security "max-age=31536000; preload;"
# disable clients from sniffing the media type
X-Content-Type-Options nosniff
# clickjacking protection
X-Frame-Options DENY
# keep referrer data off of HTTP connections
Referrer-Policy no-referrer-when-downgrade
# Server name removing
-Server
}
# TODO: Move to own caddy file
route /.well-known/matrix* {
reverse_proxy https://matrix.flausch.social {
header_up -Host
}
}
reverse_proxy caddy-mastodon-nginx:8080
}

View file

@ -0,0 +1,113 @@
{{ ansible_managed | comment }}
# Redis
# -----
REDIS_URL=unix:///run/redis/redis.sock
# PostgreSQL
# ----------
DB_HOST=/var/run/postgresql
DB_USER=postgres
DB_NAME=postgres
DB_PASS={{ mastodon_postgres_password }}
DB_PORT=5432
# Elasticsearch
# ------------------------
ES_ENABLED=true
ES_HOST=backend-mastodon-elasticsearch
ES_PORT=9200
# Federation
# ----------
# This identifies your server and cannot be changed safely later
# ----------
LOCAL_DOMAIN={{ mastodon_config.local_domain }}
{% if mastodon_config.web_domain is defined %}
# Use this only if you need to run mastodon on a different domain than the one used for federation.
# You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md
# DO *NOT* USE THIS UNLESS YOU KNOW *EXACTLY* WHAT YOU ARE DOING.
WEB_DOMAIN={{ mastodon_config.web_domain }}
{% endif %}
# Use this if you want to have several aliases handler@example1.com
# handler@example2.com etc. for the same user. LOCAL_DOMAIN should not
# be added. Comma separated values
# ALTERNATE_DOMAINS=example1.com,example2.com
# Secrets
# -------
# Make sure to use `bundle exec rails secret` to generate secrets
# -------
SECRET_KEY_BASE={{ mastodon_config.secret_key_base }}
OTP_SECRET={{ mastodon_config.otp_secret }}
# Encryption secrets
# ------------------
# Must be available (and set to same values) for all server processes
# These are private/secret values, do not share outside hosting environment
# Use `bin/rails db:encryption:init` to generate fresh secrets
# Do not change these secrets once in use, as this would cause data loss and other issues
# ------------------
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY={{ mastodon_config.ar_enc_deterministic_key }}
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT={{ mastodon_config.ar_enc_derivation_salt }}
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY={{ mastodon_config.ar_enc_primary_key }}
# Web Push
# --------
# Generate with `bundle exec rails mastodon:webpush:generate_vapid_key`
# --------
VAPID_PRIVATE_KEY={{ mastodon_config.vapid_private_key }}
VAPID_PUBLIC_KEY={{ mastodon_config.vapid_public_key }}
# Registrations
# ------------
{% if mastodon_config.single_user_mode is defined %}
# Single user mode will disable registrations and redirect frontpage to the first profile
SINGLE_USER_MODE={{ mastodon_config.single_user_mode | bool | lower }}
{% endif %}
# Prevent registrations with following e-mail domains
# EMAIL_DOMAIN_BLACKLIST=example1.com|example2.de|etc
# Only allow registrations with the following e-mail domains
# EMAIL_DOMAIN_WHITELIST=example1.com|example2.de|etc
# Optionally change default language
# DEFAULT_LOCALE=de
# Sending mail
# ------------
SMTP_SERVER={{ mastodon_config.smtp_server }}
SMTP_PORT={{ mastodon_config.smtp_port | default(587) }}
SMTP_LOGIN={{ mastodon_config.smtp_login }}
SMTP_PASSWORD={{ mastodon_config.smtp_password }}
SMTP_FROM_ADDRESS={{ mastodon_config.smtp_from_address }}
#SMTP_REPLY_TO=
#SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
#SMTP_AUTH_METHOD=plain
#SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt
#SMTP_OPENSSL_VERIFY_MODE=peer
#SMTP_ENABLE_STARTTLS_AUTO=true
#SMTP_TLS=true
# File storage (optional)
# -----------------------
# S3 (Minio Config (optional) Please check Minio instance for details)
# The attachment host must allow cross origin request from WEB_DOMAIN or
# LOCAL_DOMAIN if WEB_DOMAIN is not set. For example, the server may have the
# following header field:
# -----------------------
# S3_ENABLED=true
# S3_BUCKET=
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# S3_REGION=
# S3_PROTOCOL=https
# S3_HOSTNAME=
# S3_ENDPOINT=
# S3_SIGNATURE_VERSION=

View file

@ -0,0 +1,513 @@
{{ ansible_managed | comment }}
# Only listen on localhost
bind 127.0.0.1 -::1
# When protected mode is on and the default user has no password, the server
# only accepts local connections from the IPv4 address (127.0.0.1), IPv6 address
# (::1) or Unix domain sockets.
protected-mode yes
# Redis uses default hardened security configuration directives to reduce the
# attack surface on innocent users. Therefore, several sensitive configuration
# directives are immutable, and some potentially-dangerous commands are blocked.
#
# Configuration directives that control files that Redis writes to (e.g., 'dir'
# and 'dbfilename') and that aren't usually modified during runtime
# are protected by making them immutable.
#
# Commands that can increase the attack surface of Redis and that aren't usually
# called by users are blocked by default.
#
# These can be exposed to either all connections or just local ones by setting
# each of the configs listed below to either of these values:
#
# no - Block for any connection (remain immutable)
# yes - Allow for any connection (no protection)
# local - Allow only for local connections. Ones originating from the
# IPv4 address (127.0.0.1), IPv6 address (::1) or Unix domain sockets.
enable-protected-configs no
enable-debug-command no
enable-module-command no
# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
port 0
# Unix socket.
unixsocket /run/redis/redis.sock
unixsocketperm 777
# Close the connection after a client is idle for N seconds (0 to disable)
timeout 0
# Apply OS-specific mechanism to mark the listening socket with the specified
# ID, to support advanced routing and filtering capabilities.
#
# On Linux, the ID represents a connection mark.
# On FreeBSD, the ID represents a socket cookie ID.
# On OpenBSD, the ID represents a route table ID.
#
# The default value is 0, which implies no marking is required.
# socket-mark-id 0
################################# GENERAL #####################################
# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
# When Redis is supervised by upstart or systemd, this parameter has no impact.
daemonize no
# If you run Redis from upstart or systemd, Redis can interact with your
# supervision tree. Options:
# supervised no - no supervision interaction
# supervised upstart - signal upstart by putting Redis into SIGSTOP mode
# requires "expect stop" in your upstart job config
# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
# on startup, and updating Redis status on a regular
# basis.
# supervised auto - detect upstart or systemd method based on
# UPSTART_JOB or NOTIFY_SOCKET environment variables
# Note: these supervision methods only signal "process is ready."
# They do not enable continuous pings back to your supervisor.
#
# The default is "no". To run under upstart/systemd, you can simply uncomment
# the line below:
supervised auto
pidfile /run/redis_6379.pid
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
# nothing (nothing is logged)
loglevel notice
# Specify the log file name. Also the empty string can be used to force
# Redis to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
logfile ""
# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
# Set the local environment which is used for string comparison operations, and
# also affect the performance of Lua scripts. Empty String indicates the locale
# is derived from the environment variables.
locale-collate ""
################################ SNAPSHOTTING ################################
# Save the DB to disk.
#
# save <seconds> <changes> [<seconds> <changes> ...]
#
# Redis will save the DB if the given number of seconds elapsed and it
# surpassed the given number of write operations against the DB.
#
# Snapshotting can be completely disabled with a single empty string argument
# as in following example:
#
# save ""
#
# Unless specified otherwise, by default Redis will save the DB:
# * After 3600 seconds (an hour) if at least 1 change was performed
# * After 300 seconds (5 minutes) if at least 100 changes were performed
# * After 60 seconds if at least 10000 changes were performed
#
# You can set these explicitly by uncommenting the following line.
#
save 3600 1 300 100 60 10000
# By default Redis will stop accepting writes if RDB snapshots are enabled
# (at least one save point) and the latest background save failed.
# This will make the user aware (in a hard way) that data is not persisting
# on disk properly, otherwise chances are that no one will notice and some
# disaster will happen.
#
# If the background saving process will start working again Redis will
# automatically allow writes again.
#
# However if you have setup your proper monitoring of the Redis server
# and persistence, you may want to disable this feature so that Redis will
# continue to work as usual even if there are problems with disk,
# permissions, and so forth.
stop-writes-on-bgsave-error yes
# Compress string objects using LZF when dump .rdb databases?
# By default compression is enabled as it's almost always a win.
# If you want to save some CPU in the saving child set it to 'no' but
# the dataset will likely be bigger if you have compressible values or keys.
rdbcompression yes
# Since version 5 of RDB a CRC64 checksum is placed at the end of the file.
# This makes the format more resistant to corruption but there is a performance
# hit to pay (around 10%) when saving and loading RDB files, so you can disable it
# for maximum performances.
#
# RDB files created with checksum disabled have a checksum of zero that will
# tell the loading code to skip the check.
rdbchecksum yes
# Enables or disables full sanitization checks for ziplist and listpack etc when
# loading an RDB or RESTORE payload. This reduces the chances of a assertion or
# crash later on while processing commands.
# Options:
# no - Never perform full sanitization
# yes - Always perform full sanitization
# clients - Perform full sanitization only for user connections.
# Excludes: RDB files, RESTORE commands received from the master
# connection, and client connections which have the
# skip-sanitize-payload ACL flag.
# The default should be 'clients' but since it currently affects cluster
# resharding via MIGRATE, it is temporarily set to 'no' by default.
#
sanitize-dump-payload clients
# The filename where to dump the DB
dbfilename dump.rdb
# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
dir /data
################################## SECURITY ###################################
# Warning: since Redis is pretty fast, an outside user can try up to
# 1 million passwords per second against a modern box. This means that you
# should use very strong passwords, otherwise they will be very easy to break.
# Note that because the password is really a shared secret between the client
# and the server, and should not be memorized by any human, the password
# can be easily a long string from /dev/urandom or whatever, so by using a
# long and unguessable password no brute force attack will be possible.
# Redis ACL users are defined in the following format:
#
# user <username> ... acl rules ...
#
# For example:
#
# user worker +@list +@connection ~jobs:* on >ffa9203c493aa99
#
# The special username "default" is used for new connections. If this user
# has the "nopass" rule, then new connections will be immediately authenticated
# as the "default" user without the need of any password provided via the
# AUTH command. Otherwise if the "default" user is not flagged with "nopass"
# the connections will start in not authenticated state, and will require
# AUTH (or the HELLO command AUTH option) in order to be authenticated and
# start to work.
#
# The ACL rules that describe what a user can do are the following:
#
# on Enable the user: it is possible to authenticate as this user.
# off Disable the user: it's no longer possible to authenticate
# with this user, however the already authenticated connections
# will still work.
# skip-sanitize-payload RESTORE dump-payload sanitization is skipped.
# sanitize-payload RESTORE dump-payload is sanitized (default).
# +<command> Allow the execution of that command.
# May be used with `|` for allowing subcommands (e.g "+config|get")
# -<command> Disallow the execution of that command.
# May be used with `|` for blocking subcommands (e.g "-config|set")
# +@<category> Allow the execution of all the commands in such category
# with valid categories are like @admin, @set, @sortedset, ...
# and so forth, see the full list in the server.c file where
# the Redis command table is described and defined.
# The special category @all means all the commands, but currently
# present in the server, and that will be loaded in the future
# via modules.
# +<command>|first-arg Allow a specific first argument of an otherwise
# disabled command. It is only supported on commands with
# no sub-commands, and is not allowed as negative form
# like -SELECT|1, only additive starting with "+". This
# feature is deprecated and may be removed in the future.
# allcommands Alias for +@all. Note that it implies the ability to execute
# all the future commands loaded via the modules system.
# nocommands Alias for -@all.
# ~<pattern> Add a pattern of keys that can be mentioned as part of
# commands. For instance ~* allows all the keys. The pattern
# is a glob-style pattern like the one of KEYS.
# It is possible to specify multiple patterns.
# %R~<pattern> Add key read pattern that specifies which keys can be read
# from.
# %W~<pattern> Add key write pattern that specifies which keys can be
# written to.
# allkeys Alias for ~*
# resetkeys Flush the list of allowed keys patterns.
# &<pattern> Add a glob-style pattern of Pub/Sub channels that can be
# accessed by the user. It is possible to specify multiple channel
# patterns.
# allchannels Alias for &*
# resetchannels Flush the list of allowed channel patterns.
# ><password> Add this password to the list of valid password for the user.
# For example >mypass will add "mypass" to the list.
# This directive clears the "nopass" flag (see later).
# <<password> Remove this password from the list of valid passwords.
# nopass All the set passwords of the user are removed, and the user
# is flagged as requiring no password: it means that every
# password will work against this user. If this directive is
# used for the default user, every new connection will be
# immediately authenticated with the default user without
# any explicit AUTH command required. Note that the "resetpass"
# directive will clear this condition.
# resetpass Flush the list of allowed passwords. Moreover removes the
# "nopass" status. After "resetpass" the user has no associated
# passwords and there is no way to authenticate without adding
# some password (or setting it as "nopass" later).
# reset Performs the following actions: resetpass, resetkeys, resetchannels,
# allchannels (if acl-pubsub-default is set), off, clearselectors, -@all.
# The user returns to the same state it has immediately after its creation.
# (<options>) Create a new selector with the options specified within the
# parentheses and attach it to the user. Each option should be
# space separated. The first character must be ( and the last
# character must be ).
# clearselectors Remove all of the currently attached selectors.
# Note this does not change the "root" user permissions,
# which are the permissions directly applied onto the
# user (outside the parentheses).
#
# ACL rules can be specified in any order: for instance you can start with
# passwords, then flags, or key patterns. However note that the additive
# and subtractive rules will CHANGE MEANING depending on the ordering.
# For instance see the following example:
#
# user alice on +@all -DEBUG ~* >somepassword
#
# This will allow "alice" to use all the commands with the exception of the
# DEBUG command, since +@all added all the commands to the set of the commands
# alice can use, and later DEBUG was removed. However if we invert the order
# of two ACL rules the result will be different:
#
# user alice on -DEBUG +@all ~* >somepassword
#
# Now DEBUG was removed when alice had yet no commands in the set of allowed
# commands, later all the commands are added, so the user will be able to
# execute everything.
#
# Basically ACL rules are processed left-to-right.
#
# The following is a list of command categories and their meanings:
# * keyspace - Writing or reading from keys, databases, or their metadata
# in a type agnostic way. Includes DEL, RESTORE, DUMP, RENAME, EXISTS, DBSIZE,
# KEYS, EXPIRE, TTL, FLUSHALL, etc. Commands that may modify the keyspace,
# key or metadata will also have `write` category. Commands that only read
# the keyspace, key or metadata will have the `read` category.
# * read - Reading from keys (values or metadata). Note that commands that don't
# interact with keys, will not have either `read` or `write`.
# * write - Writing to keys (values or metadata)
# * admin - Administrative commands. Normal applications will never need to use
# these. Includes REPLICAOF, CONFIG, DEBUG, SAVE, MONITOR, ACL, SHUTDOWN, etc.
# * dangerous - Potentially dangerous (each should be considered with care for
# various reasons). This includes FLUSHALL, MIGRATE, RESTORE, SORT, KEYS,
# CLIENT, DEBUG, INFO, CONFIG, SAVE, REPLICAOF, etc.
# * connection - Commands affecting the connection or other connections.
# This includes AUTH, SELECT, COMMAND, CLIENT, ECHO, PING, etc.
# * blocking - Potentially blocking the connection until released by another
# command.
# * fast - Fast O(1) commands. May loop on the number of arguments, but not the
# number of elements in the key.
# * slow - All commands that are not Fast.
# * pubsub - PUBLISH / SUBSCRIBE related
# * transaction - WATCH / MULTI / EXEC related commands.
# * scripting - Scripting related.
# * set - Data type: sets related.
# * sortedset - Data type: zsets related.
# * list - Data type: lists related.
# * hash - Data type: hashes related.
# * string - Data type: strings related.
# * bitmap - Data type: bitmaps related.
# * hyperloglog - Data type: hyperloglog related.
# * geo - Data type: geo related.
# * stream - Data type: streams related.
#
# For more information about ACL configuration please refer to
# the Redis web site at https://redis.io/topics/acl
# ACL LOG
#
# The ACL Log tracks failed commands and authentication events associated
# with ACLs. The ACL Log is useful to troubleshoot failed commands blocked
# by ACLs. The ACL Log is stored in memory. You can reclaim memory with
# ACL LOG RESET. Define the maximum entry length of the ACL Log below.
acllog-max-len 128
#################### KERNEL transparent hugepage CONTROL ######################
# Usually the kernel Transparent Huge Pages control is set to "madvise" or
# or "never" by default (/sys/kernel/mm/transparent_hugepage/enabled), in which
# case this config has no effect. On systems in which it is set to "always",
# redis will attempt to disable it specifically for the redis process in order
# to avoid latency problems specifically with fork(2) and CoW.
# If for some reason you prefer to keep it enabled, you can set this config to
# "no" and the kernel global to "always".
disable-thp yes
############################## APPEND ONLY MODE ###############################
# By default Redis asynchronously dumps the dataset on disk. This mode is
# good enough in many applications, but an issue with the Redis process or
# a power outage may result into a few minutes of writes lost (depending on
# the configured save points).
#
# The Append Only File is an alternative persistence mode that provides
# much better durability. For instance using the default data fsync policy
# (see later in the config file) Redis can lose just one second of writes in a
# dramatic event like a server power outage, or a single write if something
# wrong with the Redis process itself happens, but the operating system is
# still running correctly.
#
# AOF and RDB persistence can be enabled at the same time without problems.
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
#
# Note that changing this value in a config file of an existing database and
# restarting the server can lead to data loss. A conversion needs to be done
# by setting it via CONFIG command on a live server first.
#
# Please check https://redis.io/topics/persistence for more information.
appendonly no
# The base name of the append only file.
#
# Redis 7 and newer use a set of append-only files to persist the dataset
# and changes applied to it. There are two basic types of files in use:
#
# - Base files, which are a snapshot representing the complete state of the
# dataset at the time the file was created. Base files can be either in
# the form of RDB (binary serialized) or AOF (textual commands).
# - Incremental files, which contain additional commands that were applied
# to the dataset following the previous file.
#
# In addition, manifest files are used to track the files and the order in
# which they were created and should be applied.
#
# Append-only file names are created by Redis following a specific pattern.
# The file name's prefix is based on the 'appendfilename' configuration
# parameter, followed by additional information about the sequence and type.
#
# For example, if appendfilename is set to appendonly.aof, the following file
# names could be derived:
#
# - appendonly.aof.1.base.rdb as a base file.
# - appendonly.aof.1.incr.aof, appendonly.aof.2.incr.aof as incremental files.
# - appendonly.aof.manifest as a manifest file.
appendfilename "appendonly.aof"
# For convenience, Redis stores all persistent append-only files in a dedicated
# directory. The name of the directory is determined by the appenddirname
# configuration parameter.
appenddirname "appendonlydir"
# The fsync() call tells the Operating System to actually write data on disk
# instead of waiting for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log. Slow, Safest.
# everysec: fsync only one time every second. Compromise.
#
# The default is "everysec", as that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".
# appendfsync always
appendfsync everysec
# appendfsync no
# When the AOF fsync policy is set to always or everysec, and a background
# saving process (a background save or AOF log background rewriting) is
# performing a lot of I/O against the disk, in some Linux configurations
# Redis may block too long on the fsync() call. Note that there is no fix for
# this currently, as even performing fsync in a different thread will block
# our synchronous write(2) call.
#
# In order to mitigate this problem it's possible to use the following option
# that will prevent fsync() from being called in the main process while a
# BGSAVE or BGREWRITEAOF is in progress.
#
# This means that while another child is saving, the durability of Redis is
# the same as "appendfsync no". In practical terms, this means that it is
# possible to lose up to 30 seconds of log in the worst scenario (with the
# default Linux settings).
#
# If you have latency problems turn this to "yes". Otherwise leave it as
# "no" that is the safest pick from the point of view of durability.
no-appendfsync-on-rewrite no
# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (if no rewrite has happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a percentage of zero in order to disable the automatic AOF
# rewrite feature.
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# An AOF file may be found to be truncated at the end during the Redis
# startup process, when the AOF data gets loaded back into memory.
# This may happen when the system where Redis is running
# crashes, especially when an ext4 filesystem is mounted without the
# data=ordered option (however this can't happen when Redis itself
# crashes or aborts but the operating system still works correctly).
#
# Redis can either exit with an error when this happens, or load as much
# data as possible (the default now) and start if the AOF file is found
# to be truncated at the end. The following option controls this behavior.
#
# If aof-load-truncated is set to yes, a truncated AOF file is loaded and
# the Redis server starts emitting a log to inform the user of the event.
# Otherwise if the option is set to no, the server aborts with an error
# and refuses to start. When the option is set to no, the user requires
# to fix the AOF file using the "redis-check-aof" utility before to restart
# the server.
#
# Note that if the AOF file will be found to be corrupted in the middle
# the server will still exit with an error. This option only applies when
# Redis will try to read more data from the AOF file but not enough bytes
# will be found.
aof-load-truncated yes
# Redis can create append-only base files in either RDB or AOF formats. Using
# the RDB format is always faster and more efficient, and disabling it is only
# supported for backward compatibility purposes.
aof-use-rdb-preamble yes
# Redis supports recording timestamp annotations in the AOF to support restoring
# the data from a specific point-in-time. However, using this capability changes
# the AOF format in a way that may not be compatible with existing AOF parsers.
aof-timestamp-enabled no

View file

@ -0,0 +1,5 @@
# The container data volume mount locations
mastodon_postgres_location: "{{ mastodon_install_location }}/postgres"
mastodon_public_location: "{{ mastodon_install_location }}/public"
mastodon_redis_location: "{{ mastodon_install_location }}/redis"
mastodon_elasticsearch_location: "{{ mastodon_install_location }}/elasticsearch"