#!/bin/bash positional_args=() original_args="${@@Q}" while [[ $# -gt 0 ]]; do case $1 in --domain) domain="$2" shift # past argument shift # past value ;; --upstream-server) upstream_server="$2" shift # past argument shift # past value ;; --upstream-base) upstream_base="$2" shift # past argument shift # past value ;; --target-server) target_server="$2" shift # past argument shift # past value ;; --acme-email) acme_email="$2" shift # past argument shift # past value ;; --is-in-target) is_in_target=1 shift # past argument ;; --pass-header) pass_headers="$pass_headers proxy_set_header $2 '$3';" shift # past argument shift # past value shift # past value ;; -*|--*) echo "Unknown option $1" exit 1 ;; *) positional_args+=("$1") # save positional arg shift # past argument ;; esac done set -- "${positional_args[@]}" # restore positional parameters # check if self is in target server if [ -z "$is_in_target" ]; then # we're still in the user's pc # make sure we have all the required arguments if [ -z "$domain" ] \ || [ -z "$upstream_server" ] \ || [ -z "$acme_email" ] \ || [ -z "$target_server" ]; then echo "Usage: $0 --domain --upstream-server --upstream-base --acme-email --target-server [--pass-header Header Value]" exit 1 fi target_filename=$(mktemp -u) echo "Copying self to target server..." scp $0 $target_server:$target_filename echo "Executing setup script on target server..." ssh $target_server "$target_filename --is-in-target $original_args" # exit exit 0 fi # we're now on the target server # make sure we're root if [ "$(id -u)" != "0" ]; then echo "This script must be run as root" exit 1 fi echo "Installing dependencies..." cat < /etc/apt/sources.list.d/nginx.list deb https://nginx.org/packages/ubuntu/ focal nginx deb-src https://nginx.org/packages/ubuntu/ focal nginx EOF while fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do echo "Waiting for dpkg lock to be free..." sleep 0.5 done apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ABF5BD827BD9BF62 && \ apt-get update && \ apt-get upgrade -y && \ apt-get install -y nginx socat # Fix firewall if command -v ufw >/dev/null 2>&1; then echo "Adding firewall rules..." ufw allow http ufw allow https fi echo "Downloading acme.sh..." wget -O - https://get.acme.sh | sh -s email=$acme_email echo "Issuing certificate..." systemctl stop nginx ~/.acme.sh/acme.sh --issue -d $domain --server letsencrypt --standalone systemctl start nginx ~/.acme.sh/acme.sh --install-cert -d $domain \ --cert-file /etc/nginx/ssl.crt \ --key-file /etc/nginx/ssl.key \ --fullchain-file /etc/nginx/ssl.pem \ --reloadcmd "systemctl reload nginx" # create directories mkdir -p /var/cache/nginx/proxy_cache # create the nginx config file echo "Setting up nginx" cat < /etc/nginx/cors.conf proxy_hide_header 'Access-Control-Allow-Origin'; proxy_hide_header 'Access-Control-Allow-Methods'; proxy_hide_header 'Access-Control-Allow-Headers'; proxy_hide_header 'Access-Control-Expose-Headers'; if (\$request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'HEAD, GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } if (\$request_method = 'POST') { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, HEAD, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; } if (\$request_method = 'GET') { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, HEAD, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; } if (\$request_method = 'HEAD') { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, HEAD, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; } EOF cat < /etc/nginx/nginx.conf user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 1048576; multi_accept on; use epoll; } http { # Basic settings sendfile on; tcp_nopush on; tcp_nodelay on; server_tokens off; keepalive_timeout 300s; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; # SSL settings ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; # Logging Settings access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; # DNS resolver resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off; resolver_timeout 10s; # Proxy cache proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2 keys_zone=restream_cache:10m inactive=10m max_size=20g; server { listen 80; listen [::]:80; server_name $domain; return 301 https://\$server_name\$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; server_name $domain; # SSL settings ssl_certificate /etc/nginx/ssl.crt; ssl_certificate_key /etc/nginx/ssl.key; proxy_redirect off; proxy_http_version 1.1; proxy_read_timeout 10s; proxy_send_timeout 10s; proxy_connect_timeout 10s; proxy_cache restream_cache; proxy_cache_methods GET HEAD; proxy_cache_key \$uri; proxy_cache_valid 200 302 5m; proxy_cache_valid 404 3s; proxy_cache_lock on; proxy_cache_lock_age 5s; proxy_cache_lock_timeout 1h; proxy_ignore_headers Cache-Control; proxy_ignore_headers Set-Cookie; add_header X-Edge-Cache-Status \$upstream_cache_status; location / { include /etc/nginx/cors.conf; $pass_headers proxy_ssl_server_name on; rewrite ^(.*)$ $upstream_base\$1 break; proxy_pass $upstream_server; location ~ \.(m3u8|mpd)$ { include /etc/nginx/cors.conf; rewrite ^(.*)$ $upstream_base\$1 break; proxy_cache_valid any 1s; proxy_pass $upstream_server; } } } } EOF nginx -t systemctl reload nginx # sysctl settings echo "Configuring sysctl" cat < /etc/sysctl.d/999-perf.conf fs.file-max=1048576 fs.inotify.max_user_instances=1048576 fs.inotify.max_user_watches=1048576 fs.nr_open=1048576 net.core.default_qdisc=fq net.core.netdev_max_backlog=1048576 net.core.rmem_max=16777216 net.core.somaxconn=65535 net.core.wmem_max=16777216 net.ipv4.ip_local_port_range=1024 65535 net.ipv4.netfilter.ip_conntrack_max=1048576 net.ipv4.tcp_fin_timeout=5 net.ipv4.tcp_max_orphans=1048576 net.ipv4.tcp_max_syn_backlog=20480 net.ipv4.tcp_max_tw_buckets=400000 net.ipv4.tcp_no_metrics_save=1 net.ipv4.tcp_rmem=4096 87380 16777216 net.ipv4.tcp_slow_start_after_idle=0 net.ipv4.tcp_synack_retries=2 net.ipv4.tcp_syn_retries=2 net.ipv4.tcp_tw_reuse=1 net.ipv4.tcp_wmem=4096 65535 16777216 net.nf_conntrack_max=1048576 vm.max_map_count=1048576 vm.min_free_kbytes=65535 vm.overcommit_memory=1 vm.swappiness=0 vm.vfs_cache_pressure=50 EOF sysctl --system # limits.conf settings cat < /etc/security/limits.d/999-perf.conf * soft nofile 1048576 * hard nofile 1048576 root soft nofile 1048576 root hard nofile 1048576 * soft nproc 1048576 * hard nproc 1048576 root soft nproc 1048576 root hard nproc 1048576 * soft memlock unlimited * hard memlock unlimited root soft memlock unlimited root hard memlock unlimited * soft core 0 * hard core 0 root soft core 0 root hard core 0 EOF # systemd limits cat < /etc/systemd/system.conf [Manager] DefaultLimitNOFILE=1048576 DefaultLimitNPROC=1048576 DefaultLimitMEMLOCK=infinity EOF # Done! reboot