From 4c59374507a12d0355aa4564e155ec3617293497 Mon Sep 17 00:00:00 2001 From: Mathieu Gauthier-Pilote Date: Fri, 23 Dec 2022 10:00:00 -0500 Subject: [PATCH] =?UTF-8?q?p10166=20R=C3=B4le=20pour=20mastodon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapps/mastodon/README.md | 71 ++++++ webapps/mastodon/defaults/main.yml | 24 ++ webapps/mastodon/handlers/main.yml | 2 + webapps/mastodon/meta/main.yml | 52 ++++ webapps/mastodon/tasks/main.yml | 210 ++++++++++++++++ webapps/mastodon/tasks/upgrade.yml | 80 ++++++ webapps/mastodon/templates/env.j2 | 235 ++++++++++++++++++ .../templates/mastodon-sidekiq.service.j2 | 23 ++ .../templates/mastodon-streaming.service.j2 | 21 ++ .../templates/mastodon-web.service.j2 | 23 ++ webapps/mastodon/templates/mastodon.target.j2 | 8 + webapps/mastodon/templates/vhost.j2 | 94 +++++++ webapps/mastodon/tests/inventory | 2 + webapps/mastodon/tests/test.yml | 5 + webapps/mastodon/vars/main.yml | 2 + 15 files changed, 852 insertions(+) create mode 100644 webapps/mastodon/README.md create mode 100644 webapps/mastodon/defaults/main.yml create mode 100644 webapps/mastodon/handlers/main.yml create mode 100644 webapps/mastodon/meta/main.yml create mode 100644 webapps/mastodon/tasks/main.yml create mode 100644 webapps/mastodon/tasks/upgrade.yml create mode 100644 webapps/mastodon/templates/env.j2 create mode 100644 webapps/mastodon/templates/mastodon-sidekiq.service.j2 create mode 100644 webapps/mastodon/templates/mastodon-streaming.service.j2 create mode 100644 webapps/mastodon/templates/mastodon-web.service.j2 create mode 100644 webapps/mastodon/templates/mastodon.target.j2 create mode 100644 webapps/mastodon/templates/vhost.j2 create mode 100644 webapps/mastodon/tests/inventory create mode 100644 webapps/mastodon/tests/test.yml create mode 100644 webapps/mastodon/vars/main.yml diff --git a/webapps/mastodon/README.md b/webapps/mastodon/README.md new file mode 100644 index 00000000..e12ef769 --- /dev/null +++ b/webapps/mastodon/README.md @@ -0,0 +1,71 @@ +Role Name +========= + +Ce rôle installe le serveur de Mastodon, une application libre de microblogage, libre et autohébergée. + +Requirements +------------ + +... + +Role Variables +-------------- + +Plusieurs des valeurs par défaut dans defaults/main.yml doivent être changées soit directement dans defaults/main.yml ou mieux encore en les supplantant ailleurs, par exemple dans votre playbook (voir l'exemple ci-bas). + +Dependencies +------------ + +Ce rôle Ansible dépend des rôles suivants : + +- nodejs +- postgresql +- redis +- elasticsearch +- rbenv +- nginx +- certbot + +Example Playbook +---------------- + +``` +- name: "Déployer un serveur Mastodon" + hosts: + - all + vars: + # Supplanter ici les variables du rôle + domains: ['votre-vrai-domaine.org'] + service: 'mon-mastodon' + db_host: 'localhost' + db_user: "{{ service }}" + db_name: "{{ service }}" + db_password: 'zKEh-CHANGEZ-MOI-qIKc' + app_secret_key_base: "" + app_otp_secret: "" + app_vapid_private_key: "" + app_vapid_public_key: "" + app_smtp_from_address: "mastodon@votre-vrai-domaine.org" + + pre_tasks: + - name: "Installer les rôles systèmes" + roles: + - { role: nodejs, nodejs_apt_version: 'node_16.x', nodejs_install_yarn: True } + - { role: postgresql } + - { role: redis } + - { role: elasticsearch } + - { role: nginx } + - { role: certbot } + roles: + - { role: webapps/mastodon , tags: "mastodon" } +``` + +License +------- + +BSD + +Author Information +------------------ + +Mathieu Gauthier-Pilote, administrateur de systèmes chez Evolix. diff --git a/webapps/mastodon/defaults/main.yml b/webapps/mastodon/defaults/main.yml new file mode 100644 index 00000000..d5b82550 --- /dev/null +++ b/webapps/mastodon/defaults/main.yml @@ -0,0 +1,24 @@ +--- +# defaults file for mastodon +system_dep: "['imagemagick', 'ffmpeg', 'libpq-dev', 'libxml2-dev', 'libxslt1-dev', 'file', 'git-core', 'g++', 'libprotobuf-dev', 'protobuf-compiler', 'pkg-config', 'nodejs', 'gcc', 'autoconf', 'bison', 'build-essential', 'libssl-dev', 'libyaml-dev', 'libreadline6-dev', 'zlib1g-dev', 'libncurses5-dev', 'libffi-dev', 'libgdbm-dev', 'nginx', 'redis-server', 'redis-tools', 'postgresql', 'postgresql-contrib', 'certbot', 'python3-certbot-nginx', 'libidn11-dev', 'libicu-dev', 'libjemalloc-dev', 'yarn']" +domains: ['exemple.evolix.org'] +git_url: 'https://github.com/mastodon/mastodon.git' +git_version: 'v4.0.2' +ruby_version: '3.0.4' +service: 'exemple' + +db_host: 'localhost' +db_user: "{{ service }}" +db_name: "{{ service }}_production" +db_password: 'CHANGE_ME' + +app_secret_key_base: "" +app_otp_secret: "" +app_vapid_private_key: "" +app_vapid_public_key: "" +app_smtp_server: "127.0.0.1" +app_smtp_port: "25" +app_smtp_from_address: "exemple@evolix.org" +app_smtp_auth_method: "none" +app_smtp_openssl_verify_mode: "none" +app_es_enabled: "false" diff --git a/webapps/mastodon/handlers/main.yml b/webapps/mastodon/handlers/main.yml new file mode 100644 index 00000000..ba8d85b1 --- /dev/null +++ b/webapps/mastodon/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for mastodon diff --git a/webapps/mastodon/meta/main.yml b/webapps/mastodon/meta/main.yml new file mode 100644 index 00000000..c572acc9 --- /dev/null +++ b/webapps/mastodon/meta/main.yml @@ -0,0 +1,52 @@ +galaxy_info: + author: your name + description: your role description + company: your company (optional) + + # If the issue tracker for your role is not on github, uncomment the + # next line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + # Choose a valid license ID from https://spdx.org - some suggested licenses: + # - BSD-3-Clause (default) + # - MIT + # - GPL-2.0-or-later + # - GPL-3.0-only + # - Apache-2.0 + # - CC-BY-4.0 + license: license (GPL-2.0-or-later, MIT, etc) + + min_ansible_version: 2.1 + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + # + # Provide a list of supported platforms, and for each platform a list of versions. + # If you don't wish to enumerate all versions for a particular platform, use 'all'. + # To view available platforms and versions (or releases), visit: + # https://galaxy.ansible.com/api/v1/platforms/ + # + # platforms: + # - name: Fedora + # versions: + # - all + # - 25 + # - name: SomePlatform + # versions: + # - all + # - 1.0 + # - 7 + # - 99.99 + + galaxy_tags: [] + # List tags for your role here, one per line. A tag is a keyword that describes + # and categorizes the role. Users find roles by searching for tags. Be sure to + # remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric characters. + # Maximum 20 tags per role. + +dependencies: [] + # List your role dependencies here, one per line. Be sure to remove the '[]' above, + # if you add dependencies to this list. diff --git a/webapps/mastodon/tasks/main.yml b/webapps/mastodon/tasks/main.yml new file mode 100644 index 00000000..fed52d83 --- /dev/null +++ b/webapps/mastodon/tasks/main.yml @@ -0,0 +1,210 @@ +--- +# tasks file for mastodon + +- name: Install main system dependencies + apt: + name: "{{ system_dep }}" + +- name: Add PostgreSQL user + postgresql_user: + name: "{{ db_user }}" + password: "{{ db_password }}" + role_attr_flags: CREATEDB + become_user: postgres + +- name: Add UNIX account + user: + name: "{{ service }}" + shell: /bin/bash +# umask: "0022" nécessite ansible-core 2.12 + +- name: Install Ruby for service user (rbenv) + include_role: + name: rbenv + vars: + - username: "{{ service }}" + - rbenv_ruby_version: "{{ ruby_version }}" + +- name: Clone Mastodon repo (git) + git: + repo: "{{ git_url }}" + dest: "~/mastodon/" + version: "{{ git_version | default(omit) }}" + #force: yes + update: yes + become_user: "{{ service }}" + +- block: + - name: Install bundler + shell: ". ~/.profile && gem install bundler --no-document" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + - name: Install gem dependencies + shell: ". ~/.profile && bundle install --deployment --without development test -j$(getconf _NPROCESSORS_ONLN)" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + - name: Install javascript dependencies + shell: ". ~/.profile && yarn install --pure-lockfile" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + become_user: "{{ service }}" + +- name: Template .env.production configuration file + template: + src: "env.j2" + dest: "~{{ service }}/mastodon/.env.production" + owner: "{{ service }}" + group: "{{ service }}" + mode: "0640" + +- name: Check if secrets need to be generated or not + shell: "grep -P SECRET_KEY_BASE=[[:alnum:]]{128} .env.production" + args: + chdir: "~/mastodon" + become_user: "{{ service }}" + register: secrets + failed_when: "secrets.rc == 2" + +- block: + - name: Generate secret for SECRET_KEY_BASE + shell: '. ~/.profile && sed -i -r "s/SECRET_KEY_BASE=/SECRET_KEY_BASE=$(RAILS_ENV=production bundle exec rake secret)/" .env.production' + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + - name: Generate secret for OTP_SECRET + shell: '. ~/.profile && sed -i -r "s/OTP_SECRET=/OTP_SECRET=$(RAILS_ENV=production bundle exec rake secret)/" .env.production' + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + - name: Generate secret for VAPID_PRIVATE_KEY and VAPID_PUBLIC_KEY + shell: . ~/.profile && RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key > vapid.tmp | head -1 | cut -c 19- + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + - name: Read VAPID_PRIVATE_KEY secret from temp file + shell: "cat vapid.tmp | head -1 | cut -c 19-" + args: + chdir: "~/mastodon" + register: app_vapid_private_key + - name: Read VAPID_PUBLIC_KEY secret from temp file + shell: "cat vapid.tmp | tail -1 | cut -c 18-" + args: + chdir: "~/mastodon" + register: app_vapid_public_key + - name: Delete secrets temp file + file: + path: "~/mastodon/vapid.tmp" + state: absent + - name: Write app_vapid_private_key to production .env file + lineinfile: + path: "~/mastodon/.env.production" + regexp: '^VAPID_PRIVATE_KEY=' + line: "VAPID_PRIVATE_KEY={{ app_vapid_private_key.stdout }}" + - name: Write app_vapid_public_key to production .env file + lineinfile: + path: "~/mastodon/.env.production" + regexp: '^VAPID_PUBLIC_KEY=' + line: "VAPID_PUBLIC_KEY={{ app_vapid_public_key.stdout }}" + become_user: "{{ service }}" + when: "secrets.rc == 1" + +- name: Check if mastodon database is already present or not + shell: | + psql -lqt | cut -d \| -f 1 | grep -qw {{ service }}_production + become_user: postgres + register: db_present + failed_when: "db_present.rc == 2" + +- name: Setup database schema if database not already present + shell: ". ~/.profile && RAILS_ENV=production SAFETY_ASSURED=1 bundle exec rails db:setup" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + become_user: "{{ service }}" + when: "db_present.rc == 1" + +- name: Precompile assets + shell: ". ~/.profile && RAILS_ENV=production bundle exec rails assets:precompile" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + become_user: "{{ service }}" + +- name: Add systemd target + template: + src: "mastodon.target.j2" + dest: "/etc/systemd/system/{{ service }}.target" + +- name: Add systemd web unit + template: + src: "mastodon-web.service.j2" + dest: "/etc/systemd/system/{{ service }}-web.service" + +- name: Add systemd sidekiq unit + template: + src: "mastodon-sidekiq.service.j2" + dest: "/etc/systemd/system/{{ service }}-sidekiq.service" + +- name: Add systemd streaming unit + template: + src: "mastodon-streaming.service.j2" + dest: "/etc/systemd/system/{{ service }}-streaming.service" + +- name: Enable systemd units + systemd: + name: "{{ item }}" + enabled: yes + daemon_reload: yes + loop: + - "{{ service }}.target" + - "{{ service }}-web.service" + - "{{ service }}-sidekiq.service" + - "{{ service }}-streaming.service" + +- name: Start services + service: + name: "{{ service }}.target" + state: started + +- name: Check if SSL certificate is present and register result + stat: + path: "/etc/letsencrypt/live/{{ domains |first }}/fullchain.pem" + register: ssl + +#- name: Generate certificate only if required (first time) + #block: + #- name: Template vhost without SSL for successfull LE challengce + #template: + #src: "vhost.j2" + #dest: "/etc/nginx/sites-available/{{ service }}" + #- name: Enable temporary nginx vhost for LE + #file: + #src: "/etc/nginx/sites-available/{{ service }}" + #dest: "/etc/nginx/sites-enabled/{{ service }}" + #state: link + #- name: Reload nginx conf + #service: + #name: nginx + #state: reloaded + #- name: Generate certificate with certbot + #shell: certbot certonly --webroot --webroot-path /var/lib/letsencrypt -d {{ domains |first }} + #when: ssl.stat.exists == false + +#- name: (Re)template conf file for nginx vhost with SSL + #template: + #src: "vhost.j2" + #dest: "/etc/nginx/sites-available/{{ service }}" + +#- name: Enable nginx vhost for mastodon + #file: + #src: "/etc/nginx/sites-available/{{ service }}" + #dest: "/etc/nginx/sites-enabled/{{ service }}" + #state: link + +#- name: Reload nginx conf + #service: + #name: nginx + #state: reloaded diff --git a/webapps/mastodon/tasks/upgrade.yml b/webapps/mastodon/tasks/upgrade.yml new file mode 100644 index 00000000..74959d3e --- /dev/null +++ b/webapps/mastodon/tasks/upgrade.yml @@ -0,0 +1,80 @@ +--- +# tasks file for mastodon + +- name: Dump database to a file with compression + postgresql_db: + name: "{{ service }}_production" + state: dump + target: "{{ service }}_production.sql.gz" + become_user: postgres + +- name: Checkout (git) + git: + repo: "{{ git_url }}" + dest: "~/mastodon/" + version: "{{ git_version | default(omit) }}" + #force: yes + update: yes + become_user: "{{ service }}" + +- block: + - name: Install bundler + shell: ". ~/.profile && gem install bundler --no-document" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + - name: Install gem dependencies + shell: ". ~/.profile && bundle install --deployment --without development test -j$(getconf _NPROCESSORS_ONLN)" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + - name: Install javascript dependencies + shell: ". ~/.profile && yarn install --pure-lockfile" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + - name: Run database migrations, skipping post-deployment + shell: ". ~/.profile && SKIP_POST_DEPLOYMENT_MIGRATIONS=true RAILS_ENV=production bundle exec rails db:migrate" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + - name: Precompile assets + shell: ". ~/.profile && RAILS_ENV=production bundle exec rails assets:precompile" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + become_user: "{{ service }}" + +- name: Restart services + service: + name: "{{ service }}.target" + state: restarted + +- name: Run database migrations, this time including post-deployment + shell: ". ~/.profile && SKIP_POST_DEPLOYMENT_MIGRATIONS=true RAILS_ENV=production bundle exec rails db:migrate" + args: + chdir: "~/mastodon" + executable: /bin/bash # fails with /bin/sh + become_user: "{{ service }}" + +- name: Define variable to skip next task by default + set_fact: + keep_db_dump: true + +- name: Remove database dump + file: + path: "{{ service }}_production.sql.gz" + state: absent + become_user: postgres + when: keep_db_dump is undefined + tags: clean + +- name: Template conf file for nginx vhost + template: + src: "vhost.j2" + dest: "/etc/nginx/sites-available/{{ service }}" + +- name: Reload nginx conf + service: + name: nginx + state: reloaded diff --git a/webapps/mastodon/templates/env.j2 b/webapps/mastodon/templates/env.j2 new file mode 100644 index 00000000..69fe5cd9 --- /dev/null +++ b/webapps/mastodon/templates/env.j2 @@ -0,0 +1,235 @@ +# 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_URL=unix:///var/run/redis/redis.sock +REDIS_HOST=localhost +REDIS_PORT=6379 +REDIS_PASSWORD= +REDIS_NAMESPACE={{ service }} +# You may set DATABASE_URL instead for more advanced options +DB_HOST={{ db_host }} +DB_USER={{ db_user }} +DB_NAME={{ db_name }} +DB_PASS='{{ db_password }}' +DB_PORT=5432 +# Optional ElasticSearch configuration +#ES_ENABLED={{ app_es_enabled | default('false') }} +#ES_HOST={{ app_es_host | default('localhost') }} +#ES_PORT={{ app_es_port | default('9200') }} + +# 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={{ domains |first }} + +# Changing LOCAL_HTTPS in production is no longer supported. (Mastodon will always serve https:// links) + +# 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.example.com + +# 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 rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose) +SECRET_KEY_BASE={{ app_secret_key_base }} +OTP_SECRET={{ app_otp_secret }} + +# 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 rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake 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={{ app_vapid_private_key }} +VAPID_PUBLIC_KEY={{ app_vapid_public_key }} + +# Registrations +# Single user mode will disable registrations and redirect frontpage to the first profile +# SINGLE_USER_MODE=true +# 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={{ app_smtp_server | default('smtp.mailgun.org') }} +SMTP_PORT={{ app_smtp_port | default('587') }} +#SMTP_LOGIN= +#SMTP_PASSWORD= +SMTP_FROM_ADDRESS={{ app_smtp_from_address | default('notifications@example.com') }} +#SMTP_DOMAIN= # defaults to LOCAL_DOMAIN +#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail +SMTP_AUTH_METHOD={{ app_smtp_auth_method | default('plain') }} +#SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt +#SMTP_OPENSSL_VERIFY_MODE={{ app_smtp_openssl_verify_mode | default('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= + +# 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. +# UID=1000 +# GID=1000 + +# 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= +# SAML_ISSUER=http://localhost:3000/auth/auth/saml/callback +# SAML_IDP_SSO_TARGET_URL=https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO +# SAML_IDP_CERT= +# SAML_IDP_CERT_FINGERPRINT= +# SAML_NAME_IDENTIFIER_FORMAT= +# 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="urn:oid:0.9.2342.19200300.100.1.1" +# SAML_ATTRIBUTES_STATEMENTS_EMAIL="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" +# 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="urn:oid:0.9.2342.19200300.100.1.1" +# 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 diff --git a/webapps/mastodon/templates/mastodon-sidekiq.service.j2 b/webapps/mastodon/templates/mastodon-sidekiq.service.j2 new file mode 100644 index 00000000..c2909526 --- /dev/null +++ b/webapps/mastodon/templates/mastodon-sidekiq.service.j2 @@ -0,0 +1,23 @@ +[Unit] +Description=mastodon-sidekiq +After=network.target +PartOf={{service}}.target + +[Service] +Type=simple +User={{service}} +Group={{service}} +UMask=0027 +WorkingDirectory=/home/{{service}}/mastodon/ +Environment="RAILS_ENV=production" +Environment="RAILS_LOG_LEVEL=error" +Environment="DB_POOL=25" +Environment="MALLOC_ARENA_MAX=2" +Environment="LD_PRELOAD=libjemalloc.so" +ExecStart=/home/{{service}}/.rbenv/shims/bundle exec sidekiq -c 25 +TimeoutSec=15 +Restart=always +SyslogIdentifier=%p + +[Install] +WantedBy={{service}}.target diff --git a/webapps/mastodon/templates/mastodon-streaming.service.j2 b/webapps/mastodon/templates/mastodon-streaming.service.j2 new file mode 100644 index 00000000..859d7506 --- /dev/null +++ b/webapps/mastodon/templates/mastodon-streaming.service.j2 @@ -0,0 +1,21 @@ +[Unit] +Description=mastodon-streaming +After=network.target +PartOf={{service}}.target + +[Service] +Type=simple +User={{service}} +Group={{service}} +UMask=0027 +WorkingDirectory=/home/{{service}}/mastodon/ +Environment="NODE_ENV=production" +Environment="PORT={{ node_port | default('4000')}}" +Environment="STREAMING_CLUSTER_NUM=1" +ExecStart=/bin/bash -lc "node ./streaming" +TimeoutSec=15 +Restart=always +SyslogIdentifier=%p + +[Install] +WantedBy={{service}}.target diff --git a/webapps/mastodon/templates/mastodon-web.service.j2 b/webapps/mastodon/templates/mastodon-web.service.j2 new file mode 100644 index 00000000..5f249325 --- /dev/null +++ b/webapps/mastodon/templates/mastodon-web.service.j2 @@ -0,0 +1,23 @@ +[Unit] +Description=mastodon-web +After=network.target +PartOf={{service}}.target + +[Service] +Type=simple +User={{service}} +Group={{service}} +UMask=0027 +WorkingDirectory=/home/{{service}}/mastodon/ +Environment="RAILS_ENV=production" +Environment="PORT={{puma_port|default('3000')}}" +Environment="RAILS_LOG_LEVEL=warn" +Environment="LD_PRELOAD=libjemalloc.so" +ExecStart=/home/{{service}}/.rbenv/shims/bundle exec puma -C config/puma.rb +ExecReload=/bin/kill -SIGUSR1 $MAINPID +TimeoutSec=15 +Restart=always +SyslogIdentifier=%p + +[Install] +WantedBy={{service}}.target diff --git a/webapps/mastodon/templates/mastodon.target.j2 b/webapps/mastodon/templates/mastodon.target.j2 new file mode 100644 index 00000000..0eb5475a --- /dev/null +++ b/webapps/mastodon/templates/mastodon.target.j2 @@ -0,0 +1,8 @@ +[Unit] +Description=Mastodon Microblogging service +Wants=redis-server.service +After=redis-server.service +Requires={{ service }}-web.service {{ service }}-sidekiq.service {{ service }}-streaming.service + +[Install] +WantedBy=multi-user.target diff --git a/webapps/mastodon/templates/vhost.j2 b/webapps/mastodon/templates/vhost.j2 new file mode 100644 index 00000000..fc27c041 --- /dev/null +++ b/webapps/mastodon/templates/vhost.j2 @@ -0,0 +1,94 @@ +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +server { + listen 80; + listen [::]:80; + server_name {{ domains |first }}; + include /etc/nginx/snippets/letsencrypt.conf; + {% if ssl.stat.exists %} + location / { return 301 https://$host$request_uri; } + {% endif %} +} + +{% if ssl.stat.exists %} +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name {{ domains |first }}; + + include /etc/nginx/ssl/{{ service }}.conf; + include /etc/nginx/snippets/letsencrypt.conf; + + # OCSP stapling + ssl_stapling on; + ssl_stapling_verify on; + + + keepalive_timeout 70; + sendfile on; + client_max_body_size 0; + + root /home/{{ service }}/mastodon/public; + + gzip on; + gzip_disable "msie6"; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + 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; + + #add_header Strict-Transport-Security "max-age=31536000"; + #add_header Content-Security-Policy "style-src 'self' 'unsafe-inline'; script-src 'self'; object-src 'self'; img-src data: https:; media-src data: https:; connect-src 'self' wss://{{ domains |first }}; upgrade-insecure-requests"; + + location / { + try_files $uri @proxy; + } + + location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) { + add_header Cache-Control "public, max-age=31536000, immutable"; + try_files $uri @proxy; + } + + location @proxy { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Proxy ""; + proxy_pass_header Server; + + proxy_pass http://127.0.0.1:{{puma_port|default('3000')}}; + proxy_buffering off; + proxy_redirect off; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + + tcp_nodelay on; + } + + location /api/v1/streaming { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Proxy ""; + + proxy_pass http://127.0.0.1:{{ node_port | default('4000')}}; + proxy_buffering off; + proxy_redirect off; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + + tcp_nodelay on; + } + + error_page 500 501 502 503 504 /500.html; +} +{% endif %} diff --git a/webapps/mastodon/tests/inventory b/webapps/mastodon/tests/inventory new file mode 100644 index 00000000..878877b0 --- /dev/null +++ b/webapps/mastodon/tests/inventory @@ -0,0 +1,2 @@ +localhost + diff --git a/webapps/mastodon/tests/test.yml b/webapps/mastodon/tests/test.yml new file mode 100644 index 00000000..708aca84 --- /dev/null +++ b/webapps/mastodon/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - mastodon diff --git a/webapps/mastodon/vars/main.yml b/webapps/mastodon/vars/main.yml new file mode 100644 index 00000000..85eebfd2 --- /dev/null +++ b/webapps/mastodon/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for mastodon