205 lines
7.4 KiB
Bash
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 "================================================================="
|