nextcloud-install/install.sh

205 lines
7.4 KiB
Bash

#!/usr/bin/env bash
# Nextcloud + Apache + PHP 8.3-FPM on Ubuntu 24.04
# - Applies requested php.ini edits
# - Apache with proxy_fcgi (no mod_php)
# - Downloads Nextcloud to /var/www/nextcloud
# - MariaDB DB + user
# - Redis for file locking (optional but recommended)
# - Cloudflare Tunnel / reverse-proxy aware (HTTPS forced, trusted proxy, real client IP)
set -euo pipefail
IFS=$'\n\t'
export DEBIAN_FRONTEND=noninteractive
# ====== EDIT ME ======
DOMAIN="domain.com"
NC_DIR="/var/www/nextcloud"
NC_DATA_DIR="/var/ncdata"
DB_NAME="nextcloud"
DB_USER="anon"
DB_PASS="changeMe"
ADMIN_USER="anon"
ADMIN_PASS="changeMe"
PHP_VER="8.3"
PHP_FPM_SOCK="/run/php/php${PHP_VER}-fpm.sock"
# ====== Base packages ======
apt-get update
apt-get -y upgrade
apt-get install -y software-properties-common apt-transport-https ca-certificates \
lsb-release unzip wget curl gnupg2 tar sudo
# ====== MariaDB ======
apt-get install -y mariadb-server mariadb-client
systemctl enable --now mariadb
# Headless mysql_secure_installation equivalent
mysql --protocol=socket <<'SQL'
DELETE FROM mysql.user WHERE User='';
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db LIKE 'test\_%';
FLUSH PRIVILEGES;
SQL
mysql --protocol=socket <<SQL
CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\`
CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost';
FLUSH PRIVILEGES;
SQL
# ====== PHP 8.3 + FPM + Redis/APCu/Imagick ======
apt-get install -y php${PHP_VER} php${PHP_VER}-fpm php${PHP_VER}-cli php${PHP_VER}-common \
php${PHP_VER}-mysql php${PHP_VER}-xml php${PHP_VER}-mbstring php${PHP_VER}-curl \
php${PHP_VER}-gd php${PHP_VER}-zip php${PHP_VER}-intl php${PHP_VER}-bcmath \
php${PHP_VER}-gmp php-redis php-apcu php-imagick
systemctl enable --now php${PHP_VER}-fpm
# ====== Apply requested php.ini edits ======
PHP_INI="/etc/php/${PHP_VER}/fpm/php.ini"
sed -ri 's/^;?\s*memory_limit\s*=.*/memory_limit = 512M/' "$PHP_INI"
sed -ri 's/^;?\s*upload_max_filesize\s*=.*/upload_max_filesize = 1024M/' "$PHP_INI"
sed -ri 's/^;?\s*post_max_size\s*=.*/post_max_size = 1024M/' "$PHP_INI"
sed -ri 's/^;?\s*max_execution_time\s*=.*/max_execution_time = 360/' "$PHP_INI"
sed -ri 's/^;?\s*opcache.enable\s*=.*/opcache.enable=1/' "$PHP_INI"
sed -ri 's/^;?\s*opcache.enable_cli\s*=.*/opcache.enable_cli=0/' "$PHP_INI"
systemctl restart php${PHP_VER}-fpm
# ====== Redis (for transactional file locking & memcache) ======
apt-get install -y redis-server
sed -ri 's|^#?\s*unixsocket\s+.*|unixsocket /var/run/redis/redis-server.sock|' /etc/redis/redis.conf
sed -ri 's|^#?\s*unixsocketperm\s+.*|unixsocketperm 770|' /etc/redis/redis.conf
install -d -m 0755 /var/run/redis
systemctl enable --now redis-server
usermod -aG redis www-data || true
systemctl restart redis-server
# ====== Apache (NO mod_php; we use php-fpm via proxy_fcgi) ======
apt-get install -y apache2
a2enmod rewrite headers env dir mime ssl proxy_fcgi setenvif
a2enconf php${PHP_VER}-fpm # .php -> PHP-FPM
a2dismod mpm_prefork >/dev/null 2>&1 || true
a2enmod mpm_event >/dev/null 2>&1 || true
# (Optional) If you want Apache logs to show real client IPs with Cloudflare:
a2enmod remoteip >/dev/null 2>&1 || true
cat >/etc/apache2/conf-available/remoteip-cloudflare.conf <<'EOF'
# Trust localhost (cloudflared) as the proxy and use CF's connecting IP header
RemoteIPHeader CF-Connecting-IP
# Since cloudflared connects from 127.0.0.1, mark it as trusted
RemoteIPTrustedProxy 127.0.0.1
RemoteIPTrustedProxy ::1
EOF
a2enconf remoteip-cloudflare >/dev/null 2>&1 || true
# Nextcloud vhost (HTTP only; TLS is terminated by Cloudflare Tunnel)
cat >/etc/apache2/sites-available/nextcloud.conf <<EOF
<VirtualHost *:80>
ServerName ${DOMAIN}
DocumentRoot ${NC_DIR}
<Directory ${NC_DIR}>
Require all granted
AllowOverride All
Options FollowSymLinks MultiViews
<IfModule mod_dav.c>
Dav off
</IfModule>
</Directory>
# Large uploads
LimitRequestBody 0
SetEnv HOME ${NC_DIR}
SetEnv HTTP_HOME ${NC_DIR}
# Security headers (add HSTS at the edge in Cloudflare if desired)
Header always set Referrer-Policy "no-referrer"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
# PHP-FPM socket
<FilesMatch "\.php$">
SetHandler "proxy:unix:${PHP_FPM_SOCK}|fcgi://localhost/"
</FilesMatch>
ErrorLog \${APACHE_LOG_DIR}/nextcloud_error.log
CustomLog \${APACHE_LOG_DIR}/nextcloud_access.log combined
</VirtualHost>
EOF
a2ensite nextcloud.conf
a2dissite 000-default.conf >/dev/null 2>&1 || true
systemctl enable --now apache2
apache2ctl configtest
systemctl reload apache2
# ====== Download Nextcloud (latest) ======
mkdir -p /tmp/nc
cd /tmp/nc
wget -q https://download.nextcloud.com/server/releases/latest.zip
unzip -q -o latest.zip
# Deploy to /var/www/nextcloud
rm -rf "${NC_DIR}"
mv nextcloud "${NC_DIR}"
# Ownership & permissions
install -d -m 0750 "${NC_DATA_DIR}"
chown -R www-data:www-data "${NC_DIR}" "${NC_DATA_DIR}"
chmod -R 750 "${NC_DIR}"
# ====== Bootstrap Nextcloud (non-interactive) ======
sudo -u www-data php "${NC_DIR}/occ" maintenance:install \
--database "mysql" \
--database-name "${DB_NAME}" \
--database-user "${DB_USER}" \
--database-pass "${DB_PASS}" \
--admin-user "${ADMIN_USER}" \
--admin-pass "${ADMIN_PASS}" \
--data-dir "${NC_DATA_DIR}"
# ====== Reverse-proxy / Cloudflare Tunnel awareness ======
# Use HTTPS in public URL and force HTTPS (fixes OIDC "must access via HTTPS")
sudo -u www-data php "${NC_DIR}/occ" config:system:set overwrite.cli.url --value="https://${DOMAIN}"
sudo -u www-data php "${NC_DIR}/occ" config:system:set overwriteprotocol --value="https"
# Trust the local proxy (cloudflared connects from localhost)
sudo -u www-data php "${NC_DIR}/occ" config:system:set trusted_proxies 0 --value="127.0.0.1"
sudo -u www-data php "${NC_DIR}/occ" config:system:set trusted_proxies 1 --value="::1"
# Record Cloudflare's real client IP header inside Nextcloud
sudo -u www-data php "${NC_DIR}/occ" config:system:set forwarded_for_headers 0 --value="HTTP_CF_CONNECTING_IP"
# Trusted domain
sudo -u www-data php "${NC_DIR}/occ" config:system:set trusted_domains 1 --value="${DOMAIN}"
# Caching: APCu local + Redis locking (unix socket)
sudo -u www-data php "${NC_DIR}/occ" config:system:set memcache.local --value='\OC\Memcache\APCu'
sudo -u www-data php "${NC_DIR}/occ" config:system:set memcache.locking --value='\OC\Memcache\Redis'
sudo -u www-data php "${NC_DIR}/occ" config:system:set redis --type=json --value='{"host":"\/var\/run\/redis\/redis-server.sock","port":0,"timeout":1.5}'
# ====== Cron every 5 minutes ======
cat >/etc/cron.d/nextcloud <<EOF
*/5 * * * * www-data php -f ${NC_DIR}/cron.php
EOF
chmod 0644 /etc/cron.d/nextcloud
systemctl restart cron
echo "================================================================="
echo " Nextcloud ready behind reverse proxy at: https://${DOMAIN}"
echo " Admin: ${ADMIN_USER} / ${ADMIN_PASS}"
echo " Data dir: ${NC_DATA_DIR}"
echo "-----------------------------------------------------------------"
echo " Notes:"
echo " - TLS is terminated by Cloudflare Tunnel; Apache listens on :80."
echo " - OIDC and login pages will now require HTTPS and work correctly."
echo " - Real client IPs appear via CF-Connecting-IP."
echo "================================================================="