diff --git a/README.md b/README.md index b6e64f1..996c1c4 100644 --- a/README.md +++ b/README.md @@ -356,6 +356,13 @@ end (indentation is ignored) +## Running a Server + +If you want to run an online renderer (like +[https://sequence.davidje13.com/](https://sequence.davidje13.com/)), +take a look at +[ubuntu-nginx-installer.sh](docs/ubuntu-nginx-installer.sh). + ## Contributing Contributions are welcome! diff --git a/docs/ubuntu-nginx-installer.sh b/docs/ubuntu-nginx-installer.sh new file mode 100644 index 0000000..7c24b9b --- /dev/null +++ b/docs/ubuntu-nginx-installer.sh @@ -0,0 +1,368 @@ +# This script was used to build sequence.davidje13.com + +# It will install the sequence diagram code (and necessary environment) +# and install an nginx proxy server. It will also use the "let's encrypt" +# service to get SSH keys for the site. +# Security updates will be applied automatically. Other updates can be +# applied by running: + +# sudo apt-get update; +# sudo apt-get dist-upgrade; +# sudo shutdown -r now; # if needed +# sudo apt-get autoremove; + +# The github code can be updated by running: +# sudo /var/www/sequence/update.sh + +# The AWS configuration used: + +# EC2: +# Community AMI: ami-0b91bd72, T2.micro, 8GB (only uses ~2GB but this is the minimum) +# Use a security group which allows 80 (public), 443 (public) and 22 (your ip) +# (assign elastic IP) + +# Route53: +# A (1day) +# A www. (1day) +# A sequence. (1day) +# CAA 0 issue "letsencrypt.org" (1day) + +# Once the EC2 & Route53 config is done, log in to the box and run this script. +# Pass a single parameter: the main domain name (e.g. davidje13.com) + +# You can easily download this script to the box by running: +# wget https://davidje13.github.io/SequenceDiagram/docs/ubuntu-nginx-installer.sh; +# chmod 0744 ubuntu-nginx-installer.sh; +# ./ubuntu-nginx-installer.sh + +# thanks, +# https://gist.github.com/nrollr/9a39bb636a820fb97eec2ed85e473d38 +# https://bjornjohansen.no/redirect-to-https-with-nginx +# http://tumblr.intranation.com/post/766288369/using-nginx-reverse-proxy +# https://certbot.eff.org/ +# https://help.ubuntu.com/lts/serverguide/automatic-updates.html +# https://cloud-images.ubuntu.com/locator/ec2/ +# https://gist.github.com/alonisser/a2c19f5362c2091ac1e7 +# https://www.freedesktop.org/software/systemd/man/systemd.service.html + +set -ex + +DOMAIN="$1"; + +if [[ -z "$DOMAIN" ]]; then + echo "Must specify domain!"; + exit 1; +fi; + +echo 'iptables-persistent iptables-persistent/autosave_v4 boolean true' | sudo debconf-set-selections; +echo 'iptables-persistent iptables-persistent/autosave_v6 boolean true' | sudo debconf-set-selections; + +sudo tee -a /etc/apt/apt.conf.d/20auto-upgrades <<'EOF' > /dev/null; +APT::Periodic::Download-Upgradeable-Packages "1"; +APT::Periodic::AutocleanInterval "7"; +EOF + +sudo tee -a /etc/apt/apt.conf.d/50unattended-upgrades <<'EOF' > /dev/null; +Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; +Unattended-Upgrade::Remove-Unused-Dependencies "true"; +Unattended-Upgrade::Automatic-Reboot "true"; +EOF + +sudo add-apt-repository ppa:certbot/certbot -y; +sudo apt-get update; +sudo apt-get dist-upgrade -y; + +sudo apt-get install -y \ + iptables-persistent \ + daemontools \ + certbot \ + nodejs \ + npm \ + nginx; +sudo systemctl stop nginx; + +sudo useradd --system --user-group --password '' sequence-runner; + +sudo mkdir -p /var/www/http/.well-known/acme-challenge; +sudo mkdir -p /var/www/https; + +git clone https://github.com/davidje13/SequenceDiagram.git; +cd SequenceDiagram && npm install --production; cd - > /dev/null; +sudo mv SequenceDiagram /var/www/sequence; +sudo mkdir -p /var/www/sequence/logs; + +sudo tee /var/www/sequence/runner.sh <<'EOF' > /dev/null; +#!/bin/bash +BASEDIR="$(dirname "$0")"; +PORT="$1"; + +mkdir -p "$BASEDIR/logs/log$PORT"; + +FONTDIR="$BASEDIR/fonts" \ +"$BASEDIR/bin/server.js" "$PORT" 2>&1 \ + > >(multilog n50 s1048576 "$BASEDIR/logs/log$PORT") & + +echo $! > "$BASEDIR/logs/pid$PORT"; +EOF + +sudo tee /var/www/sequence/update.sh <<'EOF' > /dev/null; +#!/bin/bash +BASEDIR="$(dirname "$0")"; + +cd "$BASEDIR"; +git pull; +cd - > /dev/null; +chmod -R g-w "$BASEDIR"; +systemctl restart sequence8080.service; +systemctl restart sequence8081.service; +EOF + +sudo tee /var/www/https/index.htm < /dev/null; + + +$DOMAIN + + + +Nothing to see here… +try https://sequence.$DOMAIN/ instead for now. + + +EOF + +sudo chmod 0544 /var/www/sequence/runner.sh; +sudo chmod 0744 /var/www/sequence/update.sh; + +sudo chmod -R g-w /var/www/sequence; +sudo chown -R root:sequence-runner /var/www/sequence; +sudo chown -R sequence-runner:sequence-runner /var/www/sequence/logs; +sudo chown sequence-runner:sequence-runner /var/www/sequence/runner.sh; +sudo chown -R root:www-data /var/www/http; +sudo chown -R root:www-data /var/www/https; + + +openssl dhparam -out dhparam.pem 2048; +sudo mv dhparam.pem /etc/nginx/dhparam.pem; +sudo chmod 0600 /etc/nginx/dhparam.pem; +sudo chown root:root /etc/nginx/dhparam.pem; + + +sudo rm /etc/nginx/modules-enabled/50-mod-http-geoip.conf; +sudo rm /etc/nginx/modules-enabled/50-mod-http-image-filter.conf; +sudo rm /etc/nginx/modules-enabled/50-mod-http-xslt-filter.conf; +sudo rm /etc/nginx/modules-enabled/50-mod-mail.conf; +# should be mod-stream remaining +sudo rm /etc/nginx/sites-enabled/default; + +sudo tee /etc/nginx/nginx.conf < /dev/null; +user www-data; +worker_processes auto; +pid /run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; + +events { + worker_connections 768; +} + +http { + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} +EOF + +sudo tee /etc/nginx/conf.d/custom.conf < /dev/null; +server_tokens off; +resolver 8.8.8.8 8.8.4.4 valid=300s; +resolver_timeout 5s; +EOF + +sudo tee /etc/nginx/conf.d/mime.conf < /dev/null; +types { + application/javascript mjs; +} +EOF + +sudo tee /etc/nginx/sites-available/shared-ssl.inc < /dev/null; +ssl on; +ssl_session_cache shared:SSL:5m; +ssl_protocols TLSv1 TLSv1.1 TLSv1.2; +ssl_prefer_server_ciphers on; +ssl_dhparam /etc/nginx/dhparam.pem; +ssl_certificate /etc/letsencrypt/live/all/fullchain.pem; +ssl_certificate_key /etc/letsencrypt/live/all/privkey.pem; +ssl_stapling on; +ssl_stapling_verify on; +ssl_trusted_certificate /etc/letsencrypt/live/all/fullchain.pem; +EOF + +sudo tee /etc/nginx/sites-available/http < /dev/null; +server { + listen 8000 default_server; + listen [::]:8000 default_server; + root /var/www/http; + + keepalive_requests 1; + keepalive_timeout 0s; + + client_header_timeout 5s; + client_body_timeout 5s; + client_max_body_size 1; + + location / { + access_log off; + expires max; + return 301 https://\$host\$request_uri; + } + + location /.well-known/acme-challenge/ { + } +} +EOF + +sudo tee /etc/nginx/sites-available/root < /dev/null; +server { + server_name $DOMAIN www.$DOMAIN; + listen 8443 ssl http2; + listen [::]:8443 ssl http2; +# listen 8000 +# listen [::]:8000 + root /var/www/https; + include /etc/nginx/sites-available/shared-ssl.inc; + + index index.htm index.html; + + client_header_timeout 5s; + client_body_timeout 5s; + client_max_body_size 1; + + gzip on; + gzip_comp_level 4; + gzip_types *; + + location /errors/ { + internal; + } + + error_page 404 /errors/404.htm; +} +EOF + +sudo tee /etc/nginx/sites-available/sequence < /dev/null; +upstream sequence_backend { + server 127.0.0.1:8080 max_conns=64; + server 127.0.0.1:8081 max_conns=64; + keepalive 16; +} + +server { + server_name sequence.$DOMAIN; + listen 8443 ssl http2; + listen [::]:8443 ssl http2; +# listen 8000 +# listen [::]:8000 + include /etc/nginx/sites-available/shared-ssl.inc; + + client_header_timeout 5s; + client_body_timeout 5s; + client_max_body_size 1; + + access_log off; + error_log off; + + merge_slashes off; + + location / { + proxy_pass http://sequence_backend; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_redirect off; + proxy_buffering off; + proxy_connect_timeout 5s; + proxy_read_timeout 10s; + } +} +EOF + +sudo ln -s /etc/nginx/sites-available/http /etc/nginx/sites-enabled/http; +sudo systemctl start nginx; + +sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8000; +sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443; +sudo ip6tables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8000; +sudo ip6tables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443; + +sudo certbot certonly --agree-tos --register-unsafely-without-email --cert-name all --webroot \ + -w /var/www/http \ + -d "$DOMAIN" \ + -d "www.$DOMAIN" \ + -d "sequence.$DOMAIN"; + +make_sequence_service() { + PORT="$1"; + sudo tee "/lib/systemd/system/sequence$PORT.service" < /dev/null; +[Unit] +Description=Sequence Diagram Server $PORT +After=network.target + +[Service] +Type=forking +PIDFile=/var/www/sequence/logs/pid$PORT +User=sequence-runner +ExecStart=/var/www/sequence/runner.sh $PORT +KillMode=process +KillSignal=SIGINT +Restart=always + +[Install] +WantedBy=multi-user.target +EOF + + sudo chmod 0644 "/lib/systemd/system/sequence$PORT.service"; + sudo systemctl enable "sequence$PORT.service"; +} + +make_sequence_service 8080; +make_sequence_service 8081; +sudo systemctl start sequence8080.service; +sudo systemctl start sequence8081.service; + +sudo ln -s /etc/nginx/sites-available/root /etc/nginx/sites-enabled/root; +sudo ln -s /etc/nginx/sites-available/sequence /etc/nginx/sites-enabled/sequence; +sudo nginx -s reload; + +sudo iptables-save | sudo tee /etc/iptables/rules.v4 > /dev/null; +sudo ip6tables-save | sudo tee /etc/iptables/rules.v6 > /dev/null; + +sudo rm /etc/cron.d/certbot; +sudo tee /etc/cron.daily/certbot-renew <<'EOF' > /dev/null; +certbot renew -q --deploy-hook "nginx -s reload"; +EOF +sudo chmod 0755 /etc/cron.daily/certbot-renew;