about summary refs log tree commit diff
path: root/deploy
diff options
context:
space:
mode:
Diffstat (limited to 'deploy')
-rw-r--r--deploy/.docker/nginx/nginx.conf207
-rw-r--r--deploy/docker-compose.yml162
-rwxr-xr-xdeploy/scripts/backup.sh18
-rwxr-xr-xdeploy/scripts/update-containers.sh12
-rwxr-xr-xdeploy/setup-mastodon.sh27
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."