diff --git a/roles/mastodon/files/docker-compose.yaml b/roles/mastodon/files/docker-compose.yaml new file mode 100644 index 0000000..c381701 --- /dev/null +++ b/roles/mastodon/files/docker-compose.yaml @@ -0,0 +1,146 @@ +version: '3' +services: + mastodon_db: + container_name: mastodon_db + restart: always + image: postgres:14-alpine + shm_size: 256mb + networks: + - mastodon + healthcheck: + test: ['CMD', 'pg_isready', '-U', 'postgres'] + volumes: + - ./postgres14:/var/lib/postgresql/data + env_file: .env.production + environment: + - 'POSTGRES_HOST_AUTH_METHOD=trust' + + mastodon_redis: + container_name: mastodon_redis + restart: always + image: redis:7-alpine + networks: + - mastodon + healthcheck: + test: ['CMD', 'redis-cli', 'ping'] + volumes: + - ./redis:/data + + # es: + # restart: always + # image: docker.elastic.co/elasticsearch/elasticsearch:7.17.4 + # 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" +# networks: +# - mastodon +# - nginx + # healthcheck: + # test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"] + # volumes: + # - ./elasticsearch:/usr/share/elasticsearch/data + # ulimits: + # memlock: + # soft: -1 + # hard: -1 + # nofile: + # soft: 65536 + # hard: 65536 + # ports: + # - '127.0.0.1:9200:9200' + + mastodon_web: + container_name: mastodon_web + build: . + image: tootsuite/mastodon + restart: always + env_file: .env.production + command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000" + networks: + - mastodon + - nginx + healthcheck: + # prettier-ignore + test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:3000/health || exit 1'] + ports: + - '127.0.0.1:3000:3000' + depends_on: + - mastodon_db + - mastodon_redis + # - es + volumes: + - ./public/system:/mastodon/public/system + + mastodon_streaming: + container_name: mastodon_streaming + build: . + image: tootsuite/mastodon + restart: always + env_file: .env.production + environment: + - PORT=5000 + command: node ./streaming + networks: + - mastodon + - nginx + healthcheck: + # prettier-ignore + test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:5000/api/v1/streaming/health || exit 1'] + ports: + - '127.0.0.1:5000:5000' + depends_on: + - mastodon_db + - mastodon_redis + + mastodon_sidekiq: + container_name: mastodon_sidekiq + build: . + image: tootsuite/mastodon + restart: always + env_file: .env.production + command: bundle exec sidekiq + depends_on: + - mastodon_db + - mastodon_redis + networks: + - mastodon + - nginx + volumes: + - ./public/system:/mastodon/public/system + healthcheck: + test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"] + + ## Uncomment to enable federation with tor instances along with adding the following ENV variables + ## http_proxy=http://privoxy:8118 + ## ALLOW_ACCESS_TO_HIDDEN_SERVICE=true + # tor: + # image: sirboops/tor + # networks: + # - external_network + # - internal_network + # + # privoxy: + # image: sirboops/privoxy + # volumes: + # - ./priv-config:/opt/config + # networks: + # - external_network + # - internal_network + +networks: + mastodon: + ipam: + driver: default + config: + - subnet: 172.42.0.0/16 + nginx: + external: true + diff --git a/roles/mastodon/files/mastodon-env b/roles/mastodon/files/mastodon-env new file mode 100644 index 0000000..f71f168 --- /dev/null +++ b/roles/mastodon/files/mastodon-env @@ -0,0 +1,84 @@ +# This is a sample configuration file. You can generate your configuration +# with the `rake mastodon:setup` interactive setup wizard, but to customize +# your setup even further, you'll need to edit it manually. This sample does +# not demonstrate all available configuration options. Please look at +# https://docs.joinmastodon.org/admin/config/ for the full documentation. + +# Note that this file accepts slightly different syntax depending on whether +# you are using `docker-compose` or not. In particular, if you use +# `docker-compose`, the value of each declared variable will be taken verbatim, +# including surrounding quotes. +# See: https://github.com/mastodon/mastodon/issues/16895 + +# Federation +# ---------- +# This identifies your server and cannot be changed safely later +# ---------- +LOCAL_DOMAIN=teh.entar.net +ALTERNATE_DOMAINS=entar.net,mastodon_web + +# Redis +# ----- +REDIS_HOST=mastodon_redis +REDIS_PORT=6379 + +# PostgreSQL +# ---------- +DB_HOST=mastodon_db +DB_USER=postgres +DB_NAME=mastodon_production +DB_PASS=letmein +DB_PORT=5432 + +POSTGRES_USER=postgres +POSTGRES_PASSWORD=letmein +POSTGRES_DB=mastodon_production + + +## Elasticsearch (optional) +## ------------------------ +#ES_ENABLED=true +#ES_HOST=localhost +#ES_PORT=9200 +## Authentication for ES (optional) +#ES_USER=elastic +#ES_PASS=password + +# Secrets +# ------- +# Make sure to use `rake secret` to generate secrets +# ------- +SECRET_KEY_BASE= +OTP_SECRET= + +# Web Push +# -------- +# Generate with `rake mastodon:webpush:generate_vapid_key` +# --------a +VAPID_PRIVATE_KEY= +VAPID_PUBLIC_KEY= + +# Sending mail +# ------------ +SMTP_SERVER=172.17.0.1 +SMTP_PORT=587 +SMTP_LOGIN= +SMTP_PASSWORD= +SMTP_FROM_ADDRESS=notifications@teh.entar.net + +## File storage (optional) +## ----------------------- +#S3_ENABLED=true +#S3_BUCKET=teh-entar-masto +#AWS_ACCESS_KEY_ID= +#AWS_SECRET_ACCESS_KEY= +#S3_ALIAS_HOST= + +# 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 + diff --git a/roles/mastodon/files/nginx.conf b/roles/mastodon/files/nginx.conf new file mode 100644 index 0000000..f68d59d --- /dev/null +++ b/roles/mastodon/files/nginx.conf @@ -0,0 +1,167 @@ +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +upstream backend { + server mastodon_web:3000 fail_timeout=0; +} + +upstream streaming { + server mastodon_streaming:5000 fail_timeout=0; +} + +proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g; + +server { + server_name teh.entar.net entar.net; + listen 80; + listen [::]:80; + root /srv/mastodon/live/public; + location /.well-known/acme-challenge/ { allow all; } + location / { return 301 https://$host$request_uri; } +} + +server { + server_name teh.entar.net entar.net; + listen 443 ssl http2; + listen [::]:443 ssl http2; + + # Uncomment these lines once you acquire a certificate: + # ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; + # ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; + ssl_trusted_certificate /etc/letsencrypt/live/www.poorsquinky.com/chain.pem; + ssl_certificate /etc/letsencrypt/live/www.poorsquinky.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/www.poorsquinky.com/privkey.pem; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; + ssl_prefer_server_ciphers off; + # In case of an old server with an OpenSSL version of 1.0.2 or below, + # leave only prime256v1 or comment out the following line. + ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1; + ssl_stapling on; + ssl_stapling_verify on; + + keepalive_timeout 70; + sendfile on; + client_max_body_size 80m; + + root /srv/mastodon/live/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 image/svg+xml image/x-icon; + + location / { + try_files $uri @proxy; + } + + # If Docker is used for deployment and Rails serves static files, + # then needed must replace line `try_files $uri =404;` with `try_files $uri @proxy;`. + location = sw.js { + add_header Cache-Control "public, max-age=604800, must-revalidate"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + try_files $uri =404; + } + + location ~ ^/assets/ { + add_header Cache-Control "public, max-age=2419200, must-revalidate"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + try_files $uri =404; + } + + location ~ ^/avatars/ { + add_header Cache-Control "public, max-age=2419200, must-revalidate"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + try_files $uri =404; + } + + location ~ ^/emoji/ { + add_header Cache-Control "public, max-age=2419200, must-revalidate"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + try_files $uri =404; + } + + location ~ ^/headers/ { + add_header Cache-Control "public, max-age=2419200, must-revalidate"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + try_files $uri =404; + } + + location ~ ^/packs/ { + add_header Cache-Control "public, max-age=2419200, must-revalidate"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + try_files $uri =404; + } + + location ~ ^/shortcuts/ { + add_header Cache-Control "public, max-age=2419200, must-revalidate"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + try_files $uri =404; + } + + location ~ ^/sounds/ { + add_header Cache-Control "public, max-age=2419200, must-revalidate"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + try_files $uri =404; + } + + location ~ ^/system/ { + add_header Cache-Control "public, max-age=2419200, immutable"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + try_files $uri =404; + } + + 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; + + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + + tcp_nodelay on; + } + + 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://mastodon_web:3000; + 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; + + tcp_nodelay on; + } + + error_page 404 500 501 502 503 504 /500.html; +} + diff --git a/roles/mastodon/tasks/main.yml b/roles/mastodon/tasks/main.yml new file mode 100644 index 0000000..4a72a5f --- /dev/null +++ b/roles/mastodon/tasks/main.yml @@ -0,0 +1,44 @@ +--- + +# https://docs.joinmastodon.org/admin/config/make + +# check out mastodon +- name: check out mastodon + git: + repo: https://github.com/mastodon/mastodon.git + version: v3.5.3 + dest: /srv/mastodon + update: no + register: mastodon_git + +# copy mastodon docker-compose +- name: masto docker-compose + copy: + src: files/docker-compose.yaml + dest: /srv/mastodon/docker-compose.yml + register: mastodon_docker_compose + +# mastodon env file +- name: masto env + copy: + src: files/mastodon-env + dest: /srv/mastodon/.env.production + register: mastodon_env + +# launch mastodon + +- name: nginx config + copy: + src: files/nginx.conf + dest: /srv/nginx/conf.d/teh.entar.net.conf + owner: netsrv + group: netsrv + mode: "0644" + register: entarnginx + +- name: restart nginx + command: docker restart nginx-www + when: entarnginx.changed + + +