#!/usr/bin/env bash # Nextcloud + Apache + PHP 8.3 (php-legacy) + MariaDB + Valkey on Arch Linux # Optimized version with PHP extension loading fixes set -euo pipefail IFS=$'\n\t' # ========================= # EDIT THESE VARIABLES # ========================= DOMAIN="domain.com" NC_DIR="/srv/http/nextcloud" NC_DATA_DIR="/srv/nextcloud-data" DB_NAME="nextcloud" DB_USER="nextcloud" DB_PASS="changeMe" ADMIN_USER="admin" ADMIN_PASS="changeMe" TRUST_LOCAL_PROXY="true" REAL_IP_HEADER="CF-Connecting-IP" NC_VERSION="33.0.0" NC_TARBALL_URL="https://download.nextcloud.com/server/releases/nextcloud-${NC_VERSION}.tar.bz2" NC_SHA512_URL="https://download.nextcloud.com/server/releases/nextcloud-${NC_VERSION}.tar.bz2.sha512" PHP_BIN="/usr/bin/php-legacy" PHP_INI="/etc/php-legacy/php.ini" PHP_FPM_WWW_CONF="/etc/php-legacy/php-fpm.d/www.conf" PHP_FPM_SERVICE="php-fpm-legacy" KV_SOCK="/run/valkey/valkey.sock" # ========================= # HELPERS # ========================= log() { printf '\n==== %s ====\n' "$1" } require_root() { if [[ $EUID -ne 0 ]]; then echo "Run this script as root." exit 1 fi } check_vars() { local vars=(DOMAIN NC_DIR NC_DATA_DIR DB_NAME DB_USER DB_PASS ADMIN_USER ADMIN_PASS) for v in "${vars[@]}"; do if [[ -z "${!v}" ]]; then echo "Variable $v is empty. Edit the script first." exit 1 fi done } set_ini_value() { local key="$1" local value="$2" if grep -Eq "^[;[:space:]]*${key}[[:space:]]*=" "$PHP_INI"; then sed -ri "s|^[;[:space:]]*${key}[[:space:]]*=.*|${key} = ${value}|" "$PHP_INI" else printf "\n%s = %s\n" "$key" "$value" >> "$PHP_INI" fi } set_fpm_value() { local key="$1" local value="$2" if grep -Eq "^[;[:space:]]*${key}[[:space:]]*=" "$PHP_FPM_WWW_CONF"; then sed -ri "s|^[;[:space:]]*${key}[[:space:]]*=.*|${key} = ${value}|" "$PHP_FPM_WWW_CONF" else printf "\n%s = %s\n" "$key" "$value" >> "$PHP_FPM_WWW_CONF" fi } detect_kv_conf() { for f in /etc/valkey/valkey.conf /etc/redis/redis.conf /etc/redis.conf; do [[ -f "$f" ]] && echo "$f" && return done } detect_kv_service() { for s in valkey redis; do [[ -f "/usr/lib/systemd/system/${s}.service" ]] && echo "$s" && return done } require_root check_vars # ========================= # PACKAGES # ========================= log "Updating system and installing packages" pacman -Syu --noconfirm pacman -S --needed --noconfirm \ apache mariadb valkey cronie \ php-legacy php-legacy-fpm php-legacy-gd php-legacy-intl php-legacy-sodium \ php-legacy-apcu php-legacy-redis php-legacy-imagick php-legacy-igbinary \ curl wget tar bzip2 unzip sudo KV_CONF="$(detect_kv_conf)" KV_SERVICE="$(detect_kv_service)" # ========================= # DIRECTORIES # ========================= log "Creating base directories" install -d -m 0755 /srv/http install -d -m 0750 "${NC_DATA_DIR}" # ========================= # MARIADB # ========================= log "Initializing and configuring MariaDB" if [[ ! -d /var/lib/mysql/mysql ]]; then mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql fi systemctl enable --now mariadb mariadb < temp && mv temp "$PHP_INI" set_ini_value "memory_limit" "512M" set_ini_value "upload_max_filesize" "1024M" set_ini_value "post_max_size" "1024M" set_ini_value "output_buffering" "Off" # Opcache if ! grep -Eq '^[[:space:]]*zend_extension[[:space:]]*=.*opcache' "$PHP_INI"; then sed -i "1i zend_extension=opcache" "$PHP_INI" fi set_ini_value "opcache.enable" "1" set_ini_value "opcache.memory_consumption" "256" set_ini_value "opcache.save_comments" "1" # PHP-FPM Socket Setup set_fpm_value "user" "http" set_fpm_value "group" "http" set_fpm_value "listen" "/run/php-fpm-legacy/php-fpm.sock" set_fpm_value "listen.owner" "http" set_fpm_value "listen.group" "http" set_fpm_value "listen.mode" "0660" systemctl enable --now "${PHP_FPM_SERVICE}" systemctl restart "${PHP_FPM_SERVICE}" # ========================= # VALKEY # ========================= log "Configuring Valkey/Redis" sed -ri 's|^port .*|port 0|' "${KV_CONF}" if grep -Eq '^[[:space:]]*unixsocket[[:space:]]+' "${KV_CONF}"; then sed -ri "s|^[[:space:]]*unixsocket[[:space:]]+.*|unixsocket ${KV_SOCK}|" "${KV_CONF}" else printf "\nunixsocket %s\nunixsocketperm 770\n" "${KV_SOCK}" >> "${KV_CONF}" fi usermod -aG valkey http 2>/dev/null || true usermod -aG redis http 2>/dev/null || true systemctl enable --now "${KV_SERVICE}" systemctl restart "${KV_SERVICE}" # ========================= # APACHE CONFIGURATION (FIXED) # ========================= log "Configuring Apache" HTTPD_CONF="/etc/httpd/conf/httpd.conf" # Enable required modules for mod in proxy proxy_fcgi rewrite headers remoteip env mime dir setenvif dav dav_fs dav_lock; do sed -ri "s|^#(LoadModule ${mod}_module)| \1|" "${HTTPD_CONF}" done # CLEANUP: Aggressively disable all default extra configs and wildcard includes sed -i 's/^[[:space:]]*Include conf\/extra\/httpd-.*\.conf/#&/' "${HTTPD_CONF}" sed -i '/IncludeOptional conf\/extra\/\*\.conf/d' "${HTTPD_CONF}" # Add ONLY the specific Nextcloud include if ! grep -Fq "Include conf/extra/nextcloud.conf" "${HTTPD_CONF}"; then printf "\nInclude conf/extra/nextcloud.conf\n" >> "${HTTPD_CONF}" fi cat > /etc/httpd/conf/extra/nextcloud.conf < ServerName ${DOMAIN} DocumentRoot ${NC_DIR} Require all granted AllowOverride All Options FollowSymLinks MultiViews Dav off SetHandler "proxy:unix:/run/php-fpm-legacy/php-fpm.sock|fcgi://localhost/" ErrorLog "/var/log/httpd/nextcloud_error.log" EOF systemctl enable --now httpd systemctl restart httpd # ========================= # DOWNLOAD & INSTALL # ========================= log "Downloading and Deploying Nextcloud" TMPDIR="$(mktemp -d)" cd "$TMPDIR" curl -fsSLo nextcloud.tar.bz2 "${NC_TARBALL_URL}" tar -xjf nextcloud.tar.bz2 rm -rf "${NC_DIR}" mv nextcloud "${NC_DIR}" chown -R http:http "${NC_DIR}" "${NC_DATA_DIR}" log "Running Nextcloud installer" sudo -u http "${PHP_BIN}" "${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}" # Apply System Configs sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set trusted_domains 1 --value="${DOMAIN}" sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set memcache.local --value='\OC\Memcache\APCu' sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set memcache.locking --value='\OC\Memcache\Redis' sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set redis --type=json --value="{\"host\":\"${KV_SOCK}\",\"port\":0,\"timeout\":1.5}" log "Installation Complete!" log "Please edit trusted domains at: /srv/http/nextcloud/config/config.php"