diff options
Diffstat (limited to 'deploy')
-rw-r--r-- | deploy/.docker/nginx/nginx.conf | 207 | ||||
-rw-r--r-- | deploy/docker-compose.yml | 162 | ||||
-rwxr-xr-x | deploy/scripts/backup.sh | 18 | ||||
-rwxr-xr-x | deploy/scripts/update-containers.sh | 12 | ||||
-rwxr-xr-x | deploy/setup-mastodon.sh | 27 |
5 files changed, 426 insertions, 0 deletions
diff --git a/deploy/.docker/nginx/nginx.conf b/deploy/.docker/nginx/nginx.conf new file mode 100644 index 0000000..9326f6d --- /dev/null +++ b/deploy/.docker/nginx/nginx.conf @@ -0,0 +1,207 @@ +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +upstream netdatacontainer { + server netdata:19999; + keepalive 64; +} + +server { + listen 80; + listen [::]:80; + + server_name plural.cafe; + root /var/www/html; + + location /.well-known/acme-challenge/ { + allow all; + } + + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name ~^(?<subdomain>\w+)\.plural\.cafe$; + server_tokens off; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE+CHACHA20:AES256+EECDH:AES256+EDH:!aNULL; + ssl_prefer_server_ciphers on; + ssl_ecdh_curve secp521r1:secp384r1; + ssl_session_cache shared:TLS:2m; + ssl_session_timeout 10m; + ssl_session_tickets off; + ssl_stapling on; + ssl_stapling_verify on; + + resolver 8.8.8.8 8.8.4.4 [2001:4860:4860::8888] [2001:4860:4860::8844] valid=300s; + resolver_timeout 5s; + + ssl_dhparam /etc/ssl/dhparam.pem; + + keepalive_timeout 70; + sendfile on; + client_max_body_size 0; + + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header Referrer-Policy "same-origin"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; + + ssl_certificate /etc/ssl/fullchain.pem; + ssl_certificate_key /etc/ssl/privkey.pem; + ssl_trusted_certificate /etc/ssl/cert.pem; + + return 301 "https://plural.cafe/@${subdomain}"; +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name plural.cafe; + server_tokens off; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE+CHACHA20:AES256+EECDH:AES256+EDH:!aNULL; + ssl_prefer_server_ciphers on; + ssl_ecdh_curve secp521r1:secp384r1; + ssl_session_cache shared:TLS:2m; + ssl_session_timeout 10m; + ssl_session_tickets off; + ssl_stapling on; + ssl_stapling_verify on; + + resolver 8.8.8.8 8.8.4.4 [2001:4860:4860::8888] [2001:4860:4860::8844] valid=300s; + resolver_timeout 5s; + + ssl_dhparam /etc/ssl/dhparam.pem; + + keepalive_timeout 70; + sendfile on; + client_max_body_size 0; + + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header Referrer-Policy "same-origin"; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; + + ssl_certificate /etc/ssl/fullchain.pem; + ssl_certificate_key /etc/ssl/privkey.pem; + ssl_trusted_certificate /etc/ssl/cert.pem; + + root /var/www/html; + + #add_header Content-Security-Policy "Content-Security-Policy: frame-ancestors 'none'; object-src 'none'; script-src 'self'; base-uri 'none';"; + add_header Access-Control-Allow-Origin "https://$host"; + add_header X-Cache-Status $upstream_cache_status; + + location / { + try_files $uri @proxy; + } + + location /sw.js { + add_header Cache-Control "public, max-age=0"; + try_files $uri @proxy; + } + + + location = /sysinfo { + return 301 /sysinfo/; + } + + location ~ /sysinfo/(?<ndpath>.*) { + proxy_redirect off; + proxy_set_header Host $host; + + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_http_version 1.1; + proxy_pass_request_headers on; + proxy_set_header Connection "keep-alive"; + proxy_store off; + proxy_pass http://netdatacontainer/$ndpath$is_args$args; + + gzip on; + gzip_proxied any; + gzip_types *; + } + + location ~ ^/(emoji|packs|sounds) { + add_header Cache-Control "public, max-age=31536000, immutable"; + + 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; + + try_files $uri @proxy; + } + + location ~ ^/system/(?<req>(media_attachments|accounts|preview_cards)/.+) { + return 301 "https://d2rm2wyqhf92ej.cloudfront.net/$req"; + } + + 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://mstweb: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_use_stale error timeout updating http_500 http_502 http_503 http_504; + proxy_cache_lock on; + proxy_cache_revalidate on; + + 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://mststreaming: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 403 /assets/403.html; + error_page 404 /assets/404.html; + error_page 410 /assets/410.html; + error_page 422 /assets/422.html; + error_page 500 501 502 503 504 /assets/500.html; +} + +proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=2g use_temp_path=off; diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml new file mode 100644 index 0000000..b6de5fd --- /dev/null +++ b/deploy/docker-compose.yml @@ -0,0 +1,162 @@ +version: '3' +services: + + nginx: + restart: always + image: nginx:mainline + command: nginx -g 'daemon off;' + networks: + - external_network + - mstweb_network + - mststreaming_network + - netdata_network + volumes: + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + - ./.docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro + - ./.docker/nginx/dhparam.pem:/etc/ssl/dhparam.pem:ro + - ./.docker/nginx/certs/fullchain.pem:/etc/ssl/fullchain.pem:ro + - ./.docker/nginx/certs/privkey.pem:/etc/ssl/privkey.pem:ro + - ./.docker/nginx/certs/cert.pem:/etc/ssl/cert.pem:ro + - ./public:/var/www/html:ro + ports: + - "80:80" + - "443:443" + + netdata: + restart: always + image: titpetric/netdata + restart: unless-stopped + cap_add: + - SYS_PTRACE + volumes: + - ./.docker/netdata:/etc/netdata + - /proc:/host/proc:ro + - /sys:/host/sys:ro + - /var/run/docker.sock:/var/run/docker.sock + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + networks: + - netdata_network + + mstdb: + restart: always + image: postgres:9.6-alpine + networks: + - mstdb_network + volumes: + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + - ./.docker/mastodon/db:/var/lib/postgresql/data + + mstredis: + restart: always + image: redis:alpine + networks: + - mstredis_network + volumes: + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + - ./.docker/mastodon/redis:/data + +# mstes: +# restart: always +# image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.3 +# environment: +# - "ES_JAVA_OPTS=-Xms512m -Xmx512m" +# networks: +# - mstes_network +# volumes: +# - /etc/localtime:/etc/localtime:ro +# - /etc/timezone:/etc/timezone:ro +# - ./.docker/mastodon/es:/usr/share/elasticsearch/data + + mstweb: + image: pluralcafe/mastodon:stable + restart: always + env_file: ./.docker/mastodon/.env.production + command: bash -c "rake db:migrate; bundle exec rails s -p 3000 -b '0.0.0.0'" + networks: + - external_network + - mstdb_network + - mstredis_network + - mstweb_network + depends_on: + - mstdb + - mstredis +# - mstes + volumes: + - ./public/system:/mastodon/public/system + - ./public/assets:/tmp/assets + - ./public/packs:/tmp/packs + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + + mststreaming: + image: pluralcafe/mastodon:stable + restart: always + env_file: ./.docker/mastodon/.env.production + command: yarn start + networks: + - mstdb_network + - mstredis_network + - mststreaming_network + depends_on: + - mstdb + - mstredis + volumes: + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + + mstsidekiq: + image: pluralcafe/mastodon:stable + restart: always + env_file: ./.docker/mastodon/.env.production + command: bundle exec sidekiq -q default -q mailers -q pull -q push + depends_on: + - mstdb + - mstredis + networks: + - external_network + - mstdb_network + - mstredis_network + - mstweb_network + - mststreaming_network + volumes: + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + - ./public/system:/mastodon/public/system + +# mrxsynapse: +# image: avhost/docker-matrix:latest +# restart: always +# command: start +# environment: +# - SERVER_NAME=plural.cafe +# - REPORT_STATS=yes +# - MATRIX_UID=981 +# - MATRIX_GID=981 +# networks: +# - mrxsynapse_network +# - mrxdb_network +# - external_network +# ports: +# - "8448:8448" +# - "3478:3478" +# volumes: +# - /etc/localtime:/etc/localtime:ro +# - /etc/timezone:/etc/timezone:ro +# - ./.docker/matrix:/data + +networks: + external_network: + mstdb_network: + internal: true + mstredis_network: + internal: true + mststreaming_network: + internal: true + mstweb_network: + internal: true + netdata_network: + internal: true diff --git a/deploy/scripts/backup.sh b/deploy/scripts/backup.sh new file mode 100755 index 0000000..b9a4b06 --- /dev/null +++ b/deploy/scripts/backup.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +[ -z "$COMPOSE" ] && COMPOSE="$(command -v docker-compose)" +[ -z "$COMPOSE" ] && COMPOSE="/usr/local/bin/docker-compose" +[ -z "$YML_LOC" ] && YML_LOC="$HOME/docker-compose.yml" + +COMPOSE="$COMPOSE -f $YML_LOC" + +if [ "$1" == 'daily' ]; then + find $HOME/backups -type f -name postgres-daily.* -mtime +7 -delete + $COMPOSE exec -T -u postgres mstdb sh -c "umask 0377 && /usr/local/bin/pg_dump -Fc -h mstdb -d postgres -U postgres" > "$HOME/backups/postgres-daily.$(date -Iseconds).pgsql" + $COMPOSE run -T --rm web rake mastodon:media:remove_remote +fi + +if [ "$1" == 'hourly' ]; then + find $HOME/backups -type f -name postgres-hourly.* -mmin +360 -delete + $COMPOSE exec -T -u postgres mstdb sh -c "umask 0377 && /usr/local/bin/pg_dump -Fc -h mstdb -d postgres -U postgres" > "$HOME/backups/postgres-hourly.$(date -Iseconds).pgsql" +fi diff --git a/deploy/scripts/update-containers.sh b/deploy/scripts/update-containers.sh new file mode 100755 index 0000000..ff63e9e --- /dev/null +++ b/deploy/scripts/update-containers.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +[ -z "$COMPOSE" ] && COMPOSE="$(command -v docker-compose)" +[ -z "$COMPOSE" ] && COMPOSE="/usr/local/bin/docker-compose" + +cd $HOME + +($COMPOSE pull 2>&1 | grep --silent "Downloaded newer") && \ + $COMPOSE up -d && \ + docker cp $($COMPOSE ps -q mstweb):/mastodon/public/assets public/ && \ + docker cp $($COMPOSE ps -q mstweb):/mastodon/public/packs public/ && \ + docker image prune -f diff --git a/deploy/setup-mastodon.sh b/deploy/setup-mastodon.sh new file mode 100755 index 0000000..14ae9af --- /dev/null +++ b/deploy/setup-mastodon.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +[ -z "$YML_LOC" ] && YML_LOC="$HOME" +cd $YML_LOC + +echo "Setting up the instance..." +echo + +curl -fsSL https://raw.githubusercontent.com/tootsuite/mastodon/master/.env.production.sample -o "$YML_LOC/.docker/mastodon/.env.production" + +MUID="$(docker-compose run --rm mstweb id -u 2>/dev/null)" +SECRET_KEY_BASE=$(hexdump -vn 64 -e ' /1 "%02x"' /dev/urandom) +OTP_SECRET=$(hexdump -vn 64 -e ' /1 "%02x"' /dev/urandom) + +sed -i 's|REDIS_HOST=redis|REDIS_HOST=mstredis|' $YML_LOC/.docker/mastodon/.env.production +sed -i 's|DB_HOST=db|DB_HOST=mstdb|' $YML_LOC/.docker/mastodon/.env.production +sed -i 's|ES_HOST=es|ES_HOST=mstes|' $YML_LOC/.docker/mastodon/.env.production +sed -i "s|SECRET_KEY_BASE=|SECRET_KEY_BASE=$SECRET_KEY_BASE|" $YML_LOC/.docker/mastodon/.env.production +sed -i "s|OTP_SECRET=|OTP_SECRET=$OTP_SECRET|" $YML_LOC/.docker/mastodon/.env.production + +docker-compose run --rm mstweb rake db:migrate +(openssl dhparam -rand /dev/urandom -out $YML_LOC/.docker/nginx/dhparam.pem 4096 2>&1 >/dev/null) & pid=$! + +echo +echo "Mostly set up. Modify .docker/mastodon/.env.production settings and then" +echo "you can do a 'docker-compose up -d' on this instance. OpenSSL is still" +echo "running, so wait a bit for it to finish too." |