diff --git a/conf/fail2ban/jails.conf b/conf/fail2ban/jails.conf index 952dc35a..0213ea7b 100644 --- a/conf/fail2ban/jails.conf +++ b/conf/fail2ban/jails.conf @@ -30,14 +30,6 @@ logpath = /var/log/nginx/access.log maxretry = 20 findtime = 30 -[miab-owncloud] -enabled = true -port = http,https -filter = miab-owncloud -logpath = STORAGE_ROOT/owncloud/nextcloud.log -maxretry = 20 -findtime = 120 - [miab-postfix587] enabled = true port = 587 diff --git a/conf/fail2ban/nextcloud-jail.conf b/conf/fail2ban/nextcloud-jail.conf new file mode 100644 index 00000000..a954beea --- /dev/null +++ b/conf/fail2ban/nextcloud-jail.conf @@ -0,0 +1,8 @@ + +[miab-owncloud] +enabled = true +port = http,https +filter = miab-owncloud +logpath = STORAGE_ROOT/owncloud/nextcloud.log +maxretry = 20 +findtime = 120 diff --git a/conf/nginx-nextcloud.conf b/conf/nginx-nextcloud.conf new file mode 100644 index 00000000..dd7457bf --- /dev/null +++ b/conf/nginx-nextcloud.conf @@ -0,0 +1,60 @@ + + # Nextcloud configuration. + rewrite ^/cloud$ /cloud/ redirect; + rewrite ^/cloud/$ /cloud/index.php; + rewrite ^/cloud/(contacts|calendar|files)$ /cloud/index.php/apps/$1/ redirect; + rewrite ^(/cloud/core/doc/[^\/]+/)$ $1/index.html; + rewrite ^(/cloud/oc[sm]-provider)/$ $1/index.php redirect; + location /cloud/ { + alias /usr/local/lib/owncloud/; + location ~ ^/cloud/(build|tests|config|lib|3rdparty|templates|data|README)/ { + deny all; + } + location ~ ^/cloud/(?:\.|autotest|occ|issue|indie|db_|console) { + deny all; + } + # Enable paths for service and cloud federation discovery + # Resolves warning in Nextcloud Settings panel + location ~ ^/cloud/(oc[sm]-provider)?/([^/]+\.php)$ { + index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/local/lib/owncloud/$1/$2; + fastcgi_pass php-fpm; + } + } + location ~ ^(/cloud)((?:/ocs)?/[^/]+\.php)(/.*)?$ { + # note: ~ has precendence over a regular location block + # Accept URLs like: + # /cloud/index.php/apps/files/ + # /cloud/index.php/apps/files/ajax/scan.php (it's really index.php; see 6fdef379adfdeac86cc2220209bdf4eb9562268d) + # /cloud/ocs/v1.php/apps/files_sharing/api/v1 (see #240) + # /cloud/remote.php/webdav/yourfilehere... + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/local/lib/owncloud/$2; + fastcgi_param SCRIPT_NAME $1$2; + fastcgi_param PATH_INFO $3; + fastcgi_param MOD_X_ACCEL_REDIRECT_ENABLED on; + fastcgi_param MOD_X_ACCEL_REDIRECT_PREFIX /owncloud-xaccel; + fastcgi_read_timeout 630; + fastcgi_pass php-fpm; + client_max_body_size 1G; + fastcgi_buffers 64 4K; + } + location ^~ /owncloud-xaccel/ { + # This directory is for MOD_X_ACCEL_REDIRECT_ENABLED. Nextcloud sends the full file + # path on disk as a subdirectory under this virtual path. + # We must only allow 'internal' redirects within nginx so that the filesystem + # is not exposed to the world. + internal; + alias /; + } + location ~ ^/((caldav|carddav|webdav).*)$ { + # Z-Push doesn't like getting a redirect, and a plain rewrite didn't work either. + # Properly proxying like this seems to work fine. + proxy_pass https://127.0.0.1/cloud/remote.php/$1; + } + rewrite ^/.well-known/host-meta /cloud/public.php?service=host-meta last; + rewrite ^/.well-known/host-meta.json /cloud/public.php?service=host-meta-json last; + rewrite ^/.well-known/carddav /cloud/remote.php/carddav/ redirect; + rewrite ^/.well-known/caldav /cloud/remote.php/caldav/ redirect; + diff --git a/conf/nginx-primaryonly.conf b/conf/nginx-primaryonly.conf index 288fce40..9a7576b1 100644 --- a/conf/nginx-primaryonly.conf +++ b/conf/nginx-primaryonly.conf @@ -14,63 +14,3 @@ add_header Content-Security-Policy "frame-ancestors 'none';"; } - # Nextcloud configuration. - rewrite ^/cloud$ /cloud/ redirect; - rewrite ^/cloud/$ /cloud/index.php; - rewrite ^/cloud/(contacts|calendar|files)$ /cloud/index.php/apps/$1/ redirect; - rewrite ^(/cloud/core/doc/[^\/]+/)$ $1/index.html; - rewrite ^(/cloud/oc[sm]-provider)/$ $1/index.php redirect; - location /cloud/ { - alias /usr/local/lib/owncloud/; - location ~ ^/cloud/(build|tests|config|lib|3rdparty|templates|data|README)/ { - deny all; - } - location ~ ^/cloud/(?:\.|autotest|occ|issue|indie|db_|console) { - deny all; - } - # Enable paths for service and cloud federation discovery - # Resolves warning in Nextcloud Settings panel - location ~ ^/cloud/(oc[sm]-provider)?/([^/]+\.php)$ { - index index.php; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME /usr/local/lib/owncloud/$1/$2; - fastcgi_pass php-fpm; - } - } - location ~ ^(/cloud)((?:/ocs)?/[^/]+\.php)(/.*)?$ { - # note: ~ has precendence over a regular location block - # Accept URLs like: - # /cloud/index.php/apps/files/ - # /cloud/index.php/apps/files/ajax/scan.php (it's really index.php; see 6fdef379adfdeac86cc2220209bdf4eb9562268d) - # /cloud/ocs/v1.php/apps/files_sharing/api/v1 (see #240) - # /cloud/remote.php/webdav/yourfilehere... - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME /usr/local/lib/owncloud/$2; - fastcgi_param SCRIPT_NAME $1$2; - fastcgi_param PATH_INFO $3; - fastcgi_param MOD_X_ACCEL_REDIRECT_ENABLED on; - fastcgi_param MOD_X_ACCEL_REDIRECT_PREFIX /owncloud-xaccel; - fastcgi_read_timeout 630; - fastcgi_pass php-fpm; - client_max_body_size 1G; - fastcgi_buffers 64 4K; - } - location ^~ /owncloud-xaccel/ { - # This directory is for MOD_X_ACCEL_REDIRECT_ENABLED. Nextcloud sends the full file - # path on disk as a subdirectory under this virtual path. - # We must only allow 'internal' redirects within nginx so that the filesystem - # is not exposed to the world. - internal; - alias /; - } - location ~ ^/((caldav|carddav|webdav).*)$ { - # Z-Push doesn't like getting a redirect, and a plain rewrite didn't work either. - # Properly proxying like this seems to work fine. - proxy_pass https://127.0.0.1/cloud/remote.php/$1; - } - rewrite ^/.well-known/host-meta /cloud/public.php?service=host-meta last; - rewrite ^/.well-known/host-meta.json /cloud/public.php?service=host-meta-json last; - rewrite ^/.well-known/carddav /cloud/remote.php/carddav/ redirect; - rewrite ^/.well-known/caldav /cloud/remote.php/caldav/ redirect; - - # ADDITIONAL DIRECTIVES HERE diff --git a/management/dns_update.py b/management/dns_update.py index 7d053d5e..90810047 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -11,6 +11,7 @@ import dns.resolver from mailconfig import get_mail_domains from utils import shell, load_env_vars_from_file, safe_domain_name, sort_domains +from os import environ # From https://stackoverflow.com/questions/3026957/how-to-validate-a-domain-name-using-regex-php/16491074#16491074 # This regular expression matches domain names according to RFCs, it also accepts fqdn with an leading dot, @@ -280,14 +281,14 @@ def build_zone(domain, all_domains, additional_records, www_redirect_domains, en if not has_rec(dmarc_qname, "TXT", prefix="v=DMARC1; "): records.append((dmarc_qname, "TXT", 'v=DMARC1; p=reject', "Recommended. Prevents use of this domain name for outbound mail by specifying that the SPF rule should be honoured for mail from @%s." % (qname + "." + domain))) - # Add CardDAV/CalDAV SRV records on the non-primary hostname that points to the primary hostname. - # The SRV record format is priority (0, whatever), weight (0, whatever), port, service provider hostname (w/ trailing dot). - if domain != env["PRIMARY_HOSTNAME"]: - for dav in ("card", "cal"): - qname = "_" + dav + "davs._tcp" - if not has_rec(qname, "SRV"): - records.append((qname, "SRV", "0 0 443 " + env["PRIMARY_HOSTNAME"] + ".", "Recommended. Specifies the hostname of the server that handles CardDAV/CalDAV services for email addresses on this domain.")) - + if environ.get('DISABLE_NEXTCLOUD') != '0' and domain != env["PRIMARY_HOSTNAME"]: + # Add CardDAV/CalDAV SRV records on the non-primary hostname that points to the primary hostname. + # The SRV record format is priority (0, whatever), weight (0, whatever), port, service provider hostname (w/ trailing dot). + for dav in ("card", "cal"): + qname = "_" + dav + "davs._tcp" + if not has_rec(qname, "SRV"): + records.append((qname, "SRV", "0 0 443 " + env["PRIMARY_HOSTNAME"] + ".", "Recommended. Specifies the hostname of the server that handles CardDAV/CalDAV services for email addresses on this domain.")) + # Adds autoconfiguration A records for all domains. # This allows the following clients to automatically configure email addresses in the respective applications. # autodiscover.* - Z-Push ActiveSync Autodiscover diff --git a/management/templates/index.html b/management/templates/index.html index 2c0d5a9a..bf3ee915 100644 --- a/management/templates/index.html +++ b/management/templates/index.html @@ -147,9 +147,7 @@ {% include "aliases.html" %} -
- {% include "sync-guide.html" %} -
+
{% include "sync-guide.html" %}
{% include "web.html" %} diff --git a/management/web_update.py b/management/web_update.py index 72295c21..9d03864b 100644 --- a/management/web_update.py +++ b/management/web_update.py @@ -8,6 +8,7 @@ from mailconfig import get_mail_domains from dns_update import get_custom_dns_config, get_dns_zones from ssl_certificates import get_ssl_certificates, get_domain_ssl_files, check_certificate from utils import shell, safe_domain_name, sort_domains +from os import environ def get_web_domains(env, include_www_redirects=True, exclude_dns_elsewhere=True): # What domains should we serve HTTP(S) for? @@ -75,13 +76,17 @@ def do_web_update(env): nginx_conf = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-top.conf")).read() # Load the templates. + template2_nextcloud = "" template0 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx.conf")).read() template1 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-alldomains.conf")).read() template2 = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-primaryonly.conf")).read() + # Check if the user doesn't want Nextcloud. + if environ.get('DISABLE_NEXTCLOUD') != '0': + template2_nextcloud = open(os.path.join(os.path.dirname(__file__), "../conf/nginx-nextcloud.conf")).read() template3 = "\trewrite ^(.*) https://$REDIRECT_DOMAIN$1 permanent;\n" # Add the PRIMARY_HOST configuration first so it becomes nginx's default server. - nginx_conf += make_domain_config(env['PRIMARY_HOSTNAME'], [template0, template1, template2], ssl_certificates, env) + nginx_conf += make_domain_config(env['PRIMARY_HOSTNAME'], [template0, template1, template2, template2_nextcloud], ssl_certificates, env) # Add configuration all other web domains. has_root_proxy_or_redirect = get_web_domains_with_root_overrides(env) diff --git a/setup/functions.sh b/setup/functions.sh index 3bb96b7a..b7414832 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -47,6 +47,12 @@ function apt_get_quiet { DEBIAN_FRONTEND=noninteractive hide_output apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" "$@" } +function apt_purge { + # Remove a bunch of packages. + PACKAGES=$@ + apt_get_quiet --purge remove $PACKAGES +} + function apt_install { # Install a bunch of packages. We used to report which packages were already # installed and which needed installing, before just running an 'apt-get @@ -158,6 +164,17 @@ function message_box { dialog --title "$1" --msgbox "$2" 0 0 } +function yesno_box { + # yesno_box "title" "prompt" VARIABLE + # The exit code resembles the user's input and will be stored in the variable VARIABLE + # Temporarily turn off 'set -e' because we need the dialog return code + declare -n result=$3 + set +e + dialog --stdout --title "$1" --yesno "$2" 0 0 + result=$? + set -e +} + function input_box { # input_box "title" "prompt" "defaultvalue" VARIABLE # The user's input will be stored in the variable VARIABLE. diff --git a/setup/management.sh b/setup/management.sh index 3a6e187b..9a035d60 100755 --- a/setup/management.sh +++ b/setup/management.sh @@ -85,6 +85,12 @@ unzip -q /tmp/bootstrap.zip -d $assets_dir mv $assets_dir/bootstrap-$bootstrap_version-dist $assets_dir/bootstrap rm -f /tmp/bootstrap.zip +# Remove the Contacts/Calendar section from the admin page if the user didn't enable Nextcloud +if [ "${DISABLE_NEXTCLOUD}" == 0 ]; then + sed -i '/sync_guide/d' ../management/templates/index.html + rm ../management/templates/sync-guide.html +fi + # Create an init script to start the management daemon and keep it # running after a reboot. cat > $inst_dir/start <> conf/fail2ban/jails.conf +fi + cat conf/fail2ban/jails.conf \ | sed "s/PUBLIC_IP/$PUBLIC_IP/g" \ | sed "s#STORAGE_ROOT#$STORAGE_ROOT#" \ > /etc/fail2ban/jail.d/mailinabox.conf + + cp -f conf/fail2ban/filter.d/* /etc/fail2ban/filter.d/ # On first installation, the log files that the jails look at don't all exist. diff --git a/setup/webmail.sh b/setup/webmail.sh index 6cbe55f9..0fe0fc6e 100755 --- a/setup/webmail.sh +++ b/setup/webmail.sh @@ -68,15 +68,18 @@ if [ $needs_update == 1 ]; then git_clone https://github.com/kitist/html5_notifier.git $HTML5_NOTIFIER_VERSION '' ${RCM_PLUGIN_DIR}/html5_notifier # download and verify the full release of the carddav plugin - wget_verify \ - https://github.com/blind-coder/rcmcarddav/releases/download/v${CARDDAV_VERSION}/carddav-${CARDDAV_VERSION}.zip \ - $CARDDAV_HASH \ - /tmp/carddav.zip - - # unzip and cleanup - unzip -q /tmp/carddav.zip -d ${RCM_PLUGIN_DIR} - rm -f /tmp/carddav.zip + if [ "${DISABLE_NEXTCLOUD}" != "0" ]; then + wget_verify \ + https://github.com/blind-coder/rcmcarddav/releases/download/v${CARDDAV_VERSION}/carddav-${CARDDAV_VERSION}.zip \ + $CARDDAV_HASH \ + /tmp/carddav.zip + + # unzip and cleanup + unzip -q /tmp/carddav.zip -d ${RCM_PLUGIN_DIR} + rm -f /tmp/carddav.zip + + fi # record the version we've installed echo $UPDATE_KEY > ${RCM_DIR}/version fi @@ -91,6 +94,14 @@ SECRET_KEY=$(dd if=/dev/urandom bs=1 count=18 2>/dev/null | base64 | fold -w 24 # For security, temp and log files are not stored in the default locations # which are inside the roundcube sources directory. We put them instead # in normal places. + +PLUGINS="'html5_notifier', 'archive', 'zipdownload', 'password', 'managesieve', 'jqueryui', 'persistent_login'" + +# Add the carddav plugin if the user wants to install Nextcloud +if [ "${DISABLE_NEXTCLOUD}" != "0" ]; then + PLUGINS="$PLUGINS, 'carddav'" +fi + cat > $RCM_CONFIG < $RCM_CONFIG < $RCM_CONFIG < ${RCM_PLUGIN_DIR}/carddav/config.inc.php < ${RCM_PLUGIN_DIR}/carddav/config.inc.php < ${RCM_PLUGIN_DIR}/carddav/config.inc.php < EOF +fi # Create writable directories. mkdir -p /var/log/roundcubemail /var/tmp/roundcubemail $STORAGE_ROOT/mail/roundcube @@ -182,10 +196,12 @@ chmod 775 $STORAGE_ROOT/mail chown root.www-data $STORAGE_ROOT/mail/users.sqlite chmod 664 $STORAGE_ROOT/mail/users.sqlite -# Fix Carddav permissions: -chown -f -R root.www-data ${RCM_PLUGIN_DIR}/carddav -# root.www-data need all permissions, others only read -chmod -R 774 ${RCM_PLUGIN_DIR}/carddav +if [ "${DISABLE_NEXTCLOUD}" != "0" ]; then + # Fix Carddav permissions: + chown -f -R root.www-data ${RCM_PLUGIN_DIR}/carddav + # root.www-data need all permissions, others only read + chmod -R 774 ${RCM_PLUGIN_DIR}/carddav +fi # Run Roundcube database migration script (database is created if it does not exist) ${RCM_DIR}/bin/updatedb.sh --dir ${RCM_DIR}/SQL --package roundcube diff --git a/setup/zpush.sh b/setup/zpush.sh index a1253d2d..9c836549 100755 --- a/setup/zpush.sh +++ b/setup/zpush.sh @@ -64,13 +64,16 @@ rm -f /usr/local/lib/z-push/backend/imap/config.php cp conf/zpush/backend_imap.php /usr/local/lib/z-push/backend/imap/config.php sed -i "s%STORAGE_ROOT%$STORAGE_ROOT%" /usr/local/lib/z-push/backend/imap/config.php -# Configure CardDav -rm -f /usr/local/lib/z-push/backend/carddav/config.php -cp conf/zpush/backend_carddav.php /usr/local/lib/z-push/backend/carddav/config.php - -# Configure CalDav -rm -f /usr/local/lib/z-push/backend/caldav/config.php -cp conf/zpush/backend_caldav.php /usr/local/lib/z-push/backend/caldav/config.php +if [ "${DISABLE_NEXTCLOUD}" != "0" ]; then + + # Configure CardDav + rm -f /usr/local/lib/z-push/backend/carddav/config.php + cp conf/zpush/backend_carddav.php /usr/local/lib/z-push/backend/carddav/config.php + + # Configure CalDav + rm -f /usr/local/lib/z-push/backend/caldav/config.php + cp conf/zpush/backend_caldav.php /usr/local/lib/z-push/backend/caldav/config.php +fi # Configure Autodiscover rm -f /usr/local/lib/z-push/autodiscover/config.php