aboutsummaryrefslogtreecommitdiffstats
path: root/roles/mastodon
diff options
context:
space:
mode:
authorStonewall Jackson <stonewall@sacredheartsc.com>2023-06-12 21:02:22 -0400
committerStonewall Jackson <stonewall@sacredheartsc.com>2023-06-12 21:02:22 -0400
commit865e2f05621fc10f3d332d3840707997c0b94abf (patch)
treeb5f0c85951175b813996991298501c6afb012824 /roles/mastodon
parent78fd379d33bd6853123c02a76c97ca382aa24be9 (diff)
downloadselfhosted-865e2f05621fc10f3d332d3840707997c0b94abf.tar.gz
selfhosted-865e2f05621fc10f3d332d3840707997c0b94abf.zip
add mastodon role
Diffstat (limited to 'roles/mastodon')
-rw-r--r--roles/mastodon/defaults/main.yml23
-rw-r--r--roles/mastodon/handlers/main.yml8
-rw-r--r--roles/mastodon/meta/main.yml14
-rw-r--r--roles/mastodon/tasks/database.yml23
-rw-r--r--roles/mastodon/tasks/freeipa.yml8
-rw-r--r--roles/mastodon/tasks/main.yml121
-rw-r--r--roles/mastodon/templates/etc/systemd/system/mastodon-cleanup.service.j249
-rw-r--r--roles/mastodon/templates/etc/systemd/system/mastodon-cleanup.timer.j210
-rw-r--r--roles/mastodon/templates/etc/systemd/system/mastodon-sidekiq.service.j252
-rw-r--r--roles/mastodon/templates/etc/systemd/system/mastodon-streaming.service.j251
-rw-r--r--roles/mastodon/templates/etc/systemd/system/mastodon-web.service.j252
-rw-r--r--roles/mastodon/templates/opt/mastodon/mastodon/.env.production.j259
-rw-r--r--roles/mastodon/vars/main.yml58
13 files changed, 528 insertions, 0 deletions
diff --git a/roles/mastodon/defaults/main.yml b/roles/mastodon/defaults/main.yml
new file mode 100644
index 0000000..d9bab79
--- /dev/null
+++ b/roles/mastodon/defaults/main.yml
@@ -0,0 +1,23 @@
+mastodon_version: 4.1.2
+
+mastodon_access_group: role-mastodon-access
+mastodon_db_user: s-mastodon
+# mastodon_db_password
+mastodon_db_host: '{{ postgresql_host }}'
+mastodon_db_name: mastodon
+mastodon_ldap_host: '{{ freeipa_hosts | first }}'
+
+mastodon_domain: '{{ email_domain }}'
+mastodon_web_domain: '{{ ansible_fqdn }}'
+mastodon_email_from: 'mastodon-noreply@{{ email_domain }}'
+
+mastodon_default_locale: en
+
+mastodon_registrations: close
+
+mastodon_redis_port: 6379
+mastodon_web_port: 8008
+mastodon_streaming_port: 8009
+
+mastodon_sysaccount_username: mastodon
+#mastodon_sysaccount_password
diff --git a/roles/mastodon/handlers/main.yml b/roles/mastodon/handlers/main.yml
new file mode 100644
index 0000000..20fe804
--- /dev/null
+++ b/roles/mastodon/handlers/main.yml
@@ -0,0 +1,8 @@
+- name: restart mastodon
+ systemd:
+ name: '{{ item }}'
+ state: restarted
+ loop:
+ - mastodon-web
+ - mastodon-streaming
+ - mastodon-sidekiq
diff --git a/roles/mastodon/meta/main.yml b/roles/mastodon/meta/main.yml
new file mode 100644
index 0000000..8c0b12b
--- /dev/null
+++ b/roles/mastodon/meta/main.yml
@@ -0,0 +1,14 @@
+dependencies:
+ - role: yum
+ yum_repositories:
+ - epel
+ - rpmfusion-free
+ tags: yum
+
+ - role: freeipa_system_account
+ system_account_username: '{{ mastodon_sysaccount_username }}'
+ system_account_password: '{{ mastodon_sysaccount_password }}'
+
+ - role: redis
+ redis_port: '{{ mastodon_redis_port }}'
+ tags: redis
diff --git a/roles/mastodon/tasks/database.yml b/roles/mastodon/tasks/database.yml
new file mode 100644
index 0000000..37f6dcd
--- /dev/null
+++ b/roles/mastodon/tasks/database.yml
@@ -0,0 +1,23 @@
+- name: create database user
+ postgresql_user:
+ name: '{{ mastodon_db_user }}'
+ password: '{{ mastodon_db_password }}'
+ role_attr_flags: CREATEDB
+ state: present
+ environment:
+ PGOPTIONS: "-c password_encryption=scram-sha-256"
+ delegate_to: "{{ postgresql_inventory_host }}"
+ become: yes
+ become_user: postgres
+ register: mastodon_db_user
+
+- name: create database schema
+ command:
+ chdir: '{{ mastodon_install_dir }}'
+ cmd: 'bundle exec rake db:setup'
+ environment:
+ RAILS_ENV: production
+ SAFETY_ASSURED: 1
+ become: yes
+ become_user: '{{ mastodon_user }}'
+ when: mastodon_db_user.changed
diff --git a/roles/mastodon/tasks/freeipa.yml b/roles/mastodon/tasks/freeipa.yml
new file mode 100644
index 0000000..ee68b13
--- /dev/null
+++ b/roles/mastodon/tasks/freeipa.yml
@@ -0,0 +1,8 @@
+- name: create access group
+ ipagroup:
+ ipaadmin_principal: '{{ ipa_user }}'
+ ipaadmin_password: '{{ ipa_pass }}'
+ name: '{{ mastodon_access_group }}'
+ nonposix: yes
+ state: present
+ run_once: yes
diff --git a/roles/mastodon/tasks/main.yml b/roles/mastodon/tasks/main.yml
new file mode 100644
index 0000000..7ff23dd
--- /dev/null
+++ b/roles/mastodon/tasks/main.yml
@@ -0,0 +1,121 @@
+- name: install packages
+ dnf:
+ name: '{{ mastodon_packages }}'
+ state: present
+
+- name: add local user
+ user:
+ name: '{{ mastodon_user }}'
+ system: yes
+ home: '{{ mastodon_home }}'
+ shell: /sbin/nologin
+ create_home: no
+
+- import_tasks: freeipa.yml
+
+- name: create home directory
+ file:
+ path: '{{ mastodon_home }}'
+ owner: '{{ mastodon_user }}'
+ group: '{{ mastodon_user }}'
+ mode: 0755
+ state: directory
+
+- name: clone repo
+ git:
+ repo: '{{ mastodon_git_repo }}'
+ dest: '{{ mastodon_install_dir }}'
+ version: 'v{{ mastodon_version }}'
+ update: yes
+ force: yes
+ become: yes
+ become_user: '{{ mastodon_user }}'
+ register: mastodon_git
+
+- name: set selinux context on writeable directories
+ sefcontext:
+ target: '{{ mastodon_webroot }}(/.*)?'
+ setype: httpd_sys_content_t
+ state: present
+ register: mastodon_webroot_sefcontext
+ tags: selinux
+
+- name: apply selinux context to writeable directories
+ command: 'restorecon -R {{ mastodon_webroot }}'
+ when: mastodon_webroot_sefcontext.changed
+ tags: selinux
+
+- name: build mastodon
+ command:
+ chdir: '{{ mastodon_install_dir }}'
+ cmd: '{{ item }}'
+ loop:
+ - "bundle config deployment 'true'"
+ - "bundle config without 'development test'"
+ - 'bundle install -j{{ ansible_processor_vcpus }}'
+ - yarn install --pure-lockfile
+ become: yes
+ become_user: '{{ mastodon_user }}'
+ notify: restart mastodon
+ when: mastodon_git.changed
+
+- name: generate .env.production
+ template:
+ src: '{{ mastodon_install_dir[1:] }}/.env.production.j2'
+ dest: '{{ mastodon_install_dir }}/.env.production'
+ owner: '{{ mastodon_user }}'
+ group: '{{ mastodon_user }}'
+ mode: 0600
+ notify: restart mastodon
+
+- import_tasks: database.yml
+
+- name: precompile assets
+ command:
+ chdir: '{{ mastodon_install_dir }}'
+ cmd: 'bundle exec rake assets:precompile'
+ environment:
+ NODE_OPTIONS: --openssl-legacy-provider
+ RAILS_ENV: production
+ become: yes
+ become_user: '{{ mastodon_user }}'
+ when: mastodon_git.changed
+
+- name: create systemd units
+ template:
+ src: etc/systemd/system/{{ item }}.j2
+ dest: /etc/systemd/system/{{ item }}
+ loop:
+ - mastodon-sidekiq.service
+ - mastodon-streaming.service
+ - mastodon-web.service
+ - mastodon-cleanup.service
+ - mastodon-cleanup.timer
+ register: mastodon_systemd_units
+ notify: restart mastodon
+
+- name: reload systemd daemons
+ systemd:
+ daemon_reload: yes
+ when: mastodon_systemd_units.changed
+
+- name: start mastodon
+ systemd:
+ name: '{{ item }}'
+ enabled: yes
+ state: started
+ loop:
+ - mastodon-sidekiq.service
+ - mastodon-streaming.service
+ - mastodon-web.service
+ - mastodon-cleanup.timer
+
+- name: configure registrations
+ command:
+ chdir: '{{ mastodon_install_dir }}'
+ cmd: './bin/tootctl settings registrations {{ mastodon_registrations }}'
+ environment:
+ RAILS_ENV: production
+ become: yes
+ become_user: '{{ mastodon_user }}'
+ changed_when: no
diff --git a/roles/mastodon/templates/etc/systemd/system/mastodon-cleanup.service.j2 b/roles/mastodon/templates/etc/systemd/system/mastodon-cleanup.service.j2
new file mode 100644
index 0000000..3db1ea3
--- /dev/null
+++ b/roles/mastodon/templates/etc/systemd/system/mastodon-cleanup.service.j2
@@ -0,0 +1,49 @@
+[Unit]
+Description=mastodon-cleanup
+After=network.target
+
+[Service]
+Type=oneshot
+User={{ mastodon_user }}
+WorkingDirectory={{ mastodon_install_dir }}
+Environment="RAILS_ENV=production"
+ExecStart={{ mastodon_install_dir }}/bin/tootctl media remove
+ExecStart={{ mastodon_install_dir }}/bin/tootctl preview_cards remove
+# Proc filesystem
+ProcSubset=pid
+ProtectProc=invisible
+# Capabilities
+CapabilityBoundingSet=
+# Security
+NoNewPrivileges=true
+# Sandboxing
+ProtectSystem=strict
+PrivateTmp=true
+PrivateDevices=true
+PrivateUsers=true
+ProtectHostname=true
+ProtectKernelLogs=true
+ProtectKernelModules=true
+ProtectKernelTunables=true
+ProtectControlGroups=true
+RestrictAddressFamilies=AF_INET
+RestrictAddressFamilies=AF_INET6
+RestrictAddressFamilies=AF_NETLINK
+RestrictAddressFamilies=AF_UNIX
+RestrictNamespaces=true
+LockPersonality=true
+RestrictRealtime=true
+RestrictSUIDSGID=true
+RemoveIPC=true
+PrivateMounts=true
+ProtectClock=true
+# System Call Filtering
+SystemCallArchitectures=native
+SystemCallFilter=~@cpu-emulation @debug @ipc @mount @obsolete @privileged @setuid
+SystemCallFilter=@chown
+SystemCallFilter=pipe
+SystemCallFilter=pipe2
+ReadWritePaths={{ mastodon_install_dir }}
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/mastodon/templates/etc/systemd/system/mastodon-cleanup.timer.j2 b/roles/mastodon/templates/etc/systemd/system/mastodon-cleanup.timer.j2
new file mode 100644
index 0000000..a767551
--- /dev/null
+++ b/roles/mastodon/templates/etc/systemd/system/mastodon-cleanup.timer.j2
@@ -0,0 +1,10 @@
+[Unit]
+Description=Mastodon cleanup on calendar interval
+
+[Timer]
+OnCalendar=weekly
+AccuracySec=1h
+Persistent=true
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/mastodon/templates/etc/systemd/system/mastodon-sidekiq.service.j2 b/roles/mastodon/templates/etc/systemd/system/mastodon-sidekiq.service.j2
new file mode 100644
index 0000000..9b9abfd
--- /dev/null
+++ b/roles/mastodon/templates/etc/systemd/system/mastodon-sidekiq.service.j2
@@ -0,0 +1,52 @@
+[Unit]
+Description=mastodon-sidekiq
+After=network.target
+
+[Service]
+Type=simple
+User={{ mastodon_user }}
+WorkingDirectory={{ mastodon_install_dir }}
+Environment="RAILS_ENV=production"
+Environment="DB_POOL=25"
+Environment="MALLOC_ARENA_MAX=2"
+ExecStart=/usr/bin/bundle exec sidekiq -c 25
+TimeoutSec=15
+Restart=always
+# Proc filesystem
+ProcSubset=pid
+ProtectProc=invisible
+# Capabilities
+CapabilityBoundingSet=
+# Security
+NoNewPrivileges=true
+# Sandboxing
+ProtectSystem=strict
+PrivateTmp=true
+PrivateDevices=true
+PrivateUsers=true
+ProtectHostname=true
+ProtectKernelLogs=true
+ProtectKernelModules=true
+ProtectKernelTunables=true
+ProtectControlGroups=true
+RestrictAddressFamilies=AF_INET
+RestrictAddressFamilies=AF_INET6
+RestrictAddressFamilies=AF_NETLINK
+RestrictAddressFamilies=AF_UNIX
+RestrictNamespaces=true
+LockPersonality=true
+RestrictRealtime=true
+RestrictSUIDSGID=true
+RemoveIPC=true
+PrivateMounts=true
+ProtectClock=true
+# System Call Filtering
+SystemCallArchitectures=native
+SystemCallFilter=~@cpu-emulation @debug @ipc @mount @obsolete @privileged @setuid
+SystemCallFilter=@chown
+SystemCallFilter=pipe
+SystemCallFilter=pipe2
+ReadWritePaths={{ mastodon_install_dir }}
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/mastodon/templates/etc/systemd/system/mastodon-streaming.service.j2 b/roles/mastodon/templates/etc/systemd/system/mastodon-streaming.service.j2
new file mode 100644
index 0000000..48f58ab
--- /dev/null
+++ b/roles/mastodon/templates/etc/systemd/system/mastodon-streaming.service.j2
@@ -0,0 +1,51 @@
+[Unit]
+Description=mastodon-streaming
+After=network.target
+
+[Service]
+Type=simple
+User={{ mastodon_user }}
+WorkingDirectory={{ mastodon_install_dir }}
+Environment="NODE_ENV=production"
+Environment="PORT={{ mastodon_streaming_port }}"
+Environment="STREAMING_CLUSTER_NUM=1"
+ExecStart=/usr/bin/node ./streaming
+TimeoutSec=15
+Restart=always
+# Proc filesystem
+ProcSubset=pid
+ProtectProc=invisible
+# Capabilities
+CapabilityBoundingSet=
+# Security
+NoNewPrivileges=true
+# Sandboxing
+ProtectSystem=strict
+PrivateTmp=true
+PrivateDevices=true
+PrivateUsers=true
+ProtectHostname=true
+ProtectKernelLogs=true
+ProtectKernelModules=true
+ProtectKernelTunables=true
+ProtectControlGroups=true
+RestrictAddressFamilies=AF_INET
+RestrictAddressFamilies=AF_INET6
+RestrictAddressFamilies=AF_NETLINK
+RestrictAddressFamilies=AF_UNIX
+RestrictNamespaces=true
+LockPersonality=true
+RestrictRealtime=true
+RestrictSUIDSGID=true
+RemoveIPC=true
+PrivateMounts=true
+ProtectClock=true
+# System Call Filtering
+SystemCallArchitectures=native
+SystemCallFilter=~@cpu-emulation @debug @ipc @memlock @mount @obsolete @privileged @resources @setuid
+SystemCallFilter=pipe
+SystemCallFilter=pipe2
+ReadWritePaths={{ mastodon_install_dir }}
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/mastodon/templates/etc/systemd/system/mastodon-web.service.j2 b/roles/mastodon/templates/etc/systemd/system/mastodon-web.service.j2
new file mode 100644
index 0000000..6a3fd03
--- /dev/null
+++ b/roles/mastodon/templates/etc/systemd/system/mastodon-web.service.j2
@@ -0,0 +1,52 @@
+[Unit]
+Description=mastodon-web
+After=network.target
+
+[Service]
+Type=simple
+User={{ mastodon_user }}
+WorkingDirectory={{ mastodon_install_dir }}
+Environment="RAILS_ENV=production"
+Environment="PORT={{ mastodon_web_port }}"
+ExecStart=/usr/bin/bundle exec puma -C config/puma.rb
+ExecReload=/bin/kill -SIGUSR1 $MAINPID
+TimeoutSec=15
+Restart=always
+# Proc filesystem
+ProcSubset=pid
+ProtectProc=invisible
+# Capabilities
+CapabilityBoundingSet=
+# Security
+NoNewPrivileges=true
+# Sandboxing
+ProtectSystem=strict
+PrivateTmp=true
+PrivateDevices=true
+PrivateUsers=true
+ProtectHostname=true
+ProtectKernelLogs=true
+ProtectKernelModules=true
+ProtectKernelTunables=true
+ProtectControlGroups=true
+RestrictAddressFamilies=AF_INET
+RestrictAddressFamilies=AF_INET6
+RestrictAddressFamilies=AF_NETLINK
+RestrictAddressFamilies=AF_UNIX
+RestrictNamespaces=true
+LockPersonality=true
+RestrictRealtime=true
+RestrictSUIDSGID=true
+RemoveIPC=true
+PrivateMounts=true
+ProtectClock=true
+# System Call Filtering
+SystemCallArchitectures=native
+SystemCallFilter=~@cpu-emulation @debug @ipc @mount @obsolete @privileged @setuid
+SystemCallFilter=@chown
+SystemCallFilter=pipe
+SystemCallFilter=pipe2
+ReadWritePaths={{ mastodon_install_dir }}
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/mastodon/templates/opt/mastodon/mastodon/.env.production.j2 b/roles/mastodon/templates/opt/mastodon/mastodon/.env.production.j2
new file mode 100644
index 0000000..03af34a
--- /dev/null
+++ b/roles/mastodon/templates/opt/mastodon/mastodon/.env.production.j2
@@ -0,0 +1,59 @@
+# Federation
+# ----------
+# This identifies your server and cannot be changed safely later
+# ----------
+LOCAL_DOMAIN={{ mastodon_domain }}
+WEB_DOMAIN={{ mastodon_web_domain }}
+
+DEFAULT_LOCALE={{ mastodon_default_locale }}
+
+# Redis
+# -----
+REDIS_HOST=localhost
+REDIS_PORT={{ mastodon_redis_port }}
+
+# PostgreSQL
+# ----------
+DB_SSLMODE=verify-full
+DATABASE_URL=postgresql://{{ mastodon_db_user }}:{{ mastodon_db_password}}@{{ mastodon_db_host }}/{{ mastodon_db_name }}?sslmode=verify-full&sslrootcert=/etc/pki/tls/certs/ca-bundle.crt
+
+# Secrets
+# -------
+# Make sure to use `rake secret` to generate secrets
+# -------
+SECRET_KEY_BASE={{ mastodon_secret_key_base }}
+OTP_SECRET={{ mastodon_otp_secret }}
+
+# Web Push
+# --------
+# Generate with `rake mastodon:webpush:generate_vapid_key`
+# --------
+VAPID_PRIVATE_KEY={{ mastodon_vapid_public_key }}
+VAPID_PUBLIC_KEY={{ mastodon_vapid_private_key }}
+
+# Sending mail
+# ------------
+SMTP_SERVER=localhost
+SMTP_PORT=25
+SMTP_FROM_ADDRESS={{ mastodon_email_from }}
+
+# IP and session retention
+# -----------------------
+# Make sure to modify the scheduling of ip_cleanup_scheduler in config/sidekiq.yml
+# to be less than daily if you lower IP_RETENTION_PERIOD below two days (172800).
+# -----------------------
+IP_RETENTION_PERIOD=31556952
+SESSION_RETENTION_PERIOD=31556952
+
+# LDAP
+# ----
+LDAP_ENABLED=true
+LDAP_HOST={{ mastodon_ldap_host }}
+LDAP_PORT=636
+LDAP_METHOD=simple_tls
+LDAP_BASE={{ freeipa_user_basedn }}
+LDAP_BIND_DN=uid={{ mastodon_sysaccount_username }},{{ freeipa_sysaccount_basedn }}
+LDAP_PASSWORD={{ mastodon_sysaccount_password }}
+LDAP_SEARCH_FILTER=(&(%{uid}=%{email})(memberOf=cn={{ mastodon_access_group }},{{ freeipa_group_basedn }}))
+LDAP_MAIL=mail
+LDAP_UID=mastodonUsername
diff --git a/roles/mastodon/vars/main.yml b/roles/mastodon/vars/main.yml
new file mode 100644
index 0000000..cede4a0
--- /dev/null
+++ b/roles/mastodon/vars/main.yml
@@ -0,0 +1,58 @@
+mastodon_packages:
+ - nodejs
+ - yarnpkg
+ - gcc
+ - g++
+ - libicu-devel
+ - zlib-devel
+ - openssl-devel
+ - libidn-devel
+ - ruby-devel
+ - libpq-devel
+ - git
+ - ruby
+ - ImageMagick
+ - ffmpeg
+
+mastodon_keytab: /var/lib/gssproxy/clients/{{ mastodon_user }}.keytab
+mastodon_home: /opt/mastodon
+mastodon_user: mastodon
+mastodon_install_dir: '{{ mastodon_home }}/mastodon'
+mastodon_webroot: '{{ mastodon_install_dir }}/public'
+mastodon_git_repo: https://github.com/mastodon/mastodon
+
+mastodon_apache_config: |
+ {% if mastodon_login_cidrs %}
+ <Location /auth/sign_in>
+ {% for cidr in mastodon_login_cidrs %}
+ Require ip {{ cidr }}
+ {% endfor %}
+ </Location>
+ {% endif %}
+
+ <LocationMatch "^/(assets|avatars|emoji|headers|packs|sounds|system)">
+ Header always set Cache-Control "public, max-age=31536000, immutable"
+ Require all granted
+ </LocationMatch>
+
+ ProxyPass /500.html !
+ ProxyPass /sw.js !
+ ProxyPass /robots.txt !
+ ProxyPass /manifest.json !
+ ProxyPass /browserconfig.xml !
+ ProxyPass /mask-icon.svg !
+ ProxyPass /inert.css !
+ ProxyPassMatch ^(/.*\.(png|ico)$) !
+ ProxyPassMatch ^/(assets|avatars|emoji|headers|packs|sounds|system) !
+
+ {{ apache_proxy_config }}
+ ProxyPass /api/v1/streaming ws://127.0.0.1:{{ mastodon_streaming_port }}
+ ProxyPassReverse /api/v1/streaming ws://127.0.0.1:{{ mastodon_streaming_port }}
+ ProxyPass / http://127.0.0.1:{{ mastodon_web_port }}/
+ ProxyPassReverse / http://127.0.0.1:{{ mastodon_web_port }}/
+
+ ErrorDocument 500 /500.html
+ ErrorDocument 501 /500.html
+ ErrorDocument 502 /500.html
+ ErrorDocument 503 /500.html
+ ErrorDocument 504 /500.html