freedombone/src/freedombone-utils-web

942 lines
40 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
#
# .---. . .
# | | |
# |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-.
# | | (.-' (.-' ( | ( )| | | | )( )| | (.-'
# ' ' --' --' -' - -' ' ' -' -' -' ' - --'
#
# Freedom in the Cloud
#
# Web related functions
#
# License
# =======
#
# Copyright (C) 2014-2017 Bob Mottram <bob@freedombone.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# default search engine for command line browser
DEFAULT_SEARCH='https://searx.laquadrature.net'
# onion port for the default domain
DEFAULT_DOMAIN_ONION_PORT=8099
# Whether Let's Encrypt is enabled for all sites
LETSENCRYPT_ENABLED="yes"
LETSENCRYPT_SERVER='https://acme-v01.api.letsencrypt.org/directory'
# list of encryption protocols
SSL_PROTOCOLS="TLSv1 TLSv1.1 TLSv1.2"
# Mozilla recommended default ciphers. These work better on Android
# See https://wiki.mozilla.org/Security/Server_Side_TLS
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"
# some mobile apps (eg. NextCloud) have not very good cipher compatibility.
# These ciphers can be used for those cases
SSL_CIPHERS_MOBILE="ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA"
NGINX_ENSITE_REPO="https://github.com/perusio/nginx_ensite"
NGINX_ENSITE_COMMIT='fa4d72ce1c0a490442c8474e9c8dc21ed52c93d0'
# memory limit for php in MB
MAX_PHP_MEMORY=64
# logging level for Nginx
WEBSERVER_LOG_LEVEL='warn'
# test a domain name to see if it's valid
function validate_domain_name {
# count the number of dots in the domain name
dots=${TEST_DOMAIN_NAME//[^.]}
no_of_dots=${#dots}
if (( $no_of_dots > 3 )); then
TEST_DOMAIN_NAME=$"The domain $TEST_DOMAIN_NAME has too many subdomains. It should be of the type w.x.y.z, x.y.z or y.z"
fi
if (( $no_of_dots == 0 )); then
TEST_DOMAIN_NAME=$"The domain $TEST_DOMAIN_NAME has no top level domain. It should be of the type w.x.y.z, x.y.z or y.z"
fi
}
function nginx_disable_sniffing {
domain_name=$1
filename=/etc/nginx/sites-available/$domain_name
echo ' add_header X-Frame-Options DENY;' >> $filename
echo ' add_header X-Content-Type-Options nosniff;' >> $filename
echo '' >> $filename
}
function nginx_limits {
domain_name=$1
max_body='20m'
if [ $2 ]; then
max_body=$2
fi
filename=/etc/nginx/sites-available/$domain_name
echo " client_max_body_size ${max_body};" >> $filename
echo ' client_body_buffer_size 128k;' >> $filename
echo '' >> $filename
echo ' limit_conn conn_limit_per_ip 10;' >> $filename
echo ' limit_req zone=req_limit_per_ip burst=10 nodelay;' >> $filename
echo '' >> $filename
}
function nginx_stapling {
domain_name=$1
filename=/etc/nginx/sites-available/$domain_name
echo " ssl_stapling on;" >> $filename
echo ' ssl_stapling_verify on;' >> $filename
echo ' ssl_trusted_certificate /etc/ssl/certs/${domain_name}.pem;' >> $filename
echo '' >> $filename
}
function nginx_http_redirect {
# redirect port 80 to https
domain_name=$1
filename=/etc/nginx/sites-available/$domain_name
echo 'server {' > $filename
echo ' listen 80;' >> $filename
echo ' listen [::]:80;' >> $filename
echo " server_name ${domain_name};" >> $filename
echo " root /var/www/${domain_name}/htdocs;" >> $filename
echo ' access_log /dev/null;' >> $filename
echo " error_log /dev/null;" >> $filename
function_check nginx_limits
nginx_limits $domain_name
if [ ${#2} -gt 0 ]; then
echo " $2;" >> $filename
fi
echo ' rewrite ^ https://$server_name$request_uri? permanent;' >> $filename
echo '}' >> $filename
echo '' >> $filename
}
function nginx_compress {
domain_name=$1
filename=/etc/nginx/sites-available/$domain_name
echo ' gzip on;' >> $filename
echo ' gzip_min_length 1000;' >> $filename
echo ' gzip_proxied expired no-cache no-store private auth;' >> $filename
echo ' gzip_types text/plain application/xml;' >> $filename
}
function nginx_ssl {
# creates the SSL/TLS section for a website
domain_name=$1
mobile_ciphers=$2
filename=/etc/nginx/sites-available/$domain_name
echo ' ssl_stapling off;' >> $filename
echo ' ssl_stapling_verify off;' >> $filename
echo ' ssl on;' >> $filename
echo " ssl_certificate /etc/letsencrypt/live/${domain_name}/fullchain.pem;" >> $filename
echo " ssl_certificate_key /etc/letsencrypt/live/${domain_name}/privkey.pem;" >> $filename
echo " ssl_dhparam /etc/ssl/certs/${domain_name}.dhparam;" >> $filename
echo '' >> $filename
echo ' ssl_session_cache builtin:1000 shared:SSL:10m;' >> $filename
echo ' ssl_session_timeout 60m;' >> $filename
echo ' ssl_prefer_server_ciphers on;' >> $filename
echo " ssl_protocols $SSL_PROTOCOLS;" >> $filename
if [ $mobile_ciphers ]; then
echo " # Mobile compatible ciphers" >> $filename
echo " ssl_ciphers '$SSL_CIPHERS_MOBILE';" >> $filename
else
echo " ssl_ciphers '$SSL_CIPHERS';" >> $filename
fi
echo " add_header Content-Security-Policy \"default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'\";" >> $filename
echo ' add_header X-XSS-Protection "1; mode=block";' >> $filename
echo ' add_header X-Robots-Tag none;' >> $filename
echo ' add_header X-Download-Options noopen;' >> $filename
echo ' add_header X-Permitted-Cross-Domain-Policies none;' >> $filename
#nginx_stapling $1
}
function nginx_keybase {
# creates files suitable for keybase.io verification
domain_name=$1
filename=/etc/nginx/sites-available/$domain_name
echo '' >> $filename
echo " # make sure webfinger and other well known services aren't blocked" >> $filename
echo ' # by denying dot files and rewrite request to the front controller' >> $filename
echo ' location ^~ /.well-known/ {' >> $filename
echo ' allow all;' >> $filename
echo ' }' >> $filename
if [ ! -d /var/www/${domain_name}/htdocs/.well-known ]; then
mkdir -p /var/www/${domain_name}/htdocs/.well-known
fi
if [ ! -f /var/www/${domain_name}/htdocs/keybase.txt ]; then
touch /var/www/${domain_name}/htdocs/keybase.txt
fi
if [ ! -f /var/www/${domain_name}/htdocs/.well-known/keybase.txt ]; then
touch /var/www/${domain_name}/htdocs/.well-known/keybase.txt
fi
}
# check an individual domain name
function test_domain_name {
if [ $1 ]; then
TEST_DOMAIN_NAME=$1
if [[ $TEST_DOMAIN_NAME != 'ttrss' ]]; then
function_check validate_domain_name
validate_domain_name
if [[ $TEST_DOMAIN_NAME != $1 ]]; then
echo $"Invalid domain name $TEST_DOMAIN_NAME"
exit 8528
fi
fi
fi
}
# Checks whether certificates were generated for the given hostname
function check_certificates {
if [ ! $1 ]; then
return
fi
USE_LETSENCRYPT='no'
if [ $2 ]; then
USE_LETSENCRYPT=$2
fi
if [[ $USE_LETSENCRYPT == 'no' ]]; then
if [ ! -f /etc/ssl/private/${1}.key ]; then
echo $"Private certificate for ${CHECK_HOSTNAME} was not created"
exit 63959
fi
if [ ! -f /etc/ssl/certs/${1}.crt ]; then
echo $"Public certificate for ${CHECK_HOSTNAME} was not created"
exit 7679
fi
if grep -q "${1}.pem" /etc/nginx/sites-available/${1}; then
sed -i "s|${1}.pem|${1}.crt|g" /etc/nginx/sites-available/${1}
fi
else
if [ ! -f /etc/letsencrypt/live/${1}/privkey.pem ]; then
echo $"Private certificate for ${CHECK_HOSTNAME} was not created"
exit 6282
fi
if [ ! -f /etc/letsencrypt/live/${1}/fullchain.pem ]; then
echo $"Public certificate for ${CHECK_HOSTNAME} was not created"
exit 5328
fi
if grep -q "${1}.crt" /etc/nginx/sites-available/${1}; then
sed -i "s|${1}.crt|${1}.pem|g" /etc/nginx/sites-available/${1}
fi
fi
if [ ! -f /etc/ssl/certs/${1}.dhparam ]; then
echo $"DiffieHellman parameters for ${CHECK_HOSTNAME} were not created"
exit 5989
fi
}
function cert_exists {
cert_type='dhparam'
if [ $2 ]; then
cert_type="$2"
fi
if [ -f /etc/ssl/certs/${1}.${cert_type} ]; then
echo "1"
else
if [ -f /etc/letsencrypt/live/${1}/fullchain.${cert_type} ]; then
echo "1"
else
echo "0"
fi
fi
}
function create_self_signed_cert {
${PROJECT_NAME}-addcert -h ${SITE_DOMAIN_NAME} --dhkey ${DH_KEYLENGTH}
function_check check_certificates
check_certificates ${SITE_DOMAIN_NAME}
}
function create_letsencrypt_cert {
${PROJECT_NAME}-addcert -e ${SITE_DOMAIN_NAME} -s ${LETSENCRYPT_SERVER} --dhkey ${DH_KEYLENGTH} --email ${MY_EMAIL_ADDRESS}
if [ ! "$?" = "0" ]; then
if [[ ${NO_SELF_SIGNED} == 'no' ]]; then
echo $"Lets Encrypt failed for ${SITE_DOMAIN_NAME}, so try making a self-signed cert"
${PROJECT_NAME}-addcert -h ${SITE_DOMAIN_NAME} --dhkey ${DH_KEYLENGTH}
function_check check_certificates
check_certificates ${SITE_DOMAIN_NAME}
else
echo $"Lets Encrypt failed for $SITE_DOMAIN_NAME"
exit 682529
fi
return
fi
function_check check_certificates
check_certificates ${SITE_DOMAIN_NAME} 'yes'
}
function create_site_certificate {
SITE_DOMAIN_NAME="$1"
# if yes then only "valid" certs are allowed, not self-signed
NO_SELF_SIGNED='no'
if [ $2 ]; then
NO_SELF_SIGNED="$2"
fi
if [[ $ONION_ONLY == "no" ]]; then
if [[ "$(cert_exists ${SITE_DOMAIN_NAME})" == "0" ]]; then
if [[ $LETSENCRYPT_ENABLED != "yes" ]]; then
create_self_signed_cert
else
create_letsencrypt_cert
fi
else
if [[ $LETSENCRYPT_ENABLED == "yes" ]]; then
if [[ "$(cert_exists ${SITE_DOMAIN_NAME} pem)" == "0" ]]; then
create_letsencrypt_cert
fi
fi
fi
fi
}
# script to automatically renew any Let's Encrypt certificates
function letsencrypt_renewals {
if [[ $ONION_ONLY != "no" ]]; then
return
fi
renewals_script=/etc/cron.monthly/letsencrypt
renewals_retry_script=/etc/cron.daily/letsencrypt
renewal_failure_msg=$'The certificate for $LETSENCRYPT_DOMAIN could not be renewed'
renewal_email_title=$'${PROJECT_NAME} Lets Encrypt certificate renewal'
# the main script tries to renew once per month
echo '#!/bin/bash' > $renewals_script
echo '' >> $renewals_script
echo "PROJECT_NAME='${PROJECT_NAME}'" >> $renewals_script
echo 'COMPLETION_FILE=$HOME/${PROJECT_NAME}-completed.txt' >> $renewals_script
echo '' >> $renewals_script
echo 'if [ -d /etc/letsencrypt ]; then' >> $renewals_script
echo ' if [ -f ~/letsencrypt_failed ]; then' >> $renewals_script
echo ' rm ~/letsencrypt_failed' >> $renewals_script
echo ' fi' >> $renewals_script
echo -n ' ADMIN_USERNAME=$(cat $COMPLETION_FILE | grep "Admin user" | ' >> $renewals_script
echo -n "awk -F ':' '{print " >> $renewals_script
echo -n '$2' >> $renewals_script
echo "}')" >> $renewals_script
echo ' ADMIN_EMAIL_ADDRESS=$ADMIN_USERNAME@$HOSTNAME' >> $renewals_script
echo ' for d in /etc/letsencrypt/live/*/ ; do' >> $renewals_script
echo -n ' LETSENCRYPT_DOMAIN=$(echo "$d" | ' >> $renewals_script
echo -n "awk -F '/' '{print " >> $renewals_script
echo -n '$5' >> $renewals_script
echo "}')" >> $renewals_script
echo ' if [ -f /etc/nginx/sites-available/$LETSENCRYPT_DOMAIN ]; then' >> $renewals_script
echo ' ${PROJECT_NAME}-renew-cert -h $LETSENCRYPT_DOMAIN -p letsencrypt' >> $renewals_script
echo ' if [ ! "$?" = "0" ]; then' >> $renewals_script
echo " echo \"${renewal_failure_msg}\" > ~/temp_renewletsencrypt.txt" >> $renewals_script
echo ' echo "" >> ~/temp_renewletsencrypt.txt' >> $renewals_script
echo ' ${PROJECT_NAME}-renew-cert -h $LETSENCRYPT_DOMAIN -p letsencrypt 2>> ~/temp_renewletsencrypt.txt' >> $renewals_script
echo -n " cat ~/temp_renewletsencrypt.txt | mail -s \"${renewal_email_title}\" " >> $renewals_script
echo '$ADMIN_EMAIL_ADDRESS' >> $renewals_script
echo ' rm ~/temp_renewletsencrypt.txt' >> $renewals_script
echo ' if [ ! -f ~/letsencrypt_failed ]; then' >> $renewals_script
echo ' touch ~/letsencrypt_failed' >> $renewals_script
echo ' fi' >> $renewals_script
echo ' fi' >> $renewals_script
echo ' fi' >> $renewals_script
echo ' done' >> $renewals_script
echo 'fi' >> $renewals_script
chmod +x $renewals_script
# a secondary script keeps trying to renew after a failure
echo '#!/bin/bash' > $renewals_retry_script
echo '' >> $renewals_retry_script
echo "PROJECT_NAME='${PROJECT_NAME}'" >> $renewals_retry_script
echo 'COMPLETION_FILE=$HOME/${PROJECT_NAME}-completed.txt' >> $renewals_retry_script
echo '' >> $renewals_retry_script
echo 'if [ -d /etc/letsencrypt ]; then' >> $renewals_retry_script
echo ' if [ -f ~/letsencrypt_failed ]; then' >> $renewals_retry_script
echo ' rm ~/letsencrypt_failed' >> $renewals_retry_script
echo -n ' ADMIN_USERNAME=$(cat $COMPLETION_FILE | grep "Admin user" | ' >> $renewals_retry_script
echo -n "awk -F ':' '{print " >> $renewals_retry_script
echo -n '$2' >> $renewals_retry_script
echo "}')" >> $renewals_retry_script
echo ' ADMIN_EMAIL_ADDRESS=$ADMIN_USERNAME@$HOSTNAME' >> $renewals_retry_script
echo ' for d in /etc/letsencrypt/live/*/ ; do' >> $renewals_retry_script
echo -n ' LETSENCRYPT_DOMAIN=$(echo "$d" | ' >> $renewals_retry_script
echo -n "awk -F '/' '{print " >> $renewals_retry_script
echo -n '$5' >> $renewals_retry_script
echo "}')" >> $renewals_retry_script
echo ' if [ -f /etc/nginx/sites-available/$LETSENCRYPT_DOMAIN ]; then' >> $renewals_retry_script
echo ' ${PROJECT_NAME}-renew-cert -h $LETSENCRYPT_DOMAIN -p letsencrypt' >> $renewals_retry_script
echo ' if [ ! "$?" = "0" ]; then' >> $renewals_retry_script
echo " echo \"${renewal_failure_msg}\" > ~/temp_renewletsencrypt.txt" >> $renewals_retry_script
echo ' echo "" >> ~/temp_renewletsencrypt.txt' >> $renewals_retry_script
echo ' ${PROJECT_NAME}-renew-cert -h $LETSENCRYPT_DOMAIN -p letsencrypt 2>> ~/temp_renewletsencrypt.txt' >> $renewals_retry_script
echo -n " cat ~/temp_renewletsencrypt.txt | mail -s \"${renewal_email_title}\" " >> $renewals_retry_script
echo '$ADMIN_EMAIL_ADDRESS' >> $renewals_retry_script
echo ' rm ~/temp_renewletsencrypt.txt' >> $renewals_retry_script
echo ' if [ ! -f ~/letsencrypt_failed ]; then' >> $renewals_retry_script
echo ' touch ~/letsencrypt_failed' >> $renewals_retry_script
echo ' fi' >> $renewals_retry_script
echo ' fi' >> $renewals_retry_script
echo ' fi' >> $renewals_retry_script
echo ' done' >> $renewals_retry_script
echo ' fi' >> $renewals_retry_script
echo 'fi' >> $renewals_retry_script
chmod +x $renewals_retry_script
}
function configure_php {
sed -i "s/memory_limit = 128M/memory_limit = ${MAX_PHP_MEMORY}M/g" /etc/php/7.0/fpm/php.ini
sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g' /etc/php/7.0/fpm/php.ini
sed -i "s/memory_limit = -1/memory_limit = ${MAX_PHP_MEMORY}M/g" /etc/php/7.0/cli/php.ini
sed -i "s/upload_max_filesize = 2M/upload_max_filesize = 50M/g" /etc/php/7.0/fpm/php.ini
sed -i "s/post_max_size = 8M/post_max_size = 50M/g" /etc/php/7.0/fpm/php.ini
}
function install_web_server_access_control {
if [ ! -f /etc/pam.d/nginx ]; then
echo '#%PAM-1.0' > /etc/pam.d/nginx
echo '@include common-auth' >> /etc/pam.d/nginx
echo '@include common-account' >> /etc/pam.d/nginx
echo '@include common-session' >> /etc/pam.d/nginx
fi
}
function install_dynamicdns {
if [[ $SYSTEM_TYPE == "mesh"* ]]; then
return
fi
if [[ $ONION_ONLY != "no" ]]; then
return
fi
CURR_INADYN_COMMIT=$(get_completion_param "inadyn commit")
if [[ "${CURR_INADYN_COMMIT}" == "${INADYN_COMMIT}" ]]; then
return
fi
# update to the next commit
function_check set_repo_commit
set_repo_commit $INSTALL_DIR/inadyn "inadyn commit" "$INADYN_COMMIT" $INADYN_REPO
if [[ $(is_completed $FUNCNAME) == "1" ]]; then
return
fi
# Here we compile from source because the current package
# doesn't support https, which could result in passwords
# being leaked
# Debian version 1.99.4-1
# https version 1.99.8
apt-get -yq install build-essential curl libgnutls28-dev automake1.11
if [ ! -d $INSTALL_DIR/inadyn ]; then
if [ -d /repos/inadyn ]; then
mkdir $INSTALL_DIR/inadyn
cp -r -p /repos/inadyn/. $INSTALL_DIR/inadyn
cd $INSTALL_DIR/inadyn
git pull
else
git_clone $INADYN_REPO $INSTALL_DIR/inadyn
fi
fi
if [ ! -d $INSTALL_DIR/inadyn ]; then
echo 'inadyn repo not cloned'
echo -n | openssl s_client -showcerts -connect github.com:443 -CApath /etc/ssl/certs
exit 6785
fi
cd $INSTALL_DIR/inadyn
git checkout $INADYN_COMMIT -b $INADYN_COMMIT
set_completion_param "inadyn commit" "$INADYN_COMMIT"
#./autogen.sh
./configure
if [ ! "$?" = "0" ]; then
exit 74890
fi
USE_OPENSSL=1 make
if [ ! "$?" = "0" ]; then
exit 74858
fi
make install
if [ ! "$?" = "0" ]; then
exit 3785
fi
# create an unprivileged user
#chmod 600 /etc/shadow
#chmod 600 /etc/gshadow
#useradd -r -s /bin/false debian-inadyn
#chmod 0000 /etc/shadow
#chmod 0000 /etc/gshadow
# create a configuration file
echo 'background' > /etc/inadyn.conf
echo 'verbose 1' >> /etc/inadyn.conf
echo 'period 300' >> /etc/inadyn.conf
echo 'startup-delay 60' >> /etc/inadyn.conf
echo 'cache-dir /run/inadyn' >> /etc/inadyn.conf
echo 'logfile /dev/null' >> /etc/inadyn.conf
chmod 600 /etc/inadyn.conf
echo '[Unit]' > /etc/systemd/system/inadyn.service
echo 'Description=inadyn (DynDNS updater)' >> /etc/systemd/system/inadyn.service
echo 'After=network.target' >> /etc/systemd/system/inadyn.service
echo '' >> /etc/systemd/system/inadyn.service
echo '[Service]' >> /etc/systemd/system/inadyn.service
echo 'ExecStart=/usr/local/sbin/inadyn --config /etc/inadyn.conf' >> /etc/systemd/system/inadyn.service
echo 'Restart=always' >> /etc/systemd/system/inadyn.service
echo 'Type=forking' >> /etc/systemd/system/inadyn.service
echo '' >> /etc/systemd/system/inadyn.service
echo '[Install]' >> /etc/systemd/system/inadyn.service
echo 'WantedBy=multi-user.target' >> /etc/systemd/system/inadyn.service
systemctl enable inadyn
systemctl start inadyn
systemctl daemon-reload
mark_completed $FUNCNAME
}
function install_command_line_browser {
if [[ $(is_completed $FUNCNAME) == "1" ]]; then
return
fi
apt-get -yq install elinks
# set the home page
if ! grep -q "WWW_HOME" /home/$MY_USERNAME/.bashrc; then
if ! grep -q 'controluser' /home/$MY_USERNAME/.bashrc; then
echo "export WWW_HOME=$DEFAULT_SEARCH" >> /home/$MY_USERNAME/.bashrc
else
sed -i "/controluser/i export WWW_HOME=$DEFAULT_SEARCH" /home/$MY_USERNAME/.bashrc
fi
fi
mark_completed $FUNCNAME
}
function mesh_web_server {
if [ -d /etc/apache2 ]; then
chroot "$rootdir" apt-get -yq remove --purge apache2
chroot "$rootdir" rm -rf /etc/apache2
fi
chroot "$rootdir" apt-get -yq install nginx
if [ ! -d $rootdir/etc/nginx ]; then
echo $'Unable to install web server'
exit 346825
fi
}
function install_web_server {
if [ $INSTALLING_MESH ]; then
mesh_web_server
return
fi
# update to the next commit
function_check set_repo_commit
set_repo_commit $INSTALL_DIR/nginx_ensite "nginx-ensite commit" "$NGINX_ENSITE_COMMIT" $NGINX_ENSITE_REPO
if [[ $(is_completed $FUNCNAME) == "1" ]]; then
return
fi
# remove apache
apt-get -yq remove --purge apache2
if [ -d /etc/apache2 ]; then
rm -rf /etc/apache2
fi
# install nginx
apt-get -yq install nginx
apt-get -yq install php-fpm git
# Turn off logs by default
sed -i 's|access_log.*|access_log = /dev/null;|g' /etc/nginx/nginx.conf
sed -i 's|error_log.*|error_log = /dev/null;|g' /etc/nginx/nginx.conf
# limit the number of php processes
sed -i 's/; process.max =.*/process.max = 32/g' /etc/php/7.0/fpm/php-fpm.conf
#sed -i 's/;process_control_timeout =.*/process_control_timeout = 300/g' /etc/php/7.0/fpm/php-fpm.conf
sed -i 's|;systemd_interval.*|systemd_interval = 10|g' /etc/php/7.0/fpm/php-fpm.conf
sed -i 's|;emergency_restart_threshold.*|emergency_restart_threshold = 2|g' /etc/php/7.0/fpm/php-fpm.conf
sed -i 's|emergency_restart_threshold.*|emergency_restart_threshold = 2|g' /etc/php/7.0/fpm/php-fpm.conf
sed -i 's|;emergency_restart_interval.*|emergency_restart_interval = 1m|g' /etc/php/7.0/fpm/php-fpm.conf
sed -i 's|emergency_restart_interval.*|emergency_restart_interval = 1m|g' /etc/php/7.0/fpm/php-fpm.conf
sed -i 's|;process_control_timeout.*|process_control_timeout = 10s|g' /etc/php/7.0/fpm/php-fpm.conf
sed -i 's|process_control_timeout.*|process_control_timeout = 10s|g' /etc/php/7.0/fpm/php-fpm.conf
if ! grep -q "pm.max_children" /etc/php/7.0/fpm/php-fpm.conf; then
echo 'pm = static' >> /etc/php/7.0/fpm/php-fpm.conf
echo 'pm.max_children = 10' >> /etc/php/7.0/fpm/php-fpm.conf
echo 'pm.start_servers = 2' >> /etc/php/7.0/fpm/php-fpm.conf
echo 'pm.min_spare_servers = 2' >> /etc/php/7.0/fpm/php-fpm.conf
echo 'pm.max_spare_servers = 5' >> /etc/php/7.0/fpm/php-fpm.conf
echo 'pm.max_requests = 10' >> /etc/php/7.0/fpm/php-fpm.conf
fi
if ! grep -q "request_terminate_timeout" /etc/php/7.0/fpm/php-fpm.conf; then
echo 'request_terminate_timeout = 30' >> /etc/php/7.0/fpm/php-fpm.conf
else
sed -i 's|request_terminate_timeout =.*|request_terminate_timeout = 30|g' >> /etc/php/7.0/fpm/php-fpm.conf
fi
sed -i 's|max_execution_time =.*|max_execution_time = 30|g' /etc/php/7.0/fpm/php.ini
if [ ! -d /etc/nginx ]; then
echo $"ERROR: nginx does not appear to have installed. $CHECK_MESSAGE"
exit 51
fi
# Nginx settings
echo 'user www-data;' > /etc/nginx/nginx.conf
#echo "worker_processes; $CPU_CORES" >> /etc/nginx/nginx.conf
echo 'pid /run/nginx.pid;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo 'events {' >> /etc/nginx/nginx.conf
echo ' worker_connections 50;' >> /etc/nginx/nginx.conf
echo ' # multi_accept on;' >> /etc/nginx/nginx.conf
echo '}' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo 'http {' >> /etc/nginx/nginx.conf
echo ' # limit the number of connections per single IP' >> /etc/nginx/nginx.conf
echo ' limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' # limit the number of requests for a given session' >> /etc/nginx/nginx.conf
echo ' limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=140r/s;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' # if the request body size is more than the buffer size, then the entire (or partial) request body is written into a temporary file' >> /etc/nginx/nginx.conf
echo ' client_body_buffer_size 128k;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' # headerbuffer size for the request header from client, its set for testing purpose' >> /etc/nginx/nginx.conf
echo ' client_header_buffer_size 3m;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' # maximum number and size of buffers for large headers to read from client request' >> /etc/nginx/nginx.conf
echo ' large_client_header_buffers 4 256k;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' # read timeout for the request body from client, its set for testing purpose' >> /etc/nginx/nginx.conf
echo ' client_body_timeout 3m;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' # how long to wait for the client to send a request header, its set for testing purpose' >> /etc/nginx/nginx.conf
echo ' client_header_timeout 3m;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' ##' >> /etc/nginx/nginx.conf
echo ' # Basic Settings' >> /etc/nginx/nginx.conf
echo ' ##' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' sendfile on;' >> /etc/nginx/nginx.conf
echo ' tcp_nopush on;' >> /etc/nginx/nginx.conf
echo ' tcp_nodelay on;' >> /etc/nginx/nginx.conf
echo ' keepalive_timeout 65;' >> /etc/nginx/nginx.conf
echo ' types_hash_max_size 2048;' >> /etc/nginx/nginx.conf
echo ' server_tokens off;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' # server_names_hash_bucket_size 64;' >> /etc/nginx/nginx.conf
echo ' # server_name_in_redirect off;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' include /etc/nginx/mime.types;' >> /etc/nginx/nginx.conf
echo ' default_type application/octet-stream;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' ##' >> /etc/nginx/nginx.conf
echo ' # Logging Settings' >> /etc/nginx/nginx.conf
echo ' ##' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' access_log /dev/null;' >> /etc/nginx/nginx.conf
echo ' error_log /dev/null;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' ###' >> /etc/nginx/nginx.conf
echo ' # Gzip Settings' >> /etc/nginx/nginx.conf
echo ' ##' >> /etc/nginx/nginx.conf
echo ' gzip on;' >> /etc/nginx/nginx.conf
echo ' gzip_disable "msie6";' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' # gzip_vary on;' >> /etc/nginx/nginx.conf
echo ' # gzip_proxied any;' >> /etc/nginx/nginx.conf
echo ' # gzip_comp_level 6;' >> /etc/nginx/nginx.conf
echo ' # gzip_buffers 16 8k;' >> /etc/nginx/nginx.conf
echo ' # gzip_http_version 1.1;' >> /etc/nginx/nginx.conf
echo ' # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' ##' >> /etc/nginx/nginx.conf
echo ' # Virtual Host Configs' >> /etc/nginx/nginx.conf
echo ' ##' >> /etc/nginx/nginx.conf
echo '' >> /etc/nginx/nginx.conf
echo ' include /etc/nginx/conf.d/*.conf;' >> /etc/nginx/nginx.conf
echo ' include /etc/nginx/sites-enabled/*;' >> /etc/nginx/nginx.conf
echo '}' >> /etc/nginx/nginx.conf
# install a script to easily enable and disable nginx virtual hosts
if [ ! -d $INSTALL_DIR ]; then
mkdir $INSTALL_DIR
fi
cd $INSTALL_DIR
function_check git_clone
git_clone $NGINX_ENSITE_REPO $INSTALL_DIR/nginx_ensite
cd $INSTALL_DIR/nginx_ensite
git checkout $NGINX_ENSITE_COMMIT -b $NGINX_ENSITE_COMMIT
set_completion_param "nginx-ensite commit" "$NGINX_ENSITE_COMMIT"
make install
nginx_dissite default
function_check configure_firewall_for_web_access
configure_firewall_for_web_access
mark_completed $FUNCNAME
}
function remove_certs {
domain_name=$1
if [ ! $domain_name ]; then
return
fi
if [ -f /etc/ssl/certs/${domain_name}.dhparam ]; then
rm /etc/ssl/certs/${domain_name}.dhparam
fi
if [ -f /etc/ssl/certs/${domain_name}.pem ]; then
rm /etc/ssl/certs/${domain_name}.pem
fi
if [ -f /etc/ssl/certs/${domain_name}.crt ]; then
rm /etc/ssl/certs/${domain_name}.crt
fi
if [ -f /etc/ssl/private/${domain_name}.key ]; then
rm /etc/ssl/private/${domain_name}.key
fi
}
function configure_firewall_for_web_access {
if [[ $(is_completed $FUNCNAME) == "1" ]]; then
return
fi
if [[ $INSTALLED_WITHIN_DOCKER == "yes" ]]; then
# docker does its own firewalling
return
fi
if [[ $ONION_ONLY != "no" ]]; then
return
fi
firewall_add HTTP 80 tcp
firewall_add HTTPS 443 tcp
mark_completed $FUNCNAME
}
function update_default_domain {
echo $'Updating default domain'
if [[ $ONION_ONLY == 'no' ]]; then
if [ -d /etc/prosody ]; then
if [ -f /etc/mumble-server.ini ]; then
if [ ! -f /etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem ]; then
if ! grep -q "mumble.pem" /etc/mumble-server.ini; then
sed -i 's|sslCert=.*|sslCert=/var/lib/mumble-server/mumble.pem|g' /etc/mumble-server.ini
sed -i 's|sslKey=.*|sslKey=/var/lib/mumble-server/mumble.key|g' /etc/mumble-server.ini
systemctl restart mumble
fi
else
if ! grep -q "${DEFAULT_DOMAIN_NAME}.pem" /etc/mumble-server.ini; then
usermod -a -G ssl-cert mumble-server
sed -i "s|sslCert=.*|sslCert=/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem|g" /etc/mumble-server.ini
sed -i "s|sslKey=.*|sslKey=/etc/ssl/private/${DEFAULT_DOMAIN_NAME}.key|g" /etc/mumble-server.ini
systemctl restart mumble
fi
fi
fi
if [ ! -d /etc/prosody/certs ]; then
mkdir /etc/prosody/certs
fi
cp /etc/ssl/private/xmpp* /etc/prosody/certs
cp /etc/ssl/certs/xmpp* /etc/prosody/certs
if [ /etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem ]; then
usermod -a -G ssl-cert prosody
sed -i "s|/etc/prosody/certs/xmpp.key|/etc/ssl/private/${DEFAULT_DOMAIN_NAME}.key|g" /etc/prosody/conf.avail/xmpp.cfg.lua
sed -i "s|/etc/prosody/certs/xmpp.crt|/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem|g" /etc/prosody/conf.avail/xmpp.cfg.lua
sed -i "s|/etc/prosody/certs/xmpp.key|/etc/ssl/private/${DEFAULT_DOMAIN_NAME}.key|g" /etc/prosody/prosody.cfg.lua
sed -i "s|/etc/prosody/certs/xmpp.crt|/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem|g" /etc/prosody/prosody.cfg.lua
fi
if grep -q "/etc/prosody/certs/${DEFAULT_DOMAIN_NAME}.key" /etc/prosody/conf.avail/xmpp.cfg.lua; then
sed -i "s|/etc/prosody/certs/${DEFAULT_DOMAIN_NAME}.key|/etc/ssl/private/${DEFAULT_DOMAIN_NAME}.key|g" /etc/prosody/conf.avail/xmpp.cfg.lua
fi
if grep -q "/etc/prosody/certs/${DEFAULT_DOMAIN_NAME}.pem" /etc/prosody/conf.avail/xmpp.cfg.lua; then
sed -i "s|/etc/prosody/certs/${DEFAULT_DOMAIN_NAME}.pem|/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem|g" /etc/prosody/conf.avail/xmpp.cfg.lua
fi
if grep -q "/etc/prosody/certs/${DEFAULT_DOMAIN_NAME}.key" /etc/prosody/prosody.cfg.lua; then
sed -i "s|/etc/prosody/certs/${DEFAULT_DOMAIN_NAME}.key|/etc/ssl/private/${DEFAULT_DOMAIN_NAME}.key|g" /etc/prosody/prosody.cfg.lua
fi
if grep -q "/etc/prosody/certs/${DEFAULT_DOMAIN_NAME}.pem" /etc/prosody/prosody.cfg.lua; then
sed -i "s|/etc/prosody/certs/${DEFAULT_DOMAIN_NAME}.pem|/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem|g" /etc/prosody/prosody.cfg.lua
fi
chown -R prosody:default /etc/prosody
chmod -R 700 /etc/prosody/certs/*
chmod 600 /etc/prosody/prosody.cfg.lua
cp -r $INSTALL_DIR/prosody-modules/* /var/lib/prosody/prosody-modules/
chown -R prosody:prosody /var/lib/prosody/prosody-modules
systemctl reload prosody
fi
if [ -d /home/znc/.znc ]; then
echo $'znc found'
if [[ "$(cert_exists ${DEFAULT_DOMAIN_NAME} pem)" == "1" ]]; then
pkill znc
cat /etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem /etc/ssl/private/${DEFAULT_DOMAIN_NAME}.key > /home/znc/.znc/znc.pem
chown znc:znc /home/znc/.znc/znc.pem
chmod 700 /home/znc/.znc/znc.pem
sed -i "s|CertFile =.*|CertFile = /etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem" /etc/ngircd/ngircd.conf
sed -i "s|DHFile =.*|DHFile = /etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.dhparam" /etc/ngircd/ngircd.conf
sed -i "s|KeyFile =.*|KeyFile = /etc/ssl/private/${DEFAULT_DOMAIN_NAME}.key" /etc/ngircd/ngircd.conf
echo $'irc certificates updated'
systemctl restart ngircd
su -c 'znc' - znc
fi
fi
if [ -d /etc/dovecot ]; then
if [ ${#DEFAULT_DOMAIN_NAME} -gt 0 ]; then
if ! grep -q "ssl_cert = </etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem" /etc/dovecot/conf.d/10-ssl.conf; then
sed -i "s|#ssl_cert =.*|ssl_cert = </etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem|g" /etc/dovecot/conf.d/10-ssl.conf
sed -i "s|ssl_cert =.*|ssl_cert = </etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem|g" /etc/dovecot/conf.d/10-ssl.conf
systemctl restart dovecot
fi
fi
fi
fi
}
function create_default_web_site {
if [ ! -f /etc/nginx/sites-available/${DEFAULT_DOMAIN_NAME} ]; then
# create a web site for the default domain
if [ ! -d /var/www/${DEFAULT_DOMAIN_NAME}/htdocs ]; then
mkdir -p /var/www/${DEFAULT_DOMAIN_NAME}/htdocs
if [ -d /root/${PROJECT_NAME} ]; then
cd /root/${PROJECT_NAME}/website
./deploy.sh EN /var/www/${DEFAULT_DOMAIN_NAME}/htdocs
else
if [ -d /home/${MY_USERNAME}/${PROJECT_NAME} ]; then
cd /home/${MY_USERNAME}/${PROJECT_NAME}
./deploy.sh EN /var/www/${DEFAULT_DOMAIN_NAME}/htdocs
fi
fi
fi
# add a config for the default domain
nginx_site=/etc/nginx/sites-available/$DEFAULT_DOMAIN_NAME
if [[ $ONION_ONLY == "no" ]]; then
function_check nginx_http_redirect
nginx_http_redirect $DEFAULT_DOMAIN_NAME
echo 'server {' >> $nginx_site
echo ' listen 443 ssl;' >> $nginx_site
echo ' listen [::]:443 ssl;' >> $nginx_site
echo " server_name $DEFAULT_DOMAIN_NAME;" >> $nginx_site
echo '' >> $nginx_site
echo ' # Security' >> $nginx_site
function_check nginx_ssl
nginx_ssl $DEFAULT_DOMAIN_NAME mobile
function_check nginx_disable_sniffing
nginx_disable_sniffing $DEFAULT_DOMAIN_NAME
echo ' add_header Strict-Transport-Security max-age=15768000;' >> $nginx_site
echo '' >> $nginx_site
echo ' # Logs' >> $nginx_site
echo ' access_log /dev/null;' >> $nginx_site
echo ' error_log /dev/null;' >> $nginx_site
echo '' >> $nginx_site
echo ' # Root' >> $nginx_site
echo " root /var/www/$DEFAULT_DOMAIN_NAME/htdocs;" >> $nginx_site
echo '' >> $nginx_site
echo ' # Index' >> $nginx_site
echo ' index index.html;' >> $nginx_site
echo '' >> $nginx_site
echo ' # Location' >> $nginx_site
echo ' location / {' >> $nginx_site
function_check nginx_limits
nginx_limits $DEFAULT_DOMAIN_NAME '15m'
echo ' }' >> $nginx_site
echo '' >> $nginx_site
echo ' # Restrict access that is unnecessary anyway' >> $nginx_site
echo ' location ~ /\.(ht|git) {' >> $nginx_site
echo ' deny all;' >> $nginx_site
echo ' }' >> $nginx_site
echo '}' >> $nginx_site
else
echo -n '' > $nginx_site
fi
echo 'server {' >> $nginx_site
echo " listen 127.0.0.1:$DEFAULT_DOMAIN_ONION_PORT default_server;" >> $nginx_site
echo " server_name $DEFAULT_DOMAIN_NAME;" >> $nginx_site
echo '' >> $nginx_site
function_check nginx_disable_sniffing
nginx_disable_sniffing $DEFAULT_DOMAIN_NAME
echo '' >> $nginx_site
echo ' # Logs' >> $nginx_site
echo ' access_log /dev/null;' >> $nginx_site
echo ' error_log /dev/null;' >> $nginx_site
echo '' >> $nginx_site
echo ' # Root' >> $nginx_site
echo " root /var/www/$DEFAULT_DOMAIN_NAME/htdocs;" >> $nginx_site
echo '' >> $nginx_site
echo ' # Location' >> $nginx_site
echo ' location / {' >> $nginx_site
function_check nginx_limits
nginx_limits $DEFAULT_DOMAIN_NAME '15m'
echo ' }' >> $nginx_site
echo '' >> $nginx_site
echo ' # Restrict access that is unnecessary anyway' >> $nginx_site
echo ' location ~ /\.(ht|git) {' >> $nginx_site
echo ' deny all;' >> $nginx_site
echo ' }' >> $nginx_site
echo '}' >> $nginx_site
if [ ! -f /etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem ]; then
function_check create_site_certificate
create_site_certificate $DEFAULT_DOMAIN_NAME 'yes'
fi
nginx_ensite $DEFAULT_DOMAIN_NAME
fi
}
function install_composer {
# curl -sS https://getcomposer.org/installer | php
if [ -f ~/${PROJECT_NAME}/image_build/composer_install ]; then
cat ~/${PROJECT_NAME}/image_build/composer_install | php
else
if [ -f /home/$MY_USERNAME/${PROJECT_NAME}/image_build/composer_install ]; then
cat /home/$MY_USERNAME/${PROJECT_NAME}/image_build/composer_install | php
fi
fi
php composer.phar install
if [ ! "$?" = "0" ]; then
echo $'Unable to run composer install'
exit 7252198
fi
}
# NOTE: deliberately no exit 0