From adee24af6fcf057ad9cedd44bd11199806b01379 Mon Sep 17 00:00:00 2001 From: Papa Dragon Date: Sun, 30 Aug 2020 12:18:51 +0200 Subject: Update of the home install setup script - "hubzilla" replaced by "zotserver" in file names and file content when relevant - Nginx can now be installed as the web server (Apache still chosen by default in the config file) - Setup script now allows installation of multiple hub/instances on the same server - Daily cron jobs script was updated an splitted : one global script launches shared commands (SSL cert renewal + global backup on external device) and every instance has its own script for git pull (individual scripts are launched by the global one) --- .homeinstall/README.md | 46 +- .homeinstall/hubzilla-config.txt.template | 163 ------ .homeinstall/hubzilla-setup.sh | 648 ----------------------- .homeinstall/nginx-zotserver.conf.template | 144 ++++++ .homeinstall/zotserver-config.txt.template | 178 +++++++ .homeinstall/zotserver-setup.sh | 793 +++++++++++++++++++++++++++++ 6 files changed, 1138 insertions(+), 834 deletions(-) delete mode 100644 .homeinstall/hubzilla-config.txt.template delete mode 100755 .homeinstall/hubzilla-setup.sh create mode 100644 .homeinstall/nginx-zotserver.conf.template create mode 100644 .homeinstall/zotserver-config.txt.template create mode 100755 .homeinstall/zotserver-setup.sh diff --git a/.homeinstall/README.md b/.homeinstall/README.md index df1d14ef8..e2c345969 100644 --- a/.homeinstall/README.md +++ b/.homeinstall/README.md @@ -1,9 +1,10 @@ + # How to use ## Disclaimers - This script does work with Debian 10 only. -- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation). +- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation). You may use it to install several hub/instances on the same server, though. ## Preconditions @@ -15,9 +16,11 @@ Hardware Software -+ Fresh installation of Debian 10 (Stretch) ++ Fresh installation of Debian 10 (Buster) + Router with open ports 80 and 443 for your web server -+ Some form of email server or email gateway such that PHP mail() works. + +You can of course run the script on a VPS or any distant server as long as the above sotfware requirements are satisfied. + ## How to run the script @@ -26,29 +29,29 @@ Software - apt-get install git - mkdir -p /var/www - cd /var/www - - git clone https://framagit.org/hubzilla/core.git html + - git clone https://framagit.org/hubzilla/core.git html (you can replace "html" with any folder name you like, which you'll have to do if you plan to have more than one hub/instance running on your server) - cd html/.homeinstall - - cp hubzilla-config.txt.template hubzilla-config.txt - - nano hubzilla-config.txt + - cp zotserver-config.txt.template zotserver-config.txt + - nano zotserver-config.txt - Read the comments carefully - Enter your values: db pass, domain, values for dyn DNS - Prepare your external disk for backups - - hubzilla-setup.sh as root - - ... wait, wait, wait until the script is finised -+ Open your domain with a browser and step throught the initial configuration of hubzilla. + - ./zotserver-setup.sh as root + - ... wait, wait, wait until the script is finished ++ Open your domain with a browser and step throught the initial configuration of your hub/instance. ## Optional - Set path to imagemagick -In Admin settings of hubzilla or via terminal +In Admin settings of your hub/instance or via terminal - cd /var/www/html + cd /var/www/html (or the custom path you chose) util/config system.imagick_convert_path /usr/bin/convert ## Optional - Switch verification of email on/off -Do this just befor you register the user and you have no working PHP mail(). +Do this just before you register the first user. -In Admin settings of hubzilla or via terminal +In Admin settings of your hub/instance or via terminal cd /var/www/html @@ -62,18 +65,18 @@ Switch the verification on/off (1/0) ## What the script will do for you... -+ install everything required by Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,... ++ install everything required by your hub/instance, basically a web server (Apache or Nginx), PHP, a database (MySQL), certbot,... + create a database + run certbot to have everything for a secure connection (httpS) + create a script for daily maintenance - backup to external disk (certificates, database, /var/www/) - renew certfificate (letsencrypt) - - update of Hubzilla + - update of your hub/instance (git) - update of Debian - restart + create cron jobs for - DynDNS (selfHOST.de or freedns.afraid.org) every 5 minutes - - Master.php for Zap/Hubzilla every 10 minutes + - Run.php for your hub/instance every 10 minutes - daily maintenance script every day at 05:30 The script is known to work without adjustments with @@ -86,7 +89,7 @@ The script is known to work without adjustments with - selfHOST.de - freedns.afraid.org -The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzilla-project) and [Zap](https://zotlabs.com/zap/). Make sure to use the correct GIT repositories. +The script can install [Hubzilla](https://zotlabs.org/page/hubzilla/hubzilla-project), [Zap](https://zotlabs.com/zap/) and [Mistpark 2020, aka "Misty"](https://zotlabs.com/misty/). Make sure to use the correct GIT repositories. # Step-by-Step - some Details @@ -101,11 +104,11 @@ Open the ports 80 and 443 on your router for your Debian. Make sure your web ser ## Preparations Dynamic IP Address -Follow the instructions in .homeinstall/hubzilla-config.txt. +Follow the instructions in .homeinstall/zotserver-config.txt. In short... -Your Hubzilla must be reachable by a domain that you can type in your browser +Your Hubzilla server must be reachable by a domain that you can type in your browser cooldomain.org @@ -127,8 +130,6 @@ The cost is 1,50 € per month (2019). ## Note on Rasperry -The script was tested with an Raspberry 3 under Raspian, Debian 10. - It is recommended to run the Raspi without graphical frontend (X-Server). Use... sudo raspi-config @@ -139,5 +140,4 @@ DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI! ## Reminder for Different Web Wervers -For those of you who feel adventurous enough to use a different web server (Nginx, Lighttpd...), don't forget that this script will install Apache and that you can only have one web server listening to ports 80 & 443. Also, don't forget to tweak /var/www/hubzilla-daily.sh accordingly. - +For those of you who feel adventurous enough to use a different web server (i.e. Lighttpd...), don't forget that this script will install Apache or Nginx and that you can only have one web server listening to ports 80 & 443. Also, don't forget to tweak your daily shell script in /var/www/ accordingly. diff --git a/.homeinstall/hubzilla-config.txt.template b/.homeinstall/hubzilla-config.txt.template deleted file mode 100644 index f0bf6121c..000000000 --- a/.homeinstall/hubzilla-config.txt.template +++ /dev/null @@ -1,163 +0,0 @@ -############################################### -### MANDATORY - database password ############# -# -# Please give your database password -# It is better to not use blanks inside the password. -# Example: db_pass=pass_word_with_no_blanks_in_it -db_pass= - -############################################### -### MANDATORY - let's encrypt ################# -# -# Hubilla requires encrypted communication via secure HTTP (HTTPS). -# This script automates installation of an SSL certificate from -# Let's Encrypt (https://letsencrypt.org) -# -# Please give the domain name of your hub -# -# Example: my.cooldomain.org -# Example: cooldomain.org -# -# You might use "localhost" for a LOCAL TEST installation. -# This is usefull if you want to debug the server inside a VM. -# -# Example: localhost -# -# Email is optional if you use "localhost". -# -# -le_domain= -le_email= - -############################################### -### OPTIONAL - selfHOST - dynamic IP address ## -# -# 1. Register a domain at selfhost.de -# - choose offer "DOMAIN dynamisch" 1,50€/mon at 04/2019 -# 2. Get your configuration for dynamic IP update -# - Log in at selfhost.de -# - go to "DynDNS Accounte" -# - klick "Details" of your (freshly) registered domain -# - You will find the configuration there -# - Benutzername (user name) > use this for "selfhost_user=" -# - Passwort (pass word) > use this for "selfhost_pass=" -# -# -selfhost_user= -selfhost_pass= - -############################################### -### OPTIONAL - FreeDNS - dynamic IP address ### -# -# Please give the alpha-numeric-key of freedns -# -# Get a free subdomain from freedns and use it for your dynamic ip address -# Documentation under http://www.techjawab.com/2013/06/setup-dynamic-dns-dyndns-for-free-on.html -# -# - Register for a Free domain at http://freedns.afraid.org/signup/ -# - WATCH THIS: Make sure you choose a domain with as less subdomains as -# possible. Why? Let's encrpyt issues a limited count of certificates each -# day. Possible other users of this domain will try to issue a certificate -# at the same day. -# - Logon to FreeDNS (where you just registered) -# - Goto http://freedns.afraid.org/dynamic/ -# - Right click on "Direct Link" and copy the URL and paste it somewhere. -# - You should notice a large and unique alpha-numeric key in the URL -# -# http://freedns.afraid.org/dynamic/update.php?alpha-numeric-key -# -# Provided your url from freedns is -# -# http://freedns.afraid.org/dynamic/update.php?U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5 -# -# Then you have to provide -# -# freedns_key=U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5 -# -# -freedns_key= - - -############################################### -### OPTIONAL - Backup to external device ###### -# -# The script can use an external device for the daily backup. -# The file system of the device (USB stick for example) must be compatible with -# -# - encrypted LUKS + ext4, or -# - ext4 -# -# You should test to mount the device befor you run the script -# (hubzilla-setup.sh). -# How to find your (pluged-in) devices? -# -# fdisk -l -# -# Provided your device was listed as is /dev/sdb1. You could check with: -# -# blkid | grep /dev/sdb1 -# -# Try to decrypt -# (You might install cryptsetup befor using apt-get install. -# -# apt-get install cryptsetup -# cryptsetup luksOpen /dev/sdb1 cryptobackup -# -# Try to mount -# You might create the directory /media/hubzilla_backup it it does not exist -# using mkdir. -# -# mkdir /media/hubzilla_backup -# mount /dev/mapper/cryptobackup /media/hubzilla_backup -# -# Unmounting device goes like this -# -# umount /media/hubzilla_backup -# cryptsetup luksClose cryptobackup -# -# To check if still mounted -# -# lsof /media/hubzilla_backup -# -# If you leave the following parameters -# -# - "backup_device_name" and -# - "backup_device_pass" -# -# empty the script will create daily backups on the internal disk (which could -# save you as well). -# -# Example: backup_device_name=/dev/sdc1 -# -# Leave "backup_device_pass=" empty if the external device is not encrypted. -# -backup_device_name= -backup_device_pass= - - -############################################### -### OPTIONAL - do not mess with things below ## -# (...if you are not certain) -# -# Usually you are done here -# Everything below is OPTIONAL -# -############################################### -# -# Database for hubzilla -hubzilla_db_name=hubzilla -hubzilla_db_user=hubzilla -hubzilla_db_pass=$db_pass -# -# -# Password for package mysql-server -# Example: mysqlpass=aberhallo -# Example: mysqlpass="aber hallo has blanks in it" -# -mysqlpass=$db_pass - -# Password for package phpmyadmin -# Example: phpmyadminpass=aberhallo -# Example: phpmyadminpass="aber hallo has blanks in it" -phpmyadminpass=$db_pass - diff --git a/.homeinstall/hubzilla-setup.sh b/.homeinstall/hubzilla-setup.sh deleted file mode 100755 index 063cfcea4..000000000 --- a/.homeinstall/hubzilla-setup.sh +++ /dev/null @@ -1,648 +0,0 @@ -#!/bin/bash -# -# How to use -# ---------- -# -# This file automates the installation of -# - hubzilla: https://zotlabs.org/page/hubzilla/hubzilla-project and -# - zap: https://zotlabs.com/zap/ -# under Debian Linux -# -# 1) Copy the file "hubzilla-config.txt.template" to "hubzilla-config.txt" -# Follow the instuctions there -# -# 2) Switch to user "root" by typing "su -" -# -# 3) Run with "./hubzilla-setup.sh" -# If this fails check if you can execute the script. -# - To make it executable type "chmod +x hubzilla-setup.sh" -# - or run "bash hubzilla-setup.sh" -# -# -# What does this script do basically? -# ----------------------------------- -# -# This file automates the installation of hubzilla under Debian Linux -# - install -# * apache webserer, -# * php, -# * mariadb - the database for hubzilla, -# * adminer, -# * git to download and update addons -# - configure cron -# * "Master.php" for regular background prozesses of hubzilla -# * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date -# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org -# * backup hubzillas database and files (rsync) -# - run letsencrypt to create, register and use a certifacte for https -# -# -# Discussion -# ---------- -# -# Security - password is the same for mysql-server, phpmyadmin and hubzilla db -# - The script runs into installation errors for phpmyadmin if it uses -# different passwords. For the sake of simplicity one singel password. -# -# How to restore from backup -# -------------------------- -# -# Daily backup -# - - - - - - -# -# The installation -# - writes a script /var/www/hubzilla-daily.sh -# - creates a daily cron that runs the hubzilla-daily.sh -# -# hubzilla-daily.sh makes a (daily) backup of all relevant files -# - /var/lib/mysql/ > database -# - /var/www/ > hubzilla/zap from github -# - /etc/letsencrypt/ > certificates -# -# hubzilla-daily.sh writes the backup to an external disk compatible to LUKS+ext4 (see hubzilla-config.txt) -# -# Credits -# ------- -# -# The script is based on Thomas Willinghams script "debian-setup.sh" -# which he used to install the red#matrix. -# -# The documentation for bash is here -# https://www.gnu.org/software/bash/manual/bash.html -# -function check_sanity { - # Do some sanity checking. - print_info "Sanity check..." - if [ $(/usr/bin/id -u) != "0" ] - then - die 'Must be run by root user' - fi - - if [ -f /etc/lsb-release ] - then - die "Distribution is not supported" - fi - if [ ! -f /etc/debian_version ] - then - die "Debian is supported only" - fi - if ! grep -q 'Linux 10' /etc/issue - then - die "Linux 10 (buster) is supported only"x - fi -} - -function check_config { - print_info "config check..." - # Check for required parameters - if [ -z "$db_pass" ] - then - die "db_pass not set in $configfile" - fi - if [ -z "$le_domain" ] - then - die "le_domain not set in $configfile" - fi - # backup is important and should be checked - if [ -n "$backup_device_name" ] - then - if [ ! -d "$backup_mount_point" ] - then - mkdir "$backup_mount_point" - fi - device_mounted=0 - if fdisk -l | grep -i "$backup_device_name.*linux" - then - print_info "ok - filesystem of external device is linux" - if [ -n "$backup_device_pass" ] - then - echo "$backup_device_pass" | cryptsetup luksOpen $backup_device_name cryptobackup - if mount /dev/mapper/cryptobackup /media/hubzilla_backup - then - device_mounted=1 - print_info "ok - could encrypt and mount external backup device" - umount /media/hubzilla_backup - else - print_warn "backup to external device will fail because encryption failed" - fi - cryptsetup luksClose cryptobackup - else - if mount $backup_device_name /media/hubzilla_backup - then - device_mounted=1 - print_info "ok - could mount external backup device" - umount /media/hubzilla_backup - else - print_warn "backup to external device will fail because mount failed" - fi - fi - else - print_warn "backup to external device will fail because filesystem is either not linux or 'backup_device_name' is not correct in $configfile" - fi - if [ $device_mounted == 0 ] - then - die "backup device not ready" - fi - fi -} - -function die { - echo "ERROR: $1" > /dev/null 1>&2 - exit 1 -} - - -function update_upgrade { - print_info "updated and upgrade..." - # Run through the apt-get update/upgrade first. This should be done before - # we try to install any package - apt-get -q -y update && apt-get -q -y dist-upgrade - print_info "updated and upgraded linux" -} - -function check_install { - if [ -z "`which "$1" 2>/dev/null`" ] - then - # export DEBIAN_FRONTEND=noninteractive ... answers from the package - # configuration database - # - q ... without progress information - # - y ... answer interactive questions with "yes" - # DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -q -y install $2 - DEBIAN_FRONTEND=noninteractive apt-get -q -y install $2 - print_info "installed $2 installed for $1" - else - print_warn "$2 already installed" - fi -} - -function nocheck_install { - # export DEBIAN_FRONTEND=noninteractive ... answers from the package configuration database - # - q ... without progress information - # - y ... answer interactive questions with "yes" - # DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -q -y install $2 - # DEBIAN_FRONTEND=noninteractive apt-get --install-suggests -q -y install $1 - DEBIAN_FRONTEND=noninteractive apt-get -q -y install $1 - print_info "installed $1" -} - - -function print_info { - echo -n -e '\e[1;34m' - echo -n $1 - echo -e '\e[0m' -} - -function print_warn { - echo -n -e '\e[1;31m' - echo -n $1 - echo -e '\e[0m' -} - -function stop_hubzilla { - print_info "stopping apache webserver..." - systemctl stop apache2 - print_info "stopping mysql db..." - systemctl stop mariadb -} - -function install_apache { - print_info "installing apache..." - nocheck_install "apache2 apache2-utils" - a2enmod rewrite - systemctl restart apache2 -} - -function install_imagemagick { - print_info "installing imagemagick..." - nocheck_install "imagemagick" -} - -function install_curl { - print_info "installing curl..." - nocheck_install "curl" -} - -function install_wget { - print_info "installing wget..." - nocheck_install "wget" -} - -function install_sendmail { - print_info "installing sendmail..." - nocheck_install "sendmail sendmail-bin" -} - -function install_php { - # openssl and mbstring are included in libapache2-mod-php - print_info "installing php..." - nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip" - sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.3/apache2/php.ini - sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/apache2/php.ini -} - -function install_mysql { - print_info "installing mysql..." - if [ -z "$mysqlpass" ] - then - die "mysqlpass not set in $configfile" - fi - if type mysql ; then - echo "Yes, mysql is installed" - else - echo "mariadb-server" - nocheck_install "mariadb-server" - systemctl status mariadb - systemctl start mariadb - mysql --user=root <<_EOF_ -UPDATE mysql.user SET Password=PASSWORD('${db_root_password}') WHERE User='root'; -DELETE FROM mysql.user WHERE User=''; -DROP DATABASE IF EXISTS test; -DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'; -FLUSH PRIVILEGES; -_EOF_ - fi -} - -function install_adminer { - print_info "installing adminer..." - nocheck_install "adminer" - if [ ! -f /etc/adminer/adminer.conf ] - then - echo "Alias /adminer /usr/share/adminer/adminer" > /etc/adminer/adminer.conf - ln -s /etc/adminer/adminer.conf /etc/apache2/conf-available/adminer.conf - else - print_info "file /etc/adminer/adminer.conf exists already" - fi - - a2enmod rewrite - - if [ ! -f /etc/apache2/apache2.conf ] - then - die "could not find file /etc/apache2/apache2.conf" - fi - sed -i \ - "s/AllowOverride None/AllowOverride all/" \ - /etc/apache2/apache2.conf - - a2enconf adminer - systemctl restart mariadb - systemctl reload apache2 -} - -function create_hubzilla_db { - print_info "creating hubzilla database..." - if [ -z "$hubzilla_db_name" ] - then - die "hubzilla_db_name not set in $configfile" - fi - if [ -z "$hubzilla_db_user" ] - then - die "hubzilla_db_user not set in $configfile" - fi - if [ -z "$hubzilla_db_pass" ] - then - die "hubzilla_db_pass not set in $configfile" - fi - systemctl restart mariadb - Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;" - Q2="GRANT USAGE ON *.* TO $hubzilla_db_user@localhost IDENTIFIED BY '$hubzilla_db_pass';" - Q3="GRANT ALL PRIVILEGES ON $hubzilla_db_name.* to $hubzilla_db_user@localhost identified by '$hubzilla_db_pass';" - Q4="FLUSH PRIVILEGES;" - SQL="${Q1}${Q2}${Q3}${Q4}" - mysql -uroot -p$phpmyadminpass -e "$SQL" -} - -function run_freedns { - print_info "run freedns (dynamic IP)..." - if [ -z "$freedns_key" ] - then - print_info "freedns was not started because 'freedns_key' is empty in $configfile" - else - if [ -n "$selfhost_user" ] - then - die "You can not use freeDNS AND selfHOST for dynamic IP updates ('freedns_key' AND 'selfhost_user' set in $configfile)" - fi - wget --no-check-certificate -O - http://freedns.afraid.org/dynamic/update.php?$freedns_key - fi -} - -function install_run_selfhost { - print_info "install and start selfhost (dynamic IP)..." - if [ -z "$selfhost_user" ] - then - print_info "selfHOST was not started because 'selfhost_user' is empty in $configfile" - else - if [ -n "$freedns_key" ] - then - die "You can not use freeDNS AND selfHOST for dynamic IP updates ('freedns_key' AND 'selfhost_user' set in $configfile)" - fi - if [ -z "$selfhost_pass" ] - then - die "selfHOST was not started because 'selfhost_pass' is empty in $configfile" - fi - if [ ! -d $selfhostdir ] - then - mkdir $selfhostdir - fi - # the old way - # https://carol.selfhost.de/update?username=123456&password=supersafe - # - # the prefered way - wget --output-document=$selfhostdir/$selfhostscript http://jonaspasche.de/selfhost-updater - echo "router" > $selfhostdir/device - echo "$selfhost_user" > $selfhostdir/user - echo "$selfhost_pass" > $selfhostdir/pass - bash $selfhostdir/$selfhostscript update - fi -} - -function ping_domain { - print_info "ping domain $domain..." - # Is the domain resolved? Try to ping 6 times à 10 seconds - COUNTER=0 - for i in {1..6} - do - print_info "loop $i for ping -c 1 $domain ..." - if ping -c 4 -W 1 $le_domain - then - print_info "$le_domain resolved" - break - else - if [ $i -gt 5 ] - then - die "Failed to: ping -c 1 $domain not resolved" - fi - fi - sleep 10 - done - sleep 5 -} - -function configure_cron_freedns { - print_info "configure cron for freedns..." - if [ -z "$freedns_key" ] - then - print_info "freedns is not configured because freedns_key is empty in $configfile" - else - # Use cron for dynamich ip update - # - at reboot - # - every 30 minutes - if [ -z "`grep 'freedns.afraid.org' /etc/crontab`" ] - then - echo "@reboot root http://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab - echo "*/30 * * * * root wget --no-check-certificate -O - http://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab - else - print_info "cron for freedns was configured already" - fi - fi -} - -function configure_cron_selfhost { - print_info "configure cron for selfhost..." - if [ -z "$selfhost_user" ] - then - print_info "selfhost is not configured because selfhost_key is empty in $configfile" - else - # Use cron for dynamich ip update - # - at reboot - # - every 5 minutes - if [ -z "`grep 'selfhost-updater.sh' /etc/crontab`" ] - then - echo "@reboot root bash /etc/selfhost/selfhost-updater.sh update > /dev/null 2>&1" >> /etc/crontab - echo "*/5 * * * * root /bin/bash /etc/selfhost/selfhost-updater.sh update > /dev/null 2>&1" >> /etc/crontab - else - print_info "cron for selfhost was configured already" - fi - fi -} - -function install_letsencrypt { - print_info "installing let's encrypt ..." - # check if user gave domain - if [ -z "$le_domain" ] - then - die "Failed to install let's encrypt: 'le_domain' is empty in $configfile" - fi - if [ -z "$le_email" ] - then - die "Failed to install let's encrypt: 'le_email' is empty in $configfile" - fi - nocheck_install "certbot python-certbot-apache" - print_info "run certbot ..." - certbot --apache -w /var/www/html -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir - service apache2 restart -} - -function check_https { - print_info "checking httpS > testing ..." - url_https=https://$le_domain - wget_output=$(wget -nv --spider --max-redirect 0 $url_https) - if [ $? -ne 0 ] - then - print_warn "check not ok" - else - print_info "check ok" - fi -} - -function install_hubzilla { - print_info "installing addons..." - cd /var/www/html/ - if git remote -v | grep -i "origin.*hubzilla.*" - then - print_info "hubzilla" - util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons - elif git remote -v | grep -i "origin.*zap.*" - then - print_info "zap" - util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons - else - die "neither zap nor hubzilla repository > did not install addons or zap/hubzilla" - fi - mkdir -p "store/[data]/smarty3" - mkdir -p "store" - chmod -R 777 store - touch .htconfig.php - chmod ou+w .htconfig.php - cd /var/www/ - chown -R www-data:www-data html - chown root:www-data /var/www/html/ - chown root:www-data /var/www/html/.htaccess - chmod 0644 /var/www/html/.htaccess - print_info "installed addons" -} - -function install_rsync { - print_info "installing rsync..." - nocheck_install "rsync" -} - -function install_cryptosetup { - print_info "installing cryptsetup..." - nocheck_install "cryptsetup" -} - -function configure_cron_daily { - print_info "configuring cron..." - # every 10 min for poller.php - if [ -z "`grep 'Master.php' /etc/crontab`" ] - then - echo "*/10 * * * * www-data cd /var/www/html; php Zotlabs/Daemon/Master.php Cron >> /dev/null 2>&1" >> /etc/crontab - fi - # Run external script daily at 05:30 - # - stop apache and mysql-server - # - renew the certificate of letsencrypt - # - backup db, files (/var/www/html), certificates if letsencrypt - # - update hubzilla core and addon - # - update and upgrade linux - # - reboot is done by "shutdown -h now" because "reboot" hangs sometimes depending on the system -echo "#!/bin/sh" > /var/www/$hubzilladaily -echo "#" >> /var/www/$hubzilladaily -echo "echo \" \"" >> /var/www/$hubzilladaily -echo "echo \"+++ \$(date) +++\"" >> /var/www/$hubzilladaily -echo "echo \" \"" >> /var/www/$hubzilladaily -echo "echo \"\$(date) - renew certificate...\"" >> /var/www/$hubzilladaily -echo "certbot renew --noninteractive" >> /var/www/$hubzilladaily -echo "#" >> /var/www/$hubzilladaily -echo "echo \"\$(date) - stopping apache and mysql...\"" >> /var/www/$hubzilladaily -echo "service apache2 stop" >> /var/www/$hubzilladaily -echo "/etc/init.d/mysql stop # to avoid inconsistencies" >> /var/www/$hubzilladaily -echo "#" >> /var/www/$hubzilladaily -echo "# backup" >> /var/www/$hubzilladaily -echo "echo \"\$(date) - try to mount external device for backup...\"" >> /var/www/$hubzilladaily -echo "backup_device_name=$backup_device_name" >> /var/www/$hubzilladaily -echo "backup_device_pass=$backup_device_pass" >> /var/www/$hubzilladaily -echo "backup_mount_point=$backup_mount_point" >> /var/www/$hubzilladaily -echo "device_mounted=0" >> /var/www/$hubzilladaily -echo "if [ -n \"$backup_device_name\" ]" >> /var/www/$hubzilladaily -echo "then" >> /var/www/$hubzilladaily -echo " if blkid | grep $backup_device_name" >> /var/www/$hubzilladaily -echo " then" >> /var/www/$hubzilladaily - if [ -n "$backup_device_pass" ] - then -echo " echo \"decrypting backup device...\"" >> /var/www/$hubzilladaily -echo " echo "\"$backup_device_pass\"" | cryptsetup luksOpen $backup_device_name cryptobackup" >> /var/www/$hubzilladaily - fi -echo " if [ ! -d $backup_mount_point ]" >> /var/www/$hubzilladaily -echo " then" >> /var/www/$hubzilladaily -echo " mkdir $backup_mount_point" >> /var/www/$hubzilladaily -echo " fi" >> /var/www/$hubzilladaily -echo " echo \"mounting backup device...\"" >> /var/www/$hubzilladaily - if [ -n "$backup_device_pass" ] - then -echo " if mount /dev/mapper/cryptobackup $backup_mount_point" >> /var/www/$hubzilladaily - else -echo " if mount $backup_device_name $backup_mount_point" >> /var/www/$hubzilladaily - fi -echo " then" >> /var/www/$hubzilladaily -echo " device_mounted=1" >> /var/www/$hubzilladaily -echo " echo \"device $backup_device_name is now mounted. Starting backup...\"" >> /var/www/$hubzilladaily -echo " rsync -a --delete /var/lib/mysql/ /media/hubzilla_backup/mysql" >> /var/www/$hubzilladaily -echo " rsync -a --delete /var/www/ /media/hubzilla_backup/www" >> /var/www/$hubzilladaily -echo " rsync -a --delete /etc/letsencrypt/ /media/hubzilla_backup/letsencrypt" >> /var/www/$hubzilladaily -echo " echo \"\$(date) - disk sizes...\"" >> /var/www/$hubzilladaily -echo " df -h" >> /var/www/$hubzilladaily -echo " echo \"\$(date) - db size...\"" >> /var/www/$hubzilladaily -echo " du -h $backup_mount_point | grep mysql/hubzilla" >> /var/www/$hubzilladaily -echo " echo \"unmounting backup device...\"" >> /var/www/$hubzilladaily -echo " umount $backup_mount_point" >> /var/www/$hubzilladaily -echo " else" >> /var/www/$hubzilladaily -echo " echo \"failed to mount device $backup_device_name\"" >> /var/www/$hubzilladaily -echo " fi" >> /var/www/$hubzilladaily - if [ -n "$backup_device_pass" ] - then -echo " echo \"closing decrypted backup device...\"" >> /var/www/$hubzilladaily -echo " cryptsetup luksClose cryptobackup" >> /var/www/$hubzilladaily - fi -echo " fi" >> /var/www/$hubzilladaily -echo "fi" >> /var/www/$hubzilladaily -echo "if [ \$device_mounted == 0 ]" >> /var/www/$hubzilladaily -echo "then" >> /var/www/$hubzilladaily -echo " echo \"device could not be mounted $backup_device_name. No backup written.\"" >> /var/www/$hubzilladaily -echo "fi" >> /var/www/$hubzilladaily -echo "#" >> /var/www/$hubzilladaily -echo "echo \"\$(date) - db size...\"" >> /var/www/$hubzilladaily -echo "du -h /var/lib/mysql/ | grep mysql/hubzilla" >> /var/www/$hubzilladaily -echo "#" >> /var/www/$hubzilladaily -echo "# update" >> /var/www/$hubzilladaily -echo "echo \"\$(date) - updating core and addons...\"" >> /var/www/$hubzilladaily -echo "(cd /var/www/html/ ; util/udall)" >> /var/www/$hubzilladaily -echo "chown -R www-data:www-data /var/www/html/ # make all accessable for the webserver" >> /var/www/$hubzilladaily -echo "chown root:www-data /var/www/html/.htaccess" >> /var/www/$hubzilladaily -echo "chmod 0644 /var/www/html/.htaccess # www-data can read but not write it" >> /var/www/$hubzilladaily -echo "echo \"\$(date) - updating linux...\"" >> /var/www/$hubzilladaily -echo "apt-get -q -y update && apt-get -q -y dist-upgrade && apt-get -q -y autoremove # update linux and upgrade" >> /var/www/$hubzilladaily -echo "echo \"\$(date) - Backup and update finished. Rebooting...\"" >> /var/www/$hubzilladaily -echo "#" >> /var/www/$hubzilladaily -echo "shutdown -r now" >> /var/www/$hubzilladaily - - if [ -z "`grep 'hubzilla-daily.sh' /etc/crontab`" ] - then - echo "30 05 * * * root /bin/bash /var/www/$hubzilladaily >> /var/www/html/hubzilla-daily.log 2>&1" >> /etc/crontab - echo "0 0 1 * * root rm /var/www/html/hubzilla-daily.log" >> /etc/crontab - fi - - # This is active after either "reboot" or "/etc/init.d/cron reload" - print_info "configured cron for updates/upgrades" -} - -######################################################################## -# START OF PROGRAM -######################################################################## -export PATH=/bin:/usr/bin:/sbin:/usr/sbin - -check_sanity - -# Read config file edited by user -configfile=hubzilla-config.txt -source $configfile - -selfhostdir=/etc/selfhost -selfhostscript=selfhost-updater.sh -hubzilladaily=hubzilla-daily.sh -backup_mount_point=/media/hubzilla_backup - -#set -x # activate debugging from here - -check_config -stop_hubzilla -update_upgrade -install_curl -install_wget -install_sendmail -install_apache -install_imagemagick -install_php -install_mysql -install_adminer -create_hubzilla_db -run_freedns -install_run_selfhost -ping_domain -configure_cron_freedns -configure_cron_selfhost - -if [ "$le_domain" != "localhost" ] -then - install_letsencrypt - check_https -else - print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https" -fi - -install_hubzilla - -configure_cron_daily - -if [ "$le_domain" != "localhost" ] -then - install_cryptosetup - install_rsync -else - print_info "is localhost - skipped installation of cryptosetup" -fi - - -#set +x # stop debugging from here - - diff --git a/.homeinstall/nginx-zotserver.conf.template b/.homeinstall/nginx-zotserver.conf.template new file mode 100644 index 000000000..c77788a1b --- /dev/null +++ b/.homeinstall/nginx-zotserver.conf.template @@ -0,0 +1,144 @@ +## +# Hubzilla/Zap/Mistpark/Osada Nginx block configuration template +# based on the example created by Olaf Conradi +# +# The files generated with this template will be added to +# /etc/nginx/sites-available & /etc/nginx/sites-enabled (symlink) +## + +## +# You should look at the following URL's in order to grasp a solid understanding +# of Nginx configuration files in order to fully unleash the power of Nginx. +# +# http://wiki.nginx.org/Pitfalls +# http://wiki.nginx.org/QuickStart +# http://wiki.nginx.org/Configuration +## + +## +# This configuration assumes +# You filled the zotserver-config.txt file +# Your domain/subdomain is functionnal +# You want all traffic to be https +# You have PHP FastCGI Process Manager (php-fpm) running on localhost +## + +server { + listen 80; + server_name SERVER_NAME; + +# HTTP > HTTPS # + return 301 https://$server_name$request_uri; +} + +## +# Configure Red with SSL +# +# All requests are routed to the front controller +# except for certain known file types like images, css, etc. +# Those are served statically whenever possible with a +# fall back to the front controller (needed for avatars, for example) +## + +server { + listen 443 ssl; + server_name SERVER_NAME; + + ssl on; + ssl_certificate /etc/letsencrypt/live/SERVER_NAME/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/SERVER_NAME/privkey.pem; + ssl_session_timeout 5m; +# DO WE NEED TO REVIEW THE FOLLOWING SETTINGS? + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS; + ssl_prefer_server_ciphers on; + + fastcgi_param HTTPS on; + + charset utf-8; + root INSTALL_PATH; + index index.php; + access_log /var/log/nginx/ZOTSERVER_LOG; + + #Uncomment the following line to include a standard configuration file + #Note that the most specific rule wins and your standard configuration + #will therefore *add* to this file, but not override it. + #include standard.conf + + # allow uploads up to 20MB in size + client_max_body_size 20m; + client_body_buffer_size 128k; + + include mime.types; + + # rewrite to front controller as default rule + location / { + if (!-e $request_filename) { + rewrite ^(.*)$ /index.php?req=$1; + } + } + + # make sure webfinger and other well known services aren't blocked + # by denying dot files and rewrite request to the front controller + location ^~ /.well-known/ { + allow all; + if (!-e $request_filename) { + rewrite ^(.*)$ /index.php?req=$1; + } + } + + # statically serve these file types when possible + # otherwise fall back to front controller + # allow browser to cache them + # added .htm for advanced source code editor library + # location ~* \.(jpg|jpeg|gif|png|ico|css|js|htm|html|map|ttf|woff|woff2|svg)$ { + # expires 30d; + # try_files $uri /index.php?req=$uri&$args; + # } + # SHOULD WE UNCOMMENT THE ABOVE LINES ? + + # block these file types + location ~* \.(tpl|md|tgz|log|out)$ { + deny all; + } + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # or a unix socket + location ~* \.php$ { + # IS THE FOLLOWING STILL RELEVANT AS OF AUGUST 2020? + # Zero-day exploit defense. + # http://forum.nginx.org/read.php?2,88845,page=3 + # Won't work properly (404 error) if the file is not stored on this + # server, which is entirely possible with php-fpm/php-fcgi. + # Comment the 'try_files' line out if you set up php-fpm/php-fcgi on + # another machine. And then cross your fingers that you won't get hacked. + try_files $uri =404; + + # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini + fastcgi_split_path_info ^(.+\.php)(/.+)$; + + # With php5-cgi alone: + # fastcgi_pass 127.0.0.1:9000; + + # With php-fpm: + fastcgi_pass unix:PHP_FPM_SOCK; + + include fastcgi_params; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + } + + # deny access to all dot files + location ~ /\. { + deny all; + } + +#deny access to store + + location ~ /store { + deny all; + } + + +} + diff --git a/.homeinstall/zotserver-config.txt.template b/.homeinstall/zotserver-config.txt.template new file mode 100644 index 000000000..39a6e77ff --- /dev/null +++ b/.homeinstall/zotserver-config.txt.template @@ -0,0 +1,178 @@ +############################################### +### MANDATORY - database password ############# +# +# Please give your database password +# It is better to not use blanks inside the password. +# Example: db_pass=pass_word_with_no_blanks_in_it +db_pass= + +############################################### +### MANDATORY - let's encrypt ################# +# +# Zot requires encrypted communication via secure HTTP (HTTPS). +# This script automates installation of an SSL certificate from +# Let's Encrypt (https://letsencrypt.org) +# +# Please give the domain name of your hub/instance +# +# Example: my.cooldomain.org +# Example: cooldomain.org +# +# You might use "localhost" for a LOCAL TEST installation. +# This is usefull if you want to debug the server inside a VM. +# +# Example: localhost +# +# Email is optional if you use "localhost". +# +# +le_domain= +le_email= + +############################################### +### OPTIONAL - Webserver choice ############### +# +# Please indicate if you want to choose Nginx +# or Apache as your web server +# +# Valid strings are nginx or apache (lower case), +# any other will stop the setup script. +# +webserver=apache + + +############################################### +### OPTIONAL - selfHOST - dynamic IP address ## +# +# 1. Register a domain at selfhost.de +# - choose offer "DOMAIN dynamisch" 1,50€/mon at 04/2019 +# 2. Get your configuration for dynamic IP update +# - Log in at selfhost.de +# - go to "DynDNS Accounte" +# - klick "Details" of your (freshly) registered domain +# - You will find the configuration there +# - Benutzername (user name) > use this for "selfhost_user=" +# - Passwort (pass word) > use this for "selfhost_pass=" +# +# +selfhost_user= +selfhost_pass= + +############################################### +### OPTIONAL - FreeDNS - dynamic IP address ### +# +# Please give the alpha-numeric-key of freedns +# +# Get a free subdomain from freedns and use it for your dynamic ip address +# Documentation under http://www.techjawab.com/2013/06/setup-dynamic-dns-dyndns-for-free-on.html +# +# - Register for a Free domain at http://freedns.afraid.org/signup/ +# - WATCH THIS: Make sure you choose a domain with as less subdomains as +# possible. Why? Let's encrpyt issues a limited count of certificates each +# day. Possible other users of this domain will try to issue a certificate +# at the same day. +# - Logon to FreeDNS (where you just registered) +# - Goto http://freedns.afraid.org/dynamic/ +# - Right click on "Direct Link" and copy the URL and paste it somewhere. +# - You should notice a large and unique alpha-numeric key in the URL +# +# http://freedns.afraid.org/dynamic/update.php?alpha-numeric-key +# +# Provided your url from freedns is +# +# http://freedns.afraid.org/dynamic/update.php?U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5 +# +# Then you have to provide +# +# freedns_key=U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5 +# +# +freedns_key= + + +############################################### +### OPTIONAL - Backup to external device ###### +# +# The script can use an external device for the daily backup. +# The file system of the device (USB stick for example) must be compatible with +# +# - encrypted LUKS + ext4, or +# - ext4 +# +# You should test to mount the device before you run the script +# (hubzilla-setup.sh). +# How to find your (pluged-in) devices? +# +# fdisk -l +# +# Provided your device was listed as is /dev/sdb1. You could check with: +# +# blkid | grep /dev/sdb1 +# +# Try to decrypt +# (You might install cryptsetup befor using apt-get install. +# +# apt-get install cryptsetup +# cryptsetup luksOpen /dev/sdb1 cryptobackup +# +# Try to mount +# You might create the directory /media/hubzilla_backup it it does not exist +# using mkdir. +# +# mkdir /media/hubzilla_backup +# mount /dev/mapper/cryptobackup /media/hubzilla_backup +# +# Unmounting device goes like this +# +# umount /media/hubzilla_backup +# cryptsetup luksClose cryptobackup +# +# To check if still mounted +# +# lsof /media/hubzilla_backup +# +# If you leave the following parameters +# +# - "backup_device_name" and +# - "backup_device_pass" +# +# empty the script will create daily backups on the internal disk (which could +# save you as well). +# +# Example: backup_device_name=/dev/sdc1 +# +# Leave "backup_device_pass=" empty if the external device is not encrypted. +# +backup_device_name= +backup_device_pass= + + +############################################### +### OPTIONAL - do not mess with things below ## +# (...if you are not certain) +# +# Usually you are done here +# Everything below is OPTIONAL +# +############################################### +# +# Database for your hub/instance +# If left empty, both your database and user will be named after your zot instance (hubzilla, zap or misty) +# Use custom name, at least fo the database, if you plan to run more than one hub/instance on the same server +# +zotserver_db_name= +zotserver_db_user= +zotserver_db_pass=$db_pass +# +# +# Password for package mysql-server +# Example: mysqlpass=aberhallo +# Example: mysqlpass="aber hallo has blanks in it" +# +mysqlpass=$db_pass + +# Password for package phpmyadmin +# Example: phpmyadminpass=aberhallo +# Example: phpmyadminpass="aber hallo has blanks in it" +phpmyadminpass=$db_pass + diff --git a/.homeinstall/zotserver-setup.sh b/.homeinstall/zotserver-setup.sh new file mode 100755 index 000000000..42ff6685d --- /dev/null +++ b/.homeinstall/zotserver-setup.sh @@ -0,0 +1,793 @@ +#!/bin/bash +# +# How to use +# ---------- +# +# This file automates the installation of +# - hubzilla: https://zotlabs.org/page/hubzilla/hubzilla-project and +# - zap: https://zotlabs.com/zap/ +# - misty : https://zotlabs.com/misty/ +# - osada : https://codeberg.org/zot/osada +# - redmatrix : https://codeberg.org/zot/redmatrix +# under Debian Linux "Buster" +# +# 1) Copy the file "zotserver-config.txt.template" to "zotserver-config.txt" +# Follow the instuctions there +# +# 2) Switch to user "root" by typing "su -" +# +# 3) Run with "./zotserver-setup.sh" +# If this fails check if you can execute the script. +# - To make it executable type "chmod +x zotserver-setup.sh" +# - or run "bash zotserver-setup.sh" +# +# +# What does this script do basically? +# ----------------------------------- +# +# This file automates the installation of a Zot hub/instance under Debian Linux +# - install +# * apache webserver, +# * php, +# * mariadb - the database for zotserver, +# * adminer, +# * git to download and update addons +# - configure cron +# * "Run.php" for regular background processes of your Zot hub/instance +# * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date +# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org +# * backup your server's database and files (rsync) +# - run letsencrypt to create, register and use a certifacte for https +# +# +# Discussion +# ---------- +# +# Security - password is the same for mysql-server, phpmyadmin and your hub/instance db +# - The script runs into installation errors for phpmyadmin if it uses +# different passwords. For the sake of simplicity one single password. +# +# How to restore from backup +# -------------------------- +# +# (Some explanations here would certainly be useful) +# +# Daily backup +# ------------ +# +# The installation +# - writes a shell script in /var/www/ +# - creates a daily cron that runs this script +# +# The script makes a (daily) backup of all relevant files +# - /var/lib/mysql/ > database +# - /var/www/ > hubzilla/zap/misty from git repository +# - /etc/letsencrypt/ > certificates +# +# The backup will be written on an external disk compatible to LUKS+ext4 (see zotserver-config.txt) +# +# How to restore from backup +# -------------------------- +# +# (Some explanations here would certainly be useful) +# +# +# Credits +# ------- +# +# The script is based on Thomas Willinghams script "debian-setup.sh" +# which he used to install the red#matrix. +# +# The documentation for bash is here +# https://www.gnu.org/software/bash/manual/bash.html +# +function check_sanity { + # Do some sanity checking. + print_info "Sanity check..." + if [ $(/usr/bin/id -u) != "0" ] + then + die 'Must be run by root user' + fi + + if [ -f /etc/lsb-release ] + then + die "Distribution is not supported" + fi + if [ ! -f /etc/debian_version ] + then + die "Debian is supported only" + fi + if ! grep -q 'Linux 10' /etc/issue + then + die "Linux 10 (buster) is supported only"x + fi +} + +function check_config { + print_info "config check..." + # Check for required parameters + if [ -z "$db_pass" ] + then + die "db_pass not set in $configfile" + fi + if [ -z "$le_domain" ] + then + die "le_domain not set in $configfile" + fi + # backup is important and should be checked + if [ -n "$backup_device_name" ] + then + if [ ! -d "$backup_mount_point" ] + then + mkdir "$backup_mount_point" + fi + device_mounted=0 + if fdisk -l | grep -i "$backup_device_name.*linux" + then + print_info "ok - filesystem of external device is linux" + if [ -n "$backup_device_pass" ] + then + echo "$backup_device_pass" | cryptsetup luksOpen $backup_device_name cryptobackup + if mount /dev/mapper/cryptobackup /media/zotserver_backup + then + device_mounted=1 + print_info "ok - could encrypt and mount external backup device" + umount /media/zotserver_backup + else + print_warn "backup to external device will fail because encryption failed" + fi + cryptsetup luksClose cryptobackup + else + if mount $backup_device_name /media/zotserver_backup + then + device_mounted=1 + print_info "ok - could mount external backup device" + umount /media/zotserver_backup + else + print_warn "backup to external device will fail because mount failed" + fi + fi + else + print_warn "backup to external device will fail because filesystem is either not linux or 'backup_device_name' is not correct in $configfile" + fi + if [ $device_mounted == 0 ] + then + die "backup device not ready" + fi + fi +} + +function die { + echo "ERROR: $1" > /dev/null 1>&2 + exit 1 +} + + +function update_upgrade { + print_info "updated and upgrade..." + # Run through the apt-get update/upgrade first. This should be done before + # we try to install any package + apt-get -q -y update && apt-get -q -y dist-upgrade + print_info "updated and upgraded linux" +} + +function check_install { + if [ -z "`which "$1" 2>/dev/null`" ] + then + # export DEBIAN_FRONTEND=noninteractive ... answers from the package + # configuration database + # - q ... without progress information + # - y ... answer interactive questions with "yes" + # DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -q -y install $2 + DEBIAN_FRONTEND=noninteractive apt-get -q -y install $2 + print_info "installed $2 installed for $1" + else + print_warn "$2 already installed" + fi +} + +function nocheck_install { + # export DEBIAN_FRONTEND=noninteractive ... answers from the package configuration database + # - q ... without progress information + # - y ... answer interactive questions with "yes" + # DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -q -y install $2 + # DEBIAN_FRONTEND=noninteractive apt-get --install-suggests -q -y install $1 + DEBIAN_FRONTEND=noninteractive apt-get -q -y install $1 + print_info "installed $1" +} + + +function print_info { + echo -n -e '\e[1;34m' + echo -n $1 + echo -e '\e[0m' +} + +function print_warn { + echo -n -e '\e[1;31m' + echo -n $1 + echo -e '\e[0m' +} + +function stop_zotserver { + if [ $webserver = "nginx" ] + then + print_info "stopping nginx webserver..." + systemctl stop nginx + elif [ $webserver = "apache" ] + then + print_info "stopping apache webserver..." + systemctl stop apache2 + fi + print_info "stopping mysql db..." + systemctl stop mariadb +} + +function install_apache { + print_info "installing apache..." + nocheck_install "apache2 apache2-utils" + a2enmod rewrite + systemctl restart apache2 +} + +function install_nginx { + print_info "installing nginx..." + nocheck_install "nginx" + systemctl restart nginx +} + +function add_vhost { + print_info "adding apache vhost" + echo "" >> "/etc/apache2/sites-available/${le_domain}.conf" + echo "ServerName ${le_domain}" >> "/etc/apache2/sites-available/${le_domain}.conf" + echo "DocumentRoot $install_path" >> "/etc/apache2/sites-available/${le_domain}.conf" + echo "" >> "/etc/apache2/sites-available/${le_domain}.conf" + a2ensite $le_domain +} + +function add_nginx_block { + print_info "adding nginx block" + sed "s|SERVER_NAME|${le_domain}|g;s|INSTALL_PATH|${install_path}|g;s|ZOTSERVER_LOG|${install_folder}-${zotserver}.log|;s|PHP_FPM_SOCK|$(ls /var/run/php/*sock)|;" nginx-zotserver.conf.template >> /etc/nginx/sites-enabled/${le_domain}.conf + ln -s /etc/nginx/sites-enabled/${le_domain}.conf /etc/nginx/sites-available/ +} + +function install_imagemagick { + print_info "installing imagemagick..." + nocheck_install "imagemagick" +} + +function install_curl { + print_info "installing curl..." + nocheck_install "curl" +} + +function install_wget { + print_info "installing wget..." + nocheck_install "wget" +} + +function install_sendmail { + print_info "installing sendmail..." + nocheck_install "sendmail sendmail-bin" +} + +function install_php { + # openssl and mbstring are included in libapache2-mod-php + print_info "installing php..." + if [ $webserver = "nginx" ] + then + nocheck_install "php php-pear php-curl php-gd php-mbstring php-xml php-zip php-fpm" + sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.3/fpm/php.ini + sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/fpm/php.ini + systemctl reload php7.3-fpm + elif [ $webserver = "apache" ] + then + nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mbstring php-xml php-zip" + sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.3/apache2/php.ini + sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/apache2/php.ini + fi +} + +function install_mysql { + print_info "installing mysql..." + if [ -z "$mysqlpass" ] + then + die "mysqlpass not set in $configfile" + fi + if type mysql ; then + echo "Yes, mysql is installed" + else + echo "mariadb-server" + nocheck_install "mariadb-server" + systemctl status mariadb + systemctl start mariadb + mysql --user=root <<_EOF_ +UPDATE mysql.user SET Password=PASSWORD('${mysqlpass}') WHERE User='root'; +DELETE FROM mysql.user WHERE User=''; +DROP DATABASE IF EXISTS test; +DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'; +FLUSH PRIVILEGES; +_EOF_ + fi +} + +function install_adminer { + print_info "installing adminer..." + nocheck_install "adminer" + if [ ! -f /etc/adminer/adminer.conf ] + then + echo "Alias /adminer /usr/share/adminer/adminer" > /etc/adminer/adminer.conf + ln -s /etc/adminer/adminer.conf /etc/apache2/conf-available/adminer.conf + else + print_info "file /etc/adminer/adminer.conf exists already" + fi + + a2enmod rewrite + + if [ ! -f /etc/apache2/apache2.conf ] + then + die "could not find file /etc/apache2/apache2.conf" + fi + sed -i \ + "s/AllowOverride None/AllowOverride all/" \ + /etc/apache2/apache2.conf + + a2enconf adminer + systemctl restart mariadb + systemctl reload apache2 +} + +function create_zotserver_db { + print_info "creating zotserver database..." + if [ -z "$zotserver_db_name" ] + then + zotserver_db_name=$zotserver + fi + if [ -z "$zotserver_db_user" ] + then + zotserver_db_user=$zotserver + fi + if [ -z "$zotserver_db_pass" ] + then + die "zotserver_db_pass not set in $configfile" + fi + systemctl restart mariadb + # Make sure we don't write over an already existing database if we install more than one Zot hub/instance + if [ -z $(mysql -h localhost -u root -p$mysqlpass -e "SHOW DATABASES;" | grep $zotserver_db_name) ] + then + Q1="CREATE DATABASE IF NOT EXISTS $zotserver_db_name;" + Q2="GRANT USAGE ON *.* TO $zotserver_db_user@localhost IDENTIFIED BY '$zotserver_db_pass';" + Q3="GRANT ALL PRIVILEGES ON $zotserver_db_name.* to $zotserver_db_user@localhost identified by '$zotserver_db_pass';" + Q4="FLUSH PRIVILEGES;" + SQL="${Q1}${Q2}${Q3}${Q4}" + mysql -uroot -p$mysqlpass -e "$SQL" + else + die "Can't write over an already existing database!" + fi +} + +function run_freedns { + print_info "run freedns (dynamic IP)..." + if [ -z "$freedns_key" ] + then + print_info "freedns was not started because 'freedns_key' is empty in $configfile" + else + if [ -n "$selfhost_user" ] + then + die "You can not use freeDNS AND selfHOST for dynamic IP updates ('freedns_key' AND 'selfhost_user' set in $configfile)" + fi + wget --no-check-certificate -O - http://freedns.afraid.org/dynamic/update.php?$freedns_key + fi +} + +function install_run_selfhost { + print_info "install and start selfhost (dynamic IP)..." + if [ -z "$selfhost_user" ] + then + print_info "selfHOST was not started because 'selfhost_user' is empty in $configfile" + else + if [ -n "$freedns_key" ] + then + die "You can not use freeDNS AND selfHOST for dynamic IP updates ('freedns_key' AND 'selfhost_user' set in $configfile)" + fi + if [ -z "$selfhost_pass" ] + then + die "selfHOST was not started because 'selfhost_pass' is empty in $configfile" + fi + if [ ! -d $selfhostdir ] + then + mkdir $selfhostdir + fi + # the old way + # https://carol.selfhost.de/update?username=123456&password=supersafe + # + # the prefered way + wget --output-document=$selfhostdir/$selfhostscript http://jonaspasche.de/selfhost-updater + echo "router" > $selfhostdir/device + echo "$selfhost_user" > $selfhostdir/user + echo "$selfhost_pass" > $selfhostdir/pass + bash $selfhostdir/$selfhostscript update + fi +} + +function ping_domain { + print_info "ping domain $domain..." + # Is the domain resolved? Try to ping 6 times à 10 seconds + COUNTER=0 + for i in {1..6} + do + print_info "loop $i for ping -c 1 $domain ..." + if ping -c 4 -W 1 $le_domain + then + print_info "$le_domain resolved" + break + else + if [ $i -gt 5 ] + then + die "Failed to: ping -c 1 $domain not resolved" + fi + fi + sleep 10 + done + sleep 5 +} + +function configure_cron_freedns { + print_info "configure cron for freedns..." + if [ -z "$freedns_key" ] + then + print_info "freedns is not configured because freedns_key is empty in $configfile" + else + # Use cron for dynamich ip update + # - at reboot + # - every 30 minutes + if [ -z "`grep 'freedns.afraid.org' /etc/crontab`" ] + then + echo "@reboot root http://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab + echo "*/30 * * * * root wget --no-check-certificate -O - http://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab + else + print_info "cron for freedns was configured already" + fi + fi +} + +function configure_cron_selfhost { + print_info "configure cron for selfhost..." + if [ -z "$selfhost_user" ] + then + print_info "selfhost is not configured because selfhost_key is empty in $configfile" + else + # Use cron for dynamich ip update + # - at reboot + # - every 5 minutes + if [ -z "`grep 'selfhost-updater.sh' /etc/crontab`" ] + then + echo "@reboot root bash /etc/selfhost/selfhost-updater.sh update > /dev/null 2>&1" >> /etc/crontab + echo "*/5 * * * * root /bin/bash /etc/selfhost/selfhost-updater.sh update > /dev/null 2>&1" >> /etc/crontab + else + print_info "cron for selfhost was configured already" + fi + fi +} + +function install_letsencrypt { + print_info "installing let's encrypt ..." + # check if user gave domain + if [ -z "$le_domain" ] + then + die "Failed to install let's encrypt: 'le_domain' is empty in $configfile" + fi + if [ -z "$le_email" ] + then + die "Failed to install let's encrypt: 'le_email' is empty in $configfile" + fi + if [ $webserver = "nginx" ] + then + nocheck_install "certbot" + print_info "run certbot..." + systemctl stop nginx + certbot certonly --standalone -d $le_domain -m $le_email --agree-tos --non-interactive + systemctl start nginx + elif [ $webserver = "apache" ] + then + nocheck_install "certbot python-certbot-apache" + print_info "run certbot ..." + certbot --apache -w $install_path -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir + service apache2 restart + fi +} + +function check_https { + print_info "checking httpS > testing ..." + url_https=https://$le_domain + wget_output=$(wget -nv --spider --max-redirect 0 $url_https) + if [ $? -ne 0 ] + then + print_warn "check not ok" + else + print_info "check ok" + fi +} + +function zotserver_name { + if git remote -v | grep -i "origin.*hubzilla.*" + then + zotserver=hubzilla + elif git remote -v | grep -i "origin.*zap.*" + then + zotserver=zap + elif git remote -v | grep -i "origin.*misty.*" + then + zotserver=misty + elif git remote -v | grep -i "origin.*osada.*" + then + zotserver=osada + elif git remote -v | grep -i "origin.*redmatrix.*" + then + zotserver=redmatrix + else + die "neither redmatrix, osada, misty, zap nor hubzilla repository > did not install redmatrix/osada/misty/zap/hubzilla" + fi +} + +function install_zotserver { + print_info "installing addons..." + cd $install_path/ + if [ $zotserver = "hubzilla" ] + then + print_info "hubzilla" + util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons + elif [ $zotserver = "zap" ] + then + print_info "zap" + util/add_addon_repo https://codeberg.org/zot/zap-addons.git zaddons + elif [ $zotserver = "misty" ] + then + print_info "misty" + util/add_addon_repo https://codeberg.org/zot/misty-addons.git maddons + elif [ $zotserver = "osada" ] + then + print_info "osada" + util/add_addon_repo https://codeberg.org/zot/osada-addons.git oaddons + elif [ $zotserver = "redmatrix" ] + then + print_info "redmatrix" + util/add_addon_repo https://codeberg.org/zot/redmatrix-addons.git raddons + else + die "neither redmatrix, osada, misty, zap nor hubzilla repository > did not install addons or redmatrix/osada/misty/zap/hubzilla" + fi + mkdir -p "cache/smarty3" + mkdir -p "store" + chmod -R 777 store + touch .htconfig.php + chmod ou+w .htconfig.php + cd /var/www/ + chown -R www-data:www-data $install_path + chown root:www-data $install_path/ + chown root:www-data $install_path/.htaccess + chmod 0644 $install_path/.htaccess + print_info "installed addons" +} + +function install_rsync { + print_info "installing rsync..." + nocheck_install "rsync" +} + +function install_cryptosetup { + print_info "installing cryptsetup..." + nocheck_install "cryptsetup" +} + +function configure_zotserverdaily { + echo "#!/bin/sh" >> /var/www/$zotserverdaily + echo "#" >> /var/www/$zotserverdaily + echo "# update of $le_domain Zot hub/instance" >> /var/www/$zotserverdaily + echo "echo \"\$(date) - updating core and addons...\"" >> /var/www/$zotserverdaily + echo "echo \"reaching git repository for $le_domain $zotserver hub/instance...\"" >> /var/www/$zotserverdaily + echo "(cd $install_path ; util/udall)" >> /var/www/$zotserverdaily + echo "chown -R www-data:www-data $install_path # make all accessible for the webserver" >> /var/www/$zotserverdaily + if [ $webserver = "apache" ] + then + echo "chown root:www-data $install_path/.htaccess" >> /var/www/$zotserverdaily + echo "chmod 0644 $install_path/.htaccess # www-data can read but not write it" >> /var/www/$zotserverdaily + fi + chmod a+x /var/www/$zotserverdaily +} + +function configure_cron_daily { + print_info "configuring cron..." + # every 10 min for poller.php + if [ -z "`grep '$install_path.*Run.php' /etc/crontab`" ] + then + echo "*/10 * * * * www-data cd $install_path; php Zotlabs/Daemon/Run.php Cron >> /dev/null 2>&1" >> /etc/crontab + fi + # Run external script daily at 05:30 + # - stop apache/nginx and mysql-server + # - renew the certificate of letsencrypt + # - backup db, files ($install_path), certificates if letsencrypt + # - update zotserver core and addon + # - update and upgrade linux + # - reboot is done by "shutdown -h now" because "reboot" hangs sometimes depending on the system + echo "#!/bin/sh" > /var/www/$zotcron + echo "#" >> /var/www/$zotcron + echo "echo \" \"" >> /var/www/$zotcron + echo "echo \"+++ \$(date) +++\"" >> /var/www/$zotcron + echo "echo \" \"" >> /var/www/$zotcron + echo "echo \"\$(date) - stopping $webserver and mysql...\"" >> /var/www/$zotcron + if [ $webserver = "nginx" ] + then + echo "systemctl stop nginx" >> /var/www/$zotcron + elif [ $webserver = "apache" ] + then + echo "service apache2 stop" >> /var/www/$zotcron + fi + echo "/etc/init.d/mysql stop # to avoid inconsistencies" >> /var/www/$zotcron + echo "#" >> /var/www/$zotcron + echo "echo \"\$(date) - renew certificate...\"" >> /var/www/$zotcron + echo "certbot renew --noninteractive" >> /var/www/$zotcron + echo "#" >> /var/www/$zotcron + echo "# backup" >> /var/www/$zotcron + echo "echo \"\$(date) - try to mount external device for backup...\"" >> /var/www/$zotcron + echo "backup_device_name=$backup_device_name" >> /var/www/$zotcron + echo "backup_device_pass=$backup_device_pass" >> /var/www/$zotcron + echo "backup_mount_point=$backup_mount_point" >> /var/www/$zotcron + echo "device_mounted=0" >> /var/www/$zotcron + echo "if [ -n \"\$backup_device_name\" ]" >> /var/www/$zotcron + echo "then" >> /var/www/$zotcron + echo " if blkid | grep $backup_device_name" >> /var/www/$zotcron + echo " then" >> /var/www/$zotcron + if [ -n "$backup_device_pass" ] + then + echo " echo \"decrypting backup device...\"" >> /var/www/$zotcron + echo " echo "\"$backup_device_pass\"" | cryptsetup luksOpen $backup_device_name cryptobackup" >> /var/www/$zotcron + fi + echo " if [ ! -d $backup_mount_point ]" >> /var/www/$zotcron + echo " then" >> /var/www/$zotcron + echo " mkdir $backup_mount_point" >> /var/www/$zotcron + echo " fi" >> /var/www/$zotcron + echo " echo \"mounting backup device...\"" >> /var/www/$zotcron + if [ -n "$backup_device_pass" ] + then + echo " if mount /dev/mapper/cryptobackup $backup_mount_point" >> /var/www/$zotcron + else + echo " if mount $backup_device_name $backup_mount_point" >> /var/www/$zotcron + fi + echo " then" >> /var/www/$zotcron + echo " device_mounted=1" >> /var/www/$zotcron + echo " echo \"device $backup_device_name is now mounted. Starting backup...\"" >> /var/www/$zotcron + echo " rsync -a --delete /var/lib/mysql/ /media/zotserver_backup/mysql" >> /var/www/$zotcron + echo " rsync -a --delete /var/www/ /media/zotserver_backup/www" >> /var/www/$zotcron + echo " rsync -a --delete /etc/letsencrypt/ /media/zotserver_backup/letsencrypt" >> /var/www/$zotcron + echo " echo \"\$(date) - disk sizes...\"" >> /var/www/$zotcron + echo " df -h" >> /var/www/$zotcron + echo " echo \"\$(date) - db size...\"" >> /var/www/$zotcron + echo " du -h $backup_mount_point | grep mysql/zotserver" >> /var/www/$zotcron + echo " echo \"unmounting backup device...\"" >> /var/www/$zotcron + echo " umount $backup_mount_point" >> /var/www/$zotcron + echo " else" >> /var/www/$zotcron + echo " echo \"failed to mount device $backup_device_name\"" >> /var/www/$zotcron + echo " fi" >> /var/www/$zotcron + if [ -n "$backup_device_pass" ] + then + echo " echo \"closing decrypted backup device...\"" >> /var/www/$zotcron + echo " cryptsetup luksClose cryptobackup" >> /var/www/$zotcron + fi + echo " fi" >> /var/www/$zotcron + echo "fi" >> /var/www/$zotcron + echo "if [ \$device_mounted == 0 ]" >> /var/www/$zotcron + echo "then" >> /var/www/$zotcron + echo " echo \"device could not be mounted $backup_device_name. No backup written.\"" >> /var/www/$zotcron + echo "fi" >> /var/www/$zotcron + echo "#" >> /var/www/$zotcron + echo "echo \"\$(date) - db size...\"" >> /var/www/$zotcron + echo "du -h /var/lib/mysql/ | grep mysql/" >> /var/www/$zotcron + echo "#" >> /var/www/$zotcron + echo "cd /var/www" >> /var/www/$zotcron + echo "for f in *-daily.sh; do \"./\${f}\"; done" >> /var/www/$zotcron + echo "echo \"\$(date) - updating linux...\"" >> /var/www/$zotcron + echo "apt-get -q -y update && apt-get -q -y dist-upgrade && apt-get -q -y autoremove # update linux and upgrade" >> /var/www/$zotcron + echo "echo \"\$(date) - Backup and update finished. Rebooting...\"" >> /var/www/$zotcron + echo "#" >> /var/www/$zotcron + echo "shutdown -r now" >> /var/www/$zotcron + + # If global cron job does not exist we add it to /etc/crontab + if grep -q $zotcron /etc/crontab + then + echo "cron job already in /etc/crontab" + else + echo "30 05 * * * root /bin/bash /var/www/$zotcron >> /var/www/zot-daily.log 2>&1" >> /etc/crontab + echo "0 0 1 * * root rm /var/www/zot-daily.log" >> /etc/crontab + fi + + # This is active after either "reboot" or cron reload" + systemctl restart cron + print_info "configured cron for updates/upgrades" +} + +######################################################################## +# START OF PROGRAM +######################################################################## +export PATH=/bin:/usr/bin:/sbin:/usr/sbin +check_sanity + +zotserver_name +print_info "We're installing a $zotserver instance" +install_path="$(dirname "$(pwd)")" +install_folder="$(basename $install_path)" + +# Read config file edited by user +configfile=zotserver-config.txt +source $configfile + +selfhostdir=/etc/selfhost +selfhostscript=selfhost-updater.sh +zotcron="zotcron.sh" +zotserverdaily="${install_folder}-${zotserver}-daily.sh" +backup_mount_point="/media/zotserver_backup" + +#set -x # activate debugging from here + +check_config +stop_zotserver +update_upgrade +install_curl +install_wget +install_sendmail +if [ $webserver = "nginx" ] +then + install_nginx +elif [ $webserver = "apache" ] +then + install_apache +else +die "Failed to install a Web server: 'webserver' not set to \"apache\" or \"nginx\" in $configfile" +fi +install_imagemagick +install_php +if [ $webserver = "nginx" ] +then + add_nginx_block +elif [ $webserver = "apache" ] +then + if [ "$install_path" != "/var/www/html" ] + then + add_vhost + fi +fi +install_mysql +if [ $webserver = "apache" ] +then +install_adminer +fi +create_zotserver_db +run_freedns +install_run_selfhost +ping_domain +configure_cron_freedns +configure_cron_selfhost + +if [ "$le_domain" != "localhost" ] +then + install_letsencrypt + check_https +else + print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https" +fi + +install_zotserver + +configure_zotserverdaily + +configure_cron_daily + +if [ "$le_domain" != "localhost" ] +then + install_cryptosetup + install_rsync +else + print_info "is localhost - skipped installation of cryptosetup" +fi + + +#set +x # stop debugging from here -- cgit v1.2.3