Init mastodon.pub.solar

This commit is contained in:
teutat3s 2022-06-04 20:46:19 +02:00
parent fbf5a80b6d
commit 0d1fef2a16
Signed by: teutat3s
GPG key ID: 4FA1D3FA524F22C1
7 changed files with 494 additions and 0 deletions

2
mastodon/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*.sql
.env.production

58
mastodon/README.md Normal file
View file

@ -0,0 +1,58 @@
# pub.solar mastodon
https://mastodon.pub.solar
### Upgrading
This section assumes you edited `docker-compose.yml` and bumped the mastodon docker
image version tag
```
# check current trailing number of mastodon containers
# current_container_index
docker ps | grep -E "sidekiq|streaming|web"
# make a DB backup and copy it to your local machine
docker exec -it matrix-postgres bash
# in shell in matrix-postgres container:
pg_dump -U mastodon -d mastodon_production -W -f /root/mastodon_db_backup-$(date +%F).sql
exit
# copy backup to local machine
docker cp matrix-postgres:/root/mastodon_db_backup-$(date +%F).sql .
# download new mastodon docker images
docker-compose --project-name blue-mastodon pull
# run pre-update migrations
docker-compose run \
--rm \
-e SKIP_POST_DEPLOYMENT_MIGRATIONS=true \
web \
rails db:migrate
# create new containers with new mastodon version
docker-compose --project-name blue-mastodon up \
--detach \
--scale web=2 \
--scale streaming=2 \
--scale sidekiq=2 \
--no-recreate
# stop containers with old mastodon version
docker stop \
blue-mastodon_web_($current_container_index - 1) \
blue-mastodon_streaming_($current_container_index - 1) \
blue-mastodon_sidekiq_($current_container_index - 1)
# run post-deployment migrations
docker-compose run --rm web rails db:migrate
# clean up containers with old mastodon version
docker rm \
blue-mastodon_web_($current_container_index - 1) \
blue-mastodon_streaming_($current_container_index - 1) \
blue-mastodon_sidekiq_($current_container_index - 1)
```
Todos:
- implement automatic backups, they are only done manually during upgrades at the moment
- switch proxy from nginx-dehydrated to caddy - done

View file

184
mastodon/docker-compose.yml Normal file
View file

@ -0,0 +1,184 @@
version: "2.4"
services:
# we're using matrix-postgres as DB
#db:
# restart: always
# image: postgres:14-alpine
# shm_size: 256mb
# networks:
# - mastodon-fabric
# Experimentally replaced by caddy
#nginx:
# image: hub.greenbaum.cloud/nginx-dehydrated:1.19-alpine
# mem_limit: 256m
# restart: always
# environment:
# - LETSENCRYPT_DOMAIN=mastodon.pub.solar
# - UPSTREAM_NAME=mastodon
# - UPSTREAM_CNS_BASE_DOMAIN=svc.e5756d08-36fd-424b-f8bc-acdb92ca7b82.cgn-1.int.greenbaum.zone
# - UPSTREAM_PORT=3000
# network_mode: mastodon-fabric
# ports:
# - 80
# - 443
# labels:
# - triton.cns.services=mastodon-proxy
caddy:
image: caddy:2.5.1
mem_limit: 256m
restart: always
environment:
- SITE_DOMAIN=mastodon.pub.solar
- UPSTREAM_APP_DOMAIN=mastodon-web.svc.e5756d08-36fd-424b-f8bc-acdb92ca7b82.cgn-1.int.greenbaum.zone
- UPSTREAM_STREAMING_DOMAIN=mastodon-streaming.svc.e5756d08-36fd-424b-f8bc-acdb92ca7b82.cgn-1.int.greenbaum.zone
- UPSTREAM_APP_PORT=3000
- UPSTREAM_STREAMING_PORT=4000
network_mode: mastodon-fabric
ports:
- 80
- 443
labels:
- triton.cns.services=mastodon-proxy
entrypoint: /bin/sh
command: >-
-c 'echo "
{
email admins@pub.solar
}
$$SITE_DOMAIN {
@streaming {
path /api/v1/streaming/*
}
@cache_control {
path_regexp ^/(emoji|packs|/system/accounts/avatars|/system/media_attachments/files)
}
log {
output stderr
}
handle /.well-known/keybase.txt {
root * /srv
file_server
}
reverse_proxy @streaming {
to http://$$UPSTREAM_STREAMING_DOMAIN:$$UPSTREAM_STREAMING_PORT
}
reverse_proxy {
to http://$$UPSTREAM_APP_DOMAIN:$$UPSTREAM_APP_PORT
}
handle_errors {
rewrite 500.html
}
encode zstd gzip
header {
Strict-Transport-Security "max-age=31536000"
}
header /sw.js Cache-Control "public, max-age=0"
header @cache_control Cache-Control "public, max-age=31536000, immutable"
}
files.pub.solar {
handle {
rewrite * /s/jw24ad6l4a6zxsnd32cmf5hp5nsq/pub-solar-mastodon{uri}?download
reverse_proxy {
# backends / upstreams
to https://link.tardigradeshare.io
# header manipulation
# proxy to an HTTPS endpoint
header_up Host {upstream_hostport}
# copied from mastodon docs for nginx with s3 for files
header_up Connection ""
header_up Authorization ""
# remove these header from the backends response
header_down -content-disposition
header_down -Set-Cookie
header_down -Access-Control-Allow-Origin
header_down -Access-Control-Allow-Methods
header_down -Access-Control-Allow-Headers
header_down -x-amz-id-2
header_down -x-amz-request-id
header_down -x-amz-meta-server-side-encryption
header_down -x-amz-server-side-encryption
header_down -x-amz-bucket-region
header_down -x-amzn-requestid
# add these header to the backends response
# cache client side for 7 days
header_down Cache-Control "public, max-age=604800"
}
}
handle_errors {
rewrite 500.html
}
}
" | caddy run --adapter caddyfile --config -'
# using SmartOS native zone mastodon-redis, lx-brand redis crashes regularly,
# upstream bug: https://github.com/redis/redis/issues/8861
# redis:
# image: redis:6.2-alpine
# mem_limit: 512m
# restart: always
# network_mode: mastodon-fabric
# labels:
# - triton.cns.services=mastodon-redis
web:
image: tootsuite/mastodon:v3.5.3
mem_limit: 1g
restart: always
env_file: .env.production
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
network_mode: mastodon-fabric
# see redis service comment
#depends_on:
# - redis
labels:
- triton.cns.services=mastodon-web
streaming:
image: tootsuite/mastodon:v3.5.3
mem_limit: 1g
restart: always
env_file: .env.production
command: node ./streaming
network_mode: mastodon-fabric
# see redis service comment
#depends_on:
# - redis
labels:
- triton.cns.services=mastodon-streaming
sidekiq:
image: tootsuite/mastodon:v3.5.3
mem_limit: 1g
restart: always
env_file: .env.production
command: bundle exec sidekiq
network_mode: mastodon-fabric
labels:
- triton.cns.services=mastodon-sidekiq
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2
mem_limit: 512m
restart: always
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- "cluster.name=es-mastodon"
- "discovery.type=single-node"
- "bootstrap.memory_lock=true"
network_mode: mastodon-fabric
labels:
- triton.cns.services=mastodon-elasticsearch
ulimits:
memlock:
soft: -1
hard: -1

View file

@ -0,0 +1,56 @@
==================================================================
https://keybase.io/teutat3s
--------------------------------------------------------------------
I hereby claim:
* I am an admin of https://mastodon.pub.solar
* I am teutat3s (https://keybase.io/teutat3s) on keybase.
* I have a public key ASCk3wTzXKHXwHUoTzp0MOjVgNx3qrRAx21X_rjzqTZJFQo
To do so, I am signing this object:
{
"body": {
"key": {
"eldest_kid": "0120a4df04f35ca1d7c075284f3a7430e8d580dc77aab440c76d57feb8f3a93649150a",
"host": "keybase.io",
"kid": "0120a4df04f35ca1d7c075284f3a7430e8d580dc77aab440c76d57feb8f3a93649150a",
"uid": "5d555cc40616a706ec189ddd24b35019",
"username": "teutat3s"
},
"merkle_root": {
"ctime": 1618093923,
"hash": "0aa5f6178ad671eda21e4e198202f4ab7f4fefff87760df4da17c78fdaf299ecdf0ae6d8858389123fe360416a4a9471bb4de5cdade3a068bed6a1bf377e76de",
"hash_meta": "883b0d6b47df62fc1566dd8671aac8a34bb93fa7e2d41e8e38bec4f5e19b3721",
"seqno": 19597808
},
"service": {
"entropy": "gopmQPbYzUUJHhnB0+YaTF45",
"hostname": "mastodon.pub.solar",
"protocol": "https:"
},
"type": "web_service_binding",
"version": 2
},
"client": {
"name": "keybase.io go client",
"version": "5.6.1"
},
"ctime": 1618093946,
"expire_in": 504576000,
"prev": "ecc6e3707d269e8fd62ea94d1ee7330fd15206ae3e6d14946c2f2a4b8f12c535",
"seqno": 28,
"tag": "signature"
}
which yields the signature:
hKRib2R5hqhkZXRhY2hlZMOpaGFzaF90eXBlCqNrZXnEIwEgpN8E81yh18B1KE86dDDo1YDcd6q0QMdtV/6486k2SRUKp3BheWxvYWTESpcCHMQg7MbjcH0mno/WLqlNHuczD9FSBq4+bRSUbC8qS48SxTXEIJd2HskvMapYSjPnoSSaFz9MJALBipX25kyi5bMvU+yUAgHCo3NpZ8RA+CMgOYpqqk/K0x7tgsH810Qvjxvs8FJbdCQ3SwAiFZ9v323TzWnFxuq1qbl5fAvQq6RInKYpPNALxD0c42miAahzaWdfdHlwZSCkaGFzaIKkdHlwZQildmFsdWXEIOyhPREWh9nbN6VTbOXs1YJofwkachECGbSqLa/aoyuWo3RhZ80CAqd2ZXJzaW9uAQ==
And finally, I am proving ownership of this host by posting or
appending to this document.
View my publicly-auditable identity here: https://keybase.io/teutat3s
==================================================================

View file

@ -0,0 +1,117 @@
upstream ${UPSTREAM_NAME} {
server mastodon-web.${UPSTREAM_CNS_BASE_DOMAIN}:${UPSTREAM_PORT};
}
upstream streaming {
server mastodon-streaming.${UPSTREAM_CNS_BASE_DOMAIN}:4000 fail_timeout=0;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g;
# generated 2021-02-28, Mozilla Guideline v5.6, nginx 1.19, OpenSSL 1.1.1d, modern configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.19&config=modern&openssl=1.1.1d&guideline=5.6
server {
listen 80 default_server;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
ssl_certificate /data/dehydrated/certs/${LETSENCRYPT_DOMAIN}/fullchain.pem;
ssl_certificate_key /data/dehydrated/certs/${LETSENCRYPT_DOMAIN}/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
# modern configuration
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /data/dehydrated/certs/${LETSENCRYPT_DOMAIN}/fullchain.pem;
# replace with the IP address of your resolver
resolver 85.88.23.13 85.88.23.14 85.88.1.92;
keepalive_timeout 70;
sendfile on;
client_max_body_size 80m;
location /.well-known/keybase.txt {
root /var/www/html;
}
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";
try_files $uri @proxy;
}
location /sw.js {
add_header Cache-Control "public, max-age=0";
add_header Strict-Transport-Security "max-age=31536000";
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://${UPSTREAM_NAME};
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";
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;
}

View file

@ -0,0 +1,77 @@
server {
listen 443 ssl http2;
server_name files.pub.solar;
ssl_certificate /data/dehydrated/certs/files.pub.solar/fullchain.pem;
ssl_certificate_key /data/dehydrated/certs/files.pub.solar/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
# modern configuration
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /data/dehydrated/certs/files.pub.solar/fullchain.pem;
root /var/www/files;
keepalive_timeout 30;
location = / {
index index.html;
}
location / {
try_files $uri @s3;
}
set $s3_backend 'https://link.tardigradeshare.io/s/jw24ad6l4a6zxsnd32cmf5hp5nsq/pub-solar-mastodon';
location @s3 {
limit_except GET {
deny all;
}
resolver 85.88.23.13 85.88.23.14 85.88.1.92;
proxy_set_header Host link.tardigradeshare.io;
proxy_set_header Connection '';
proxy_set_header Authorization '';
proxy_hide_header content-disposition;
proxy_hide_header Set-Cookie;
proxy_hide_header 'Access-Control-Allow-Origin';
proxy_hide_header 'Access-Control-Allow-Methods';
proxy_hide_header 'Access-Control-Allow-Headers';
proxy_hide_header x-amz-id-2;
proxy_hide_header x-amz-request-id;
proxy_hide_header x-amz-meta-server-side-encryption;
proxy_hide_header x-amz-server-side-encryption;
proxy_hide_header x-amz-bucket-region;
proxy_hide_header x-amzn-requestid;
proxy_ignore_headers Set-Cookie;
proxy_pass $s3_backend$uri?download;
proxy_intercept_errors off;
proxy_cache CACHE;
proxy_cache_valid 200 48h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
expires 1y;
add_header Cache-Control public;
add_header 'Access-Control-Allow-Origin' '*';
add_header X-Cache-Status $upstream_cache_status;
add_header Content-Disposition 'inline';
}
}