#!/bin/bash set -e root_directory="/var/www/flarum/" unprivileged_php_user="php_flarum" install_os="ubuntu" help_message() { echo "" echo "##################################" echo " Usage" echo "" echo -e " -a Restore the most recent backup" echo " -a sub.domain.tld" echo " Eg. $0 -a flarum.mysite.org" echo " Eg. $0 -a flarum.mysite.org -a mysecondflarum.mysite.org" echo "" echo -e " -b Create a backup of specified site" echo " -b sub.domain.tld" echo " Eg. $0 -b flarum.mysite.org" echo " Eg. $0 -b flarum.mysite.org -a mysecondflarum.mysite.org" echo "" echo " -f sub.domain.tld" echo " Eg. $0 -f flarum.mysite.org" echo " Eg. $0 -f flarum.mysite.org -f mysecondflarum.mysite.org" echo "" echo " -h This help message" echo "" echo -e " -i Install LEMP stack\n (Linux Nginx Mysql Php)" echo " Eg. $0 -i" echo "" echo -e " -r Remove existing site install and database. SSL certificate\n removed if used with -s" echo " Eg. $0 -r flarum.mysite.org" echo " Eg. $0 -sr flarum.mysite.org" echo "" echo " -s Configure with ssl. When used with -r will remove ssl. Use before -f or -s." echo " Eg $0 -s -f flarum.mysite.org" echo " Eg $0 -s -r flarum.mysite.org" echo " Eg $0 -s -r flarum.mysite.org -f mysecondflarum.mysite.org" echo "##################################" echo "" } if [ -z "${1+x}" ]; then help_message exit 1 fi setup_users() { # Adds needed users and assigns them to their groups sudo mkdir -p "$root_directory" sudo useradd "$unprivileged_php_user" --home-dir "$root_directory" --system --shell /bin/false || true sudo useradd "$webserver_user" --system --shell /bin/false || true sudo gpasswd -a "$unprivileged_php_user" "$webserver_user" sudo gpasswd -a "$webserver_user" "$unprivileged_php_user" } setup_php_config() { ### Write php7-fpm pool config ### Usage: setup_php_config /config/directory echo writing php7-fpm config sudo tee << EOF "$1" &> /dev/null [flarum] listen = /var/run/php7-fpm.\$pool.sock listen.allowed_clients = 127.0.0.1 user = "$unprivileged_php_user" group = "$unprivileged_php_user" listen.owner = www-data listen.group = www-data pm = ondemand pm.max_children = 10 pm.max_requests = 5000 pm.process_idle_timeout = 180s chdir = / EOF } initial_install_nginx_ubuntu-19.04() { webserver_user="www-data" # Sets up initial users and groups setup_users # Update lists echo 'Updating...' sudo apt-get update sudo apt-get install \ nginx \ mysql-server \ mysql-client \ php7.2 \ php7.2-curl \ php7.2-gd \ php7.2-cli \ php7.2-mysql \ php7.2-mbstring \ php7.2-dom \ php7.2-fpm \ pwgen \ zip \ unzip \ git # Writes php config setup_php_config '/etc/php/7.2/fpm/pool.d/flarum.conf' # If default nginx config exists delete it if [ -f /etc/nginx/sites-enabled/default ] then sudo rm /etc/nginx/sites-enabled/default fi sudo service php7.2-fpm stop; sudo service php7.2-fpm start } initial_install_nginx_ubuntu-18.10() { webserver_user="www-data" # Sets up initial users and groups setup_users # Update lists echo 'Updating...' sudo apt-get update sudo apt-get install \ nginx \ mysql-server \ mysql-client \ php7.2 \ php7.2-curl \ php7.2-gd \ php7.2-cli \ php7.2-mysql \ php7.2-mbstring \ php7.2-dom \ php7.2-fpm \ pwgen \ zip \ unzip \ git # Writes php config setup_php_config '/etc/php/7.2/fpm/pool.d/flarum.conf' # If default nginx config exists delete it if [ -f /etc/nginx/sites-enabled/default ] then sudo rm /etc/nginx/sites-enabled/default fi sudo service php7.2-fpm stop; sudo service php7.1-fpm start } initial_install_nginx_ubuntu-16.04() { webserver_user="www-data" # Sets up initial users and groups setup_users # Update lists echo 'Updating...' sudo apt-get update sudo apt-get install \ nginx-full \ mysql-server \ mysql-client \ php7.0-curl \ php7.0-gd \ php7.0-cli \ php7.0-mysql \ php7.0-mbstring \ php7.0-dom \ php7.0-fpm \ pwgen \ zip \ unzip \ git # Writes php config setup_php_config '/etc/php/7.0/fpm/pool.d/flarum.conf' # If default nginx config exists delete it if [ -f /etc/nginx/sites-enabled/default ] then sudo rm /etc/nginx/sites-enabled/default fi sudo service php7.0-fpm stop; sudo service php7.0-fpm start } initial_install_nginx_ubuntu-17.10() { webserver_user="www-data" # Sets up initial users and groups setup_users # Update lists echo 'Updating...' sudo apt-get update sudo apt-get install \ nginx-full \ mysql-server \ mysql-client \ php7.1-curl \ php7.1-gd \ php7.1-cli \ php7.1-mysql \ php7.1-mbstring \ php7.1-dom \ php7.1-fpm \ pwgen \ zip \ unzip \ git # Writes php config setup_php_config '/etc/php/7.1/fpm/pool.d/flarum.conf' # If default nginx config exists delete it if [ -f /etc/nginx/sites-enabled/default ] then sudo rm /etc/nginx/sites-enabled/default fi sudo service php7.1-fpm stop; sudo service php7.1-fpm start } initial_install_nginx_ubuntu-16.04() { webserver_user="www-data" # Sets up initial users and groups setup_users # Update lists echo 'Updating...' sudo apt-get update sudo apt-get install \ nginx-full \ mysql-server \ mysql-client \ php7.0-curl \ php7.0-gd \ php7.0-cli \ php7.0-mysql \ php7.0-mbstring \ php7.0-dom \ php7.0-fpm \ pwgen \ zip \ unzip \ git # Writes php config setup_php_config '/etc/php/7.0/fpm/pool.d/flarum.conf' # If default nginx config exists delete it if [ -f /etc/nginx/sites-enabled/default ] then sudo rm /etc/nginx/sites-enabled/default fi sudo service php7.0-fpm stop; sudo service php7.0-fpm start } ssl_nginx_install() { if [ ! -f /opt/certbot-auto ] then wget https://dl.eff.org/certbot-auto chmod a+x certbot-auto sudo mv certbot-auto /opt/certbot-auto fi if [ ! -f /etc/nginx/ssl/dhparam.pem ] then sudo mkdir -p /etc/nginx/ssl echo 'Creating your dhparen.pem will take several minutes or more. It is required one-time only ' sleep 5 sudo openssl dhparam 2048 -out /etc/nginx/ssl/dhparam.pem fi if [ ! -d /var/tmp/letsencrypt ] then sudo mkdir -p /var/tmp/letsencrypt fi if [ ! -f /etc/nginx/sites-available/letsencrypt ] then # Installing letsencrypt webroot config echo Configuring letsencrypt webroot config sudo tee << EOF /etc/nginx/sites-available/letsencrypt &> /dev/null server { # autogenerated listen 80; root /var/tmp/letsencrypt; error_log /var/log/nginx/error.log error; server_name _; location /.well-known/acme-challenge { } } EOF fi if [ ! -h /etc/nginx/sites-enabled/letsencrypt ] then sudo ln -s /etc/nginx/sites-available/letsencrypt /etc/nginx/sites-enabled/letsencrypt fi # Remove flarum nginx config to prevent missing cert error. Will be regenerated if [ -f /etc/nginx/sites-available/"$site_url" ] then sudo rm /etc/nginx/sites-available/"$site_url" fi sudo nginx -t && sudo service nginx reload # Causes certificates to be renewed and then restarts nginx if [ ! -f /etc/cron.daily/certbot ] then echo '/opt/certbot-auto renew' | sudo tee --append /etc/cron.daily/certbot echo 'service nginx reload' | sudo tee --append /etc/cron.daily/certbot fi } install_nginx_flarum() { site_url="$( echo "$1" | grep -iIohE '[^[:space:]]+' | cut -d'/' -f3)" site_install_directory="${root_directory}${site_url}" # Only do config if directory already exists if [ -d "$site_install_directory" ] then echo "$site_install_directory already exists. Will only alter configuration" existing_install=TRUE else echo -e "\n\nInstalling $site_url to $site_install_directory\n" sleep 3 fi # Install composer if [ ! -x /usr/bin/composer ] then php -r "readfile('https://getcomposer.org/installer');" > composer-setup.php sudo php composer-setup.php --install-dir=/usr/bin --filename composer php -r "unlink('composer-setup.php');" fi if [ "$existing_install" != TRUE ] then echo Installing flarum.. sudo mkdir -p "$site_install_directory" sudo chown "$USER":"$unprivileged_php_user" "$site_install_directory" composer create-project flarum/flarum "$site_install_directory" --stability=beta # Change group and permissions chmod 775 "$site_install_directory" chmod -R 775 "$site_install_directory/public/assets" "$site_install_directory/storage" sudo chgrp -R "$unprivileged_php_user" "$site_install_directory/public/assets" "$site_install_directory/storage" fi if [ "$modify_ssl" == TRUE ] then ssl_nginx_install fi # Installing nginx config echo Configuring nginx for "$site_install_directory" sudo tee << EOF /etc/nginx/sites-available/"$site_url" &> /dev/null server { # autogenerated listen 80; root $site_install_directory; index index.php index.html index.htm; error_log /var/log/nginx/error.log error; server_name $site_url; EOF #Optional ssl config if [ "$modify_ssl" == TRUE ] then sudo tee --append << EOF /etc/nginx/sites-available/"$site_url" &> /dev/null listen 443 ssl; ssl_certificate /etc/letsencrypt/live/$site_url/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/$site_url/privkey.pem; location /.well-known/acme-challenge { root /var/tmp/letsencrypt; } # SSL Config # modern configuration. tweak to your needs. ssl_protocols TLSv1.1 TLSv1.2; ssl_session_timeout 1d; ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:50m; ssl_dhparam /etc/nginx/ssl/dhparam.pem; # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) # add_header Strict-Transport-Security max-age=15768000; # End SSL Config EOF fi sudo tee --append << 'EOF' /etc/nginx/sites-available/"$site_url" &> /dev/null location / { try_files $uri $uri/ /index.php?$query_string; } location /api { try_files $uri $uri/ /api.php?$query_string; } location /admin { try_files $uri $uri/ /admin.php?$query_string; } location /flarum { deny all; return 404; } location ~ .php$ { fastcgi_split_path_info ^(.+.php)(/.+)$; fastcgi_pass unix:/var/run/php7-fpm.flarum.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } location ~* \.html$ { expires -1; } location ~* \.(css|js|gif|jpe?g|png)$ { expires 1M; add_header Pragma public; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; } gzip on; gzip_http_version 1.1; gzip_vary on; gzip_comp_level 6; gzip_proxied any; gzip_types application/atom+xml application/javascript application/json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/xml; gzip_buffers 16 8k; gzip_disable "MSIE [1-6]\.(?!.*SV1)"; } EOF # Enable flarum site if [ ! -h /etc/nginx/sites-enabled/"$site_url" ] then sudo ln -s /etc/nginx/sites-available/"$site_url" /etc/nginx/sites-enabled/"$site_url" fi # Enable ssl for current flarum install if [ "$modify_ssl" == TRUE ] then /opt/certbot-auto certonly --webroot -w /var/tmp/letsencrypt -d "$site_url" fi sudo nginx -t && sudo service nginx reload if [ "$existing_install" != TRUE ] then # Database creation # Generate Password generated_mysql_pass=$(pwgen 20 1) database_name="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)" database_username="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)" if [ -z "${mysql_pass+x}" ]; then read -sp 'Enter mysql root password ' mysql_pass fi mysql -uroot -p"$mysql_pass" -e 'DROP DATABASE `'"$database_name"'` ;' || true mysql -uroot -p"$mysql_pass" -e 'CREATE DATABASE `'"$database_name"'` ;' || true mysql -uroot -p"$mysql_pass" -e "DROP USER '$database_username'@'localhost' ;" || true mysql -uroot -p"$mysql_pass" -e "CREATE USER '$database_username'@'localhost' IDENTIFIED BY '$generated_mysql_pass';" || true mysql -uroot -p"$mysql_pass" -e "GRANT USAGE ON * . * TO '$database_username'@'localhost' IDENTIFIED BY '$generated_mysql_pass' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;" mysql -uroot -p"$mysql_pass" -e "GRANT ALL PRIVILEGES ON \`$database_name\` . * TO '$database_username'@'localhost';" echo "#############################" echo "Site directory created at" echo "$site_install_directory" echo "" echo "Database Credentials Generated!" echo "Copy the below credentials to your website at" echo "$site_url" echo "" echo "Flarum database -> $database_name" echo "Flarum username -> $database_username" echo "Flarum database password ->" "$generated_mysql_pass" echo "" echo "Ensure you have completed the web install PRIOR to hitting enter" echo "if you are installing flarum more then once" echo "" echo "#############################" unset generated_mysql_pass read -sp 'Hit Enter to Continue ' null else echo Configuration written fi } remove_nginx_site() { site_url="$( echo "$1" | grep -iIohE '[^[:space:]]+' | cut -d'/' -f3)" site_install_directory="${root_directory}${site_url}" # Remove site files if [ -d "$site_install_directory" ] then sudo rm -r "$site_install_directory" fi # Remove site nginx config if [ -e "/etc/nginx/sites-available/$site_url" ] then sudo rm /etc/nginx/sites-available/"$site_url" /etc/nginx/sites-enabled/"$site_url" fi # Remove ssl keys for site if [ "$modify_ssl" == TRUE ] && [ -e /etc/letsencrypt/renewal/"$site_url".conf ] then sudo rm -r /etc/letsencrypt/live/"$site_url" sudo rm -r /etc/letsencrypt/archive/"$site_url" sudo rm /etc/letsencrypt/renewal/"$site_url".conf fi # Drop database and user for this flarum site database_name="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)" database_username="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)" if [ -z "${mysql_pass+x}" ]; then read -sp 'Enter mysql root password ' mysql_pass fi mysql -uroot -p"$mysql_pass" -e 'DROP DATABASE `'"$database_name"'` ;' || true mysql -uroot -p"$mysql_pass" -e "DROP USER '$database_username'@'localhost' ;" || true sudo service nginx configtest && sudo service nginx reload } update_flarum() { site_url="$( echo "$1" | grep -iIohE '[^[:space:]]+' | cut -d'/' -f3)" site_install_directory="${root_directory}${site_url}" if [ ! -f "$site_install_directory"/composer.json ] then echo "No composer.json at "$site_install_directory"/composer.json" else ( cd "$site_install_directory" && \ composer update "$( python3 -c "import sys, json; \ [ print(key, end=' ') for key, value in json.load(sys.stdin)['require'].items()]" \ < composer.json)" && \ php flarum cache:clear ) fi } restore_site() { site_url="$(echo "$1" | grep -iIohE '[^[:space:]]+' | cut -d'/' -f3)" site_install_directory="${root_directory}${site_url}" backup_location="${root_directory}backups/${site_url}" database_name="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)" database_username="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)" most_recent_backup="$(find "$backup_location" -maxdepth 1 -type d -not -name "$(basename "$backup_location")" -printf "%T@ %p\n"| sort -nr | head -n1 | cut -d' ' -f 2)" echo "Choosing ${most_recent_backup}" if [ -z "${mysql_pass+x}" ]; then read -sp 'Enter mysql root password ' mysql_pass fi sudo rsync --owner --group -a --delete "${most_recent_backup}/site_files/" "$site_install_directory" mysqldump -u'root' -p"$mysql_pass" --add-drop-table --no-data "$database_name" | grep -e '^DROP \| FOREIGN_KEY_CHECKS' | mysql -u'root' -p"$mysql_pass" "$database_name" mysql -uroot -p"$mysql_pass" "$database_name" < <(gzip -dc "${most_recent_backup}/"database.sql.gz) ( cd "$site_install_directory" sudo php flarum cache:clear ) } backup_site() { site_url="$( echo "$1" | grep -iIohE '[^[:space:]]+' | cut -d'/' -f3)" site_install_directory="${root_directory}${site_url}" backup_location="${root_directory}backups/${site_url}" if [ ! -d "$backup_location" ] then echo 'Creating' "$backup_location" sudo mkdir -p "${backup_location}" fi database_name="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)" database_username="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)" if [ -z "${mysql_pass+x}" ]; then read -sp 'Enter mysql root password ' mysql_pass fi if [ -d "${backup_location}"/source ] then count=1 new_dir="$(date '+%F')_${count}" while [ -d "${backup_location}/$new_dir" ] do # If new_dir exist, append and increment _n until no match count="$((count + 1))" new_dir="${new_dir%_*}_${count}" done # Sync changes and dump database to source backup sudo rsync --delete --owner --group -a "$site_install_directory"/ "${backup_location}/source/site_files" mysqldump -uroot -p"$mysql_pass" "$database_name" | gzip | sudo tee "${backup_location}/source/database".sql.gz 1> /dev/null echo Creating "${backup_location}/${new_dir}" sudo mkdir "${backup_location}/${new_dir}" # Increment backup number if done more then once per day if [ "$count" -gt 1 ] then old_dir="${new_dir%_*}_$((count - 1 ))" else old_dir="source" fi # Sync the old backup with the new one, using the source to hardlink only changes sudo rsync -a --delete --link-dest="${backup_location}"/source "${backup_location}"/"${old_dir}"/ "$backup_location"/"$new_dir" else sudo mkdir "${backup_location}"/source mysqldump -uroot -p"$mysql_pass" "$database_name" | gzip | sudo tee "${backup_location}/source/database".sql.gz 1> /dev/null sudo cp -a "$site_install_directory" "${backup_location}/source/site_files" fi sudo find "$backup_location" -maxdepth 1 -type d -mtime +14 -daystart -delete } while getopts "a:b:f:hir:su:" opt; do case "$opt" in a) # Restore most recent backup restore_site "$OPTARG" ;; b) # Backup site to root_directory/backups backup_site "$OPTARG" ;; f) # Install Flarum with argument of sitename eg helloworld.domain.org install_nginx_flarum "$OPTARG" ;; h) help_message ;; i) # initial_install if [ "${install_os,,}" == 'ubuntu' ] then initial_install_nginx_ubuntu-"$(lsb_release -r | grep -oE '[0-9]{1,2}\.[0-9]{1,2}')" fi ;; r) echo "WARNING - THIS WILL REMOVE THE SITE $OPTARG" echo "Are you SURE you want to continue?" read -p'Y/N ' kill_site if [ "${kill_site,,}" == 'y' ] || [ "${kill_site,,}" == 'yes' ]; then remove_nginx_site "$OPTARG" else echo "Not removing $OPTARG" fi ;; s) # Configure with SSL modify_ssl=TRUE ;; u) # Update site update_flarum "$OPTARG" ;; esac done