Compare commits
1 Commits
327943d96a
...
accd829e91
Author | SHA1 | Date | |
---|---|---|---|
accd829e91
|
@ -9,6 +9,9 @@ available.
|
|||||||
|
|
||||||
## Roles
|
## Roles
|
||||||
|
|
||||||
|
- [`mastodon`](roles/mastodon/README.md): deployment using a container based
|
||||||
|
setup, able to use webfinger delegation.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[CNPLv7+](LICENSE.md): Cooperative Nonviolent Public License
|
[CNPLv7+](LICENSE.md): Cooperative Nonviolent Public License
|
||||||
|
65
roles/mastodon/README.md
Normal file
65
roles/mastodon/README.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# `finallycoffee.fediverse.mastodon` ansible role
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This role aims to automate as much as possible with running a docker container
|
||||||
|
based mastodon setup. It provides you with the streaming container, sidekiq and
|
||||||
|
web (api) as well an nginx routing the application traffic.
|
||||||
|
|
||||||
|
You need to provide a postgresql database, the redis server, optionally an
|
||||||
|
elasticsearch instance and the mail server. Roles providing components are linked,
|
||||||
|
if applicable.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
The minimum configuration could be as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
mastodon_domain: finally.coffee
|
||||||
|
# Optional, if you want to host your frontend + api somewhere else
|
||||||
|
mastodon_web_domain: frontend.some.website
|
||||||
|
|
||||||
|
# you need to provide and manage the following secrets
|
||||||
|
mastodon_secret_key: very_long_secret
|
||||||
|
mastodon_otp_secret: also_very_long_secret
|
||||||
|
mastodon_vapid_public_key: check_mastodon_docs_for_this
|
||||||
|
mastodon_vapid_private_key: see_above
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Database
|
||||||
|
|
||||||
|
The database configuration is as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
mastodon_database_host: postgres.local
|
||||||
|
mastodon_database_port: 5432 #optional, defaults to this
|
||||||
|
mastodon_database_user: mastodont
|
||||||
|
mastodon_database_pass: hopefully_secure
|
||||||
|
mastodon_database_name: mastodon
|
||||||
|
```
|
||||||
|
|
||||||
|
For seeding the database during initial deployment, you need to set
|
||||||
|
`mastodon_seed_database: true` exactly once (when it succeeds).
|
||||||
|
|
||||||
|
### Redis
|
||||||
|
|
||||||
|
As of writing this, it seems that atleast one component of mastodon can't
|
||||||
|
deal with a password for redis, leading to the need to run redis without
|
||||||
|
authentification for all components:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
mastodon_redis_url: unix:///var/run/redis/mastodon.sock
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Mail
|
||||||
|
|
||||||
|
The mail server for verifications and notifications can be configured as followed:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
mastodon_mail_server: mail.example.org
|
||||||
|
mastodon_mail_user: mailuser@mydomain.org
|
||||||
|
mastodon_mail_password: very_secure_password_for_mailing_account
|
||||||
|
```
|
||||||
|
|
||||||
|
For further Configuration, see [`defaults/main.yml`](defaults/main.yml) to
|
||||||
|
override further keys for configuration
|
@ -3,6 +3,7 @@
|
|||||||
mastodon_user: mastodon
|
mastodon_user: mastodon
|
||||||
mastodon_base_path: /opt/mastodon
|
mastodon_base_path: /opt/mastodon
|
||||||
mastodon_domain: ~
|
mastodon_domain: ~
|
||||||
|
mastodon_web_domain: ~
|
||||||
mastodon_version: 3.5.1
|
mastodon_version: 3.5.1
|
||||||
mastodon_git_upstream_url: "https://github.com/mastodon/mastodon.git"
|
mastodon_git_upstream_url: "https://github.com/mastodon/mastodon.git"
|
||||||
|
|
||||||
@ -10,6 +11,14 @@ mastodon_data_path: "{{ mastodon_base_path }}/data"
|
|||||||
mastodon_repo_path: "{{ mastodon_base_path }}/src"
|
mastodon_repo_path: "{{ mastodon_base_path }}/src"
|
||||||
mastodon_config_path: "{{ mastodon_base_path }}/config"
|
mastodon_config_path: "{{ mastodon_base_path }}/config"
|
||||||
mastodon_config_env_file: "{{ mastodon_config_path }}/env.production"
|
mastodon_config_env_file: "{{ mastodon_config_path }}/env.production"
|
||||||
|
mastodon_nginx_config_path: "{{ mastodon_base_path }}/nginx-config"
|
||||||
|
mastodon_nginx_config_file: "{{ mastodon_nginx_config_path }}/nginx.conf"
|
||||||
|
mastodon_nginx_cache_path: "{{ mastodon_base_path }}/nginx-cache"
|
||||||
|
|
||||||
|
mastodon_container_bind_ip: "127.0.0.1"
|
||||||
|
mastodon_streaming_backend: "{{ mastodon_container_bind_ip }}:4000"
|
||||||
|
mastodon_api_backend: "{{ mastodon_container_bind_ip }}:3000"
|
||||||
|
mastodon_backend: "{{ mastodon_container_bind_ip }}:5000"
|
||||||
|
|
||||||
mastodon_container_name: mastodon
|
mastodon_container_name: mastodon
|
||||||
mastodon_container_name_sidekiq: "{{ mastodon_container_name }}_sidekiq"
|
mastodon_container_name_sidekiq: "{{ mastodon_container_name }}_sidekiq"
|
||||||
@ -32,17 +41,33 @@ mastodon_container_volumes_sidekiq: >-
|
|||||||
{{ mastodon_container_base_volumes_sidekiq + mastodon_container_extra_volumes_sidekiq }}
|
{{ mastodon_container_base_volumes_sidekiq + mastodon_container_extra_volumes_sidekiq }}
|
||||||
|
|
||||||
mastodon_container_base_volumes:
|
mastodon_container_base_volumes:
|
||||||
- "{{ mastodon_repo_path }}/public/system:/mastodon/public/system:z"
|
- "{{ mastodon_repo_path }}/public:/mastodon/public:z"
|
||||||
mastodon_container_extra_volumes: []
|
mastodon_container_extra_volumes: []
|
||||||
mastodon_container_volumes: >-
|
mastodon_container_volumes: >-
|
||||||
{{ mastodon_container_base_volumes + mastodon_container_extra_volumes }}
|
{{ mastodon_container_base_volumes + mastodon_container_extra_volumes }}
|
||||||
|
|
||||||
mastodon_container_ports_streaming:
|
mastodon_container_ports_streaming:
|
||||||
- "127.0.0.1:4000:4000"
|
- "{{ mastodon_streaming_backend }}:4000"
|
||||||
mastodon_container_ports:
|
mastodon_container_ports:
|
||||||
- "127.0.0.1:3000:3000"
|
- "{{ mastodon_api_backend }}:3000"
|
||||||
mastodon_container_restart_policy: unless-stopped
|
mastodon_container_restart_policy: unless-stopped
|
||||||
|
|
||||||
|
mastodon_nginx_version: 1.21.6
|
||||||
|
mastodon_nginx_server_name: "{{ mastodon_domain }}"
|
||||||
|
mastodon_container_nginx_name: "{{ mastodon_container_name }}_nginx"
|
||||||
|
mastodon_container_nginx_image_name: docker.io/library/nginx
|
||||||
|
mastodon_container_nginx_image_tag: ~
|
||||||
|
mastodon_container_nginx_image_flavour: alpine
|
||||||
|
mastodon_container_nginx_image: >-2
|
||||||
|
{{ mastodon_container_nginx_image_name }}:{{ mastodon_container_nginx_image_tag
|
||||||
|
| default(mastodon_nginx_version + ('-' + mastodon_container_nginx_image_flavour if mastodon_container_nginx_image_flavour else ''), True) }}
|
||||||
|
mastodon_container_nginx_working_directory: "/var/www/mastodon"
|
||||||
|
mastodon_container_nginx_cache_directory: "/var/cache/nginx"
|
||||||
|
mastodon_container_volumes_nginx:
|
||||||
|
- "{{ mastodon_nginx_config_file }}:/etc/nginx/conf.d/default.conf:ro"
|
||||||
|
- "{{ mastodon_repo_path }}/public:{{ mastodon_container_nginx_working_directory }}:ro"
|
||||||
|
- "{{ mastodon_nginx_cache_path }}:{{ mastodon_container_nginx_cache_directory }}:z"
|
||||||
|
|
||||||
mastodon_container_network_name: mastodon
|
mastodon_container_network_name: mastodon
|
||||||
|
|
||||||
mastodon_secret_key: ~
|
mastodon_secret_key: ~
|
||||||
@ -52,6 +77,7 @@ mastodon_vapid_private_key: ~
|
|||||||
|
|
||||||
mastodon_redis_host: ~
|
mastodon_redis_host: ~
|
||||||
mastodon_redis_port: ~
|
mastodon_redis_port: ~
|
||||||
|
mastodon_redis_url: ~
|
||||||
mastodon_redis_password: ~
|
mastodon_redis_password: ~
|
||||||
mastodon_redis_db_index: ~
|
mastodon_redis_db_index: ~
|
||||||
|
|
||||||
|
@ -24,3 +24,10 @@
|
|||||||
state: started
|
state: started
|
||||||
restart: true
|
restart: true
|
||||||
listen: restart-mastodon
|
listen: restart-mastodon
|
||||||
|
|
||||||
|
- name: Restart mastodon nginx
|
||||||
|
docker_container:
|
||||||
|
name: "{{ mastodon_container_nginx_name }}"
|
||||||
|
state: started
|
||||||
|
restart: true
|
||||||
|
listen: restart-mastodon-nginx
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
- path: "{{ mastodon_data_path }}"
|
- path: "{{ mastodon_data_path }}"
|
||||||
- path: "{{ mastodon_repo_path }}"
|
- path: "{{ mastodon_repo_path }}"
|
||||||
mode: '0700'
|
mode: '0700'
|
||||||
|
- path: "{{ mastodon_nginx_config_path }}"
|
||||||
|
- path: "{{ mastodon_nginx_cache_path }}"
|
||||||
loop_control: { label: "{{ item.path }}" }
|
loop_control: { label: "{{ item.path }}" }
|
||||||
|
|
||||||
- name: Ensure environment file is templated
|
- name: Ensure environment file is templated
|
||||||
@ -32,6 +34,15 @@
|
|||||||
mode: "0640"
|
mode: "0640"
|
||||||
notify: restart-mastodon
|
notify: restart-mastodon
|
||||||
|
|
||||||
|
- name: Ensure reverse proxy configuration is templated
|
||||||
|
template:
|
||||||
|
src: nginx.conf.j2
|
||||||
|
dest: "{{ mastodon_nginx_config_file }}"
|
||||||
|
owner: "{{ mastodon_user_info.uid | default(mastodon_user) }}"
|
||||||
|
group: "{{ mastodon_user_info.group | default(mastodon_user) }}"
|
||||||
|
mode: "0640"
|
||||||
|
notify: restart-mastodon-nginx
|
||||||
|
|
||||||
- name: Ensure mastodon git repository is present and up-to-date
|
- name: Ensure mastodon git repository is present and up-to-date
|
||||||
git:
|
git:
|
||||||
repo: "{{ mastodon_git_upstream_url }}"
|
repo: "{{ mastodon_git_upstream_url }}"
|
||||||
@ -43,6 +54,14 @@
|
|||||||
track_submodules: yes
|
track_submodules: yes
|
||||||
register: git_repo_info
|
register: git_repo_info
|
||||||
|
|
||||||
|
- name: Ensure mastodon git repository and children belong to {{ mastodon_user }}
|
||||||
|
file:
|
||||||
|
path: "{{ mastodon_repo_path }}"
|
||||||
|
state: directory
|
||||||
|
recurse: yes
|
||||||
|
owner: "{{ mastodon_user }}"
|
||||||
|
group: "{{ mastodon_user }}"
|
||||||
|
|
||||||
- name: Ensure docker network for backend communication is created
|
- name: Ensure docker network for backend communication is created
|
||||||
docker_network:
|
docker_network:
|
||||||
name: "{{ mastodon_container_network_name }}"
|
name: "{{ mastodon_container_network_name }}"
|
||||||
@ -61,6 +80,17 @@
|
|||||||
GID: "{{ mastodon_user_info.group }}"
|
GID: "{{ mastodon_user_info.group }}"
|
||||||
when: git_repo_info.before != git_repo_info.after
|
when: git_repo_info.before != git_repo_info.after
|
||||||
|
|
||||||
|
- name: Ensure nginx reverse proxy image is present
|
||||||
|
docker_image:
|
||||||
|
name: "{{ mastodon_container_nginx_image }}"
|
||||||
|
state: present
|
||||||
|
source: pull
|
||||||
|
force_source: "{{ mastodon_container_nginx_image_tag|default(false, true) | bool }}"
|
||||||
|
register: masto_nginx_pull
|
||||||
|
until: masto_nginx_pull is succeeded
|
||||||
|
retries: 5
|
||||||
|
delay: 3
|
||||||
|
|
||||||
- name: Ensure database is seeded
|
- name: Ensure database is seeded
|
||||||
docker_container:
|
docker_container:
|
||||||
name: "{{ mastodon_container_name }}_setup_db"
|
name: "{{ mastodon_container_name }}_setup_db"
|
||||||
@ -73,6 +103,7 @@
|
|||||||
interactive: yes
|
interactive: yes
|
||||||
detach: no
|
detach: no
|
||||||
cleanup: yes
|
cleanup: yes
|
||||||
|
when: mastodon_seed_database|default(false, true)
|
||||||
|
|
||||||
- name: Ensure mastodon sidekiq container '{{ mastodon_container_name_sidekiq }}' is running
|
- name: Ensure mastodon sidekiq container '{{ mastodon_container_name_sidekiq }}' is running
|
||||||
docker_container:
|
docker_container:
|
||||||
@ -117,9 +148,29 @@
|
|||||||
command: "bash -c \"rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000\""
|
command: "bash -c \"rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000\""
|
||||||
restart_policy: "{{ mastodon_container_restart_policy }}"
|
restart_policy: "{{ mastodon_container_restart_policy }}"
|
||||||
ports: "{{ mastodon_container_ports }}"
|
ports: "{{ mastodon_container_ports }}"
|
||||||
|
user: "{{ mastodon_user }}"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "wget -q --spider --proxy=off localhost:3000/health || exit 1"]
|
test: ["CMD-SHELL", "wget -q --spider --proxy=off localhost:3000/health || exit 1"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 0s
|
start_period: 0s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
|
|
||||||
|
- name: Ensure mastodon-nginx container '{{ mastodon_container_nginx_name }}' is running
|
||||||
|
docker_container:
|
||||||
|
name: "{{ mastodon_container_nginx_name }}"
|
||||||
|
image: "{{ mastodon_container_nginx_image }}"
|
||||||
|
network_mode: host
|
||||||
|
volumes: "{{ mastodon_container_volumes_nginx }}"
|
||||||
|
restart_policy: "{{ mastodon_container_restart_policy }}"
|
||||||
|
|
||||||
|
- name: Ensure assets are precompiled
|
||||||
|
docker_container:
|
||||||
|
name: "{{ mastodon_container_name }}"
|
||||||
|
env_file: "{{ mastodon_config_env_file }}"
|
||||||
|
command: "bash -c \"bundle exec rails assets:precompile\""
|
||||||
|
user: "{{ mastodon_user }}"
|
||||||
|
tty: yes
|
||||||
|
interactive: yes
|
||||||
|
detach: no
|
||||||
|
when: git_repo_info.before != git_repo_info.after
|
||||||
|
@ -15,16 +15,26 @@
|
|||||||
# This identifies your server and cannot be changed safely later
|
# This identifies your server and cannot be changed safely later
|
||||||
# ----------
|
# ----------
|
||||||
LOCAL_DOMAIN={{ mastodon_domain }}
|
LOCAL_DOMAIN={{ mastodon_domain }}
|
||||||
|
{% if mastodon_web_domain|default(false, true) %}
|
||||||
|
WEB_DOMAIN={{ mastodon_web_domain }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
# Redis
|
# Redis
|
||||||
# -----
|
# -----
|
||||||
|
{% if mastodon_redis_host|default(false, true) %}
|
||||||
REDIS_HOST={{ mastodon_redis_host }}
|
REDIS_HOST={{ mastodon_redis_host }}
|
||||||
|
{% endif %}
|
||||||
|
{% if mastodon_redis_port|default(false, true) %}
|
||||||
REDIS_PORT={{ mastodon_redis_port }}
|
REDIS_PORT={{ mastodon_redis_port }}
|
||||||
|
{% endif %}
|
||||||
|
{% if mastodon_redis_url %}
|
||||||
|
REDIS_URL={{ mastodon_redis_url }}
|
||||||
|
{% endif %}
|
||||||
{% if mastodon_redis_password %}
|
{% if mastodon_redis_password %}
|
||||||
REDIS_PASSWORD={{ mastodon_redis_password }}
|
REDIS_PASSWORD={{ mastodon_redis_password }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if mastodon_redis_db_index %}
|
{% if mastodon_redis_db_index %}
|
||||||
REDIS_PASSWORD={{ mastodon_redis_db_index }}
|
REDIS_DB_INDEX={{ mastodon_redis_db_index }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
# PostgreSQL
|
# PostgreSQL
|
||||||
|
94
roles/mastodon/templates/nginx.conf.j2
Normal file
94
roles/mastodon/templates/nginx.conf.j2
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream backend {
|
||||||
|
server {{ mastodon_api_backend }} fail_timeout=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream streaming {
|
||||||
|
server {{ mastodon_streaming_backend }} fail_timeout=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy_cache_path {{ mastodon_container_nginx_cache_directory }} levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=2g;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen {{ mastodon_backend }};
|
||||||
|
server_name {{ mastodon_nginx_server_name }};
|
||||||
|
|
||||||
|
keepalive_timeout 70;
|
||||||
|
sendfile on;
|
||||||
|
client_max_body_size 200m;
|
||||||
|
|
||||||
|
root {{ mastodon_container_nginx_working_directory }};
|
||||||
|
|
||||||
|
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 image/svg+xml image/x-icon;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri @proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) {
|
||||||
|
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000" always;
|
||||||
|
try_files $uri @proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /sw.js {
|
||||||
|
add_header Cache-Control "public, max-age=0";
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000" always;
|
||||||
|
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 $scheme;
|
||||||
|
proxy_set_header Proxy "";
|
||||||
|
proxy_pass_header Server;
|
||||||
|
|
||||||
|
proxy_pass http://backend;
|
||||||
|
proxy_buffering on;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
|
||||||
|
proxy_cache CACHE;
|
||||||
|
proxy_cache_valid 200 7d;
|
||||||
|
proxy_cache_valid 410 24h;
|
||||||
|
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
||||||
|
add_header X-Cached $upstream_cache_status;
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000" always;
|
||||||
|
|
||||||
|
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 $scheme;
|
||||||
|
proxy_set_header Proxy "";
|
||||||
|
|
||||||
|
proxy_pass http://streaming;
|
||||||
|
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;
|
||||||
|
}
|
Reference in New Issue
Block a user