From 8cda037dc8c8b1182bf70dfcaea9814958085bed Mon Sep 17 00:00:00 2001 From: RomanNum3ral Date: Wed, 18 Mar 2026 17:18:26 +0000 Subject: [PATCH] Add arch_install.sh --- arch_install.sh | 355 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 arch_install.sh diff --git a/arch_install.sh b/arch_install.sh new file mode 100644 index 0000000..40fb4a4 --- /dev/null +++ b/arch_install.sh @@ -0,0 +1,355 @@ +#!/usr/bin/env bash +# Nextcloud + Apache + PHP-FPM on Arch Linux +# Production-oriented, reverse-proxy aware +# +# What this does: +# - Installs Apache, MariaDB, Redis, PHP-FPM and needed PHP extensions +# - Downloads official Nextcloud release tarball +# - Configures Apache -> PHP-FPM via mod_proxy_fcgi +# - Configures MariaDB database/user +# - Configures Redis over unix socket for locking/cache +# - Installs Nextcloud non-interactively +# - Sets trusted proxy / HTTPS overwrite options +# - Adds cron job for background jobs +# +# Assumptions: +# - Arch server with systemd +# - You want Apache listening on :80 and TLS terminated upstream +# - Apache runs as user/group "http" on Arch +# +# Run as root. + +set -euo pipefail +IFS=$'\n\t' + +# ====== EDIT ME ====== +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" + +# If behind Cloudflare Tunnel or another local reverse proxy: +TRUST_LOCAL_PROXY="true" +REAL_IP_HEADER="CF-Connecting-IP" # or X-Forwarded-For if not Cloudflare + +# Download URL: pin a version for production stability +# Check https://download.nextcloud.com/server/releases/ +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" + +# ====== Sanity checks ====== +if [[ $EUID -ne 0 ]]; then + echo "Run this script as root." + exit 1 +fi + +for v in DOMAIN NC_DIR NC_DATA_DIR DB_NAME DB_USER DB_PASS ADMIN_USER ADMIN_PASS NC_VERSION; do + if [[ -z "${!v}" ]]; then + echo "Variable $v is empty. Edit the script first." + exit 1 + fi +done + +# ====== Packages ====== +pacman -Syu --noconfirm + +pacman -S --needed --noconfirm \ + apache mariadb redis cronie \ + php php-fpm php-gd php-intl php-sodium php-zip php-apcu php-redis php-imagick \ + curl wget tar bzip2 unzip sudo + +# ====== Directories ====== +install -d -m 0755 /srv/http +install -d -m 0750 "${NC_DATA_DIR}" + +# ====== MariaDB ====== +if [[ ! -d /var/lib/mysql/mysql ]]; then + mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql +fi + +systemctl enable --now mariadb + +# Headless mysql_secure_installation-ish cleanup +mysql <<'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 <> "$PHP_INI" + fi + fi +} + +# Core modules shipped as split packages / shared modules on Arch +for ext in gd intl mysqli pdo_mysql sodium zip; do + enable_php_ext "$ext" +done + +# Recommended php.ini tuning for Nextcloud +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*output_buffering\s*=.*/output_buffering = Off/' "$PHP_INI" +sed -ri 's/^;?\s*date\.timezone\s*=.*/date.timezone = UTC/' "$PHP_INI" + +# OPcache tuning +if grep -Eq '^\s*;?\s*opcache.enable\s*=' "$PHP_INI"; then + sed -ri 's/^;?\s*opcache.enable\s*=.*/opcache.enable=1/' "$PHP_INI" +else + printf "\nopcache.enable=1\n" >> "$PHP_INI" +fi + +if grep -Eq '^\s*;?\s*opcache.enable_cli\s*=' "$PHP_INI"; then + sed -ri 's/^;?\s*opcache.enable_cli\s*=.*/opcache.enable_cli=0/' "$PHP_INI" +else + printf "opcache.enable_cli=0\n" >> "$PHP_INI" +fi + +if grep -Eq '^\s*;?\s*opcache.interned_strings_buffer\s*=' "$PHP_INI"; then + sed -ri 's/^;?\s*opcache.interned_strings_buffer\s*=.*/opcache.interned_strings_buffer=16/' "$PHP_INI" +else + printf "opcache.interned_strings_buffer=16\n" >> "$PHP_INI" +fi + +if grep -Eq '^\s*;?\s*opcache.max_accelerated_files\s*=' "$PHP_INI"; then + sed -ri 's/^;?\s*opcache.max_accelerated_files\s*=.*/opcache.max_accelerated_files=10000/' "$PHP_INI" +else + printf "opcache.max_accelerated_files=10000\n" >> "$PHP_INI" +fi + +if grep -Eq '^\s*;?\s*opcache.memory_consumption\s*=' "$PHP_INI"; then + sed -ri 's/^;?\s*opcache.memory_consumption\s*=.*/opcache.memory_consumption=256/' "$PHP_INI" +else + printf "opcache.memory_consumption=256\n" >> "$PHP_INI" +fi + +if grep -Eq '^\s*;?\s*opcache.save_comments\s*=' "$PHP_INI"; then + sed -ri 's/^;?\s*opcache.save_comments\s*=.*/opcache.save_comments=1/' "$PHP_INI" +else + printf "opcache.save_comments=1\n" >> "$PHP_INI" +fi + +# php-fpm: use unix socket and Apache-compatible user/group +PHP_FPM_WWW_CONF="/etc/php/php-fpm.d/www.conf" +sed -ri 's|^user\s*=.*|user = http|' "$PHP_FPM_WWW_CONF" +sed -ri 's|^group\s*=.*|group = http|' "$PHP_FPM_WWW_CONF" +sed -ri 's|^listen\s*=.*|listen = /run/php-fpm/php-fpm.sock|' "$PHP_FPM_WWW_CONF" +sed -ri 's|^;?listen.owner\s*=.*|listen.owner = http|' "$PHP_FPM_WWW_CONF" +sed -ri 's|^;?listen.group\s*=.*|listen.group = http|' "$PHP_FPM_WWW_CONF" +sed -ri 's|^;?listen.mode\s*=.*|listen.mode = 0660|' "$PHP_FPM_WWW_CONF" +sed -ri 's|^;?env\[HOSTNAME\].*|env[HOSTNAME] = $HOSTNAME|' "$PHP_FPM_WWW_CONF" || true +sed -ri 's|^;?env\[PATH\].*|env[PATH] = /usr/local/bin:/usr/bin:/bin|' "$PHP_FPM_WWW_CONF" || true +sed -ri 's|^;?env\[TMP\].*|env[TMP] = /tmp|' "$PHP_FPM_WWW_CONF" || true +sed -ri 's|^;?env\[TMPDIR\].*|env[TMPDIR] = /tmp|' "$PHP_FPM_WWW_CONF" || true +sed -ri 's|^;?env\[TEMP\].*|env[TEMP] = /tmp|' "$PHP_FPM_WWW_CONF" || true + +systemctl enable --now php-fpm +systemctl restart php-fpm + +# ====== Redis ====== +REDIS_CONF="/etc/redis/redis.conf" + +sed -ri 's|^port .*|port 0|' "$REDIS_CONF" +if grep -Eq '^\s*unixsocket\s+' "$REDIS_CONF"; then + sed -ri 's|^unixsocket\s+.*|unixsocket /run/redis/redis.sock|' "$REDIS_CONF" +else + printf "\nunixsocket /run/redis/redis.sock\n" >> "$REDIS_CONF" +fi + +if grep -Eq '^\s*unixsocketperm\s+' "$REDIS_CONF"; then + sed -ri 's|^unixsocketperm\s+.*|unixsocketperm 770|' "$REDIS_CONF" +else + printf "unixsocketperm 770\n" >> "$REDIS_CONF" +fi + +install -d -m 0755 /run/redis +usermod -aG redis http || true + +systemctl enable --now redis +systemctl restart redis + +# ====== Apache ====== +HTTPD_CONF="/etc/httpd/conf/httpd.conf" + +# Enable required modules if commented +sed -ri 's|^#(LoadModule proxy_module modules/mod_proxy.so)|\1|' "$HTTPD_CONF" +sed -ri 's|^#(LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so)|\1|' "$HTTPD_CONF" +sed -ri 's|^#(LoadModule rewrite_module modules/mod_rewrite.so)|\1|' "$HTTPD_CONF" +sed -ri 's|^#(LoadModule headers_module modules/mod_headers.so)|\1|' "$HTTPD_CONF" +sed -ri 's|^#(LoadModule remoteip_module modules/mod_remoteip.so)|\1|' "$HTTPD_CONF" || true +sed -ri 's|^#(LoadModule ssl_module modules/mod_ssl.so)|\1|' "$HTTPD_CONF" || true +sed -ri 's|^#(LoadModule socache_shmcb_module modules/mod_socache_shmcb.so)|\1|' "$HTTPD_CONF" || true + +# ServerName to silence warning +if ! grep -Eq '^\s*ServerName\s+' "$HTTPD_CONF"; then + printf "\nServerName %s\n" "$DOMAIN" >> "$HTTPD_CONF" +fi + +# Include extra vhosts dir +install -d -m 0755 /etc/httpd/conf/extra +if ! grep -Fq "IncludeOptional conf/extra/*.conf" "$HTTPD_CONF"; then + printf "\nIncludeOptional conf/extra/*.conf\n" >> "$HTTPD_CONF" +fi + +# RemoteIP config for local tunnel/proxy +cat > /etc/httpd/conf/extra/remoteip-nextcloud.conf < /etc/httpd/conf/extra/nextcloud.conf < + ServerName ${DOMAIN} + DocumentRoot ${NC_DIR} + + + Require all granted + AllowOverride All + Options FollowSymLinks MultiViews + + + Dav off + + + + 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" + + + + LimitRequestBody 0 + SetEnv HOME ${NC_DIR} + SetEnv HTTP_HOME ${NC_DIR} + + + SetHandler "proxy:unix:/run/php-fpm/php-fpm.sock|fcgi://localhost/" + + + ErrorLog "/var/log/httpd/nextcloud_error.log" + CustomLog "/var/log/httpd/nextcloud_access.log" combined + +EOF + +systemctl enable --now httpd +httpd -t +systemctl reload httpd + +# ====== Download Nextcloud (official upstream tarball) ====== +TMPDIR="$(mktemp -d)" +trap 'rm -rf "$TMPDIR"' EXIT + +cd "$TMPDIR" +curl -fsSLo nextcloud.tar.bz2 "${NC_TARBALL_URL}" +curl -fsSLo nextcloud.tar.bz2.sha512 "${NC_SHA512_URL}" + +# Verify sha512 +sha512sum -c nextcloud.tar.bz2.sha512 + +tar -xjf nextcloud.tar.bz2 + +# Deploy +rm -rf "${NC_DIR}" +mv nextcloud "${NC_DIR}" + +# Ownership & permissions +chown -R http:http "${NC_DIR}" "${NC_DATA_DIR}" +find "${NC_DIR}" -type d -exec chmod 0750 {} \; +find "${NC_DIR}" -type f -exec chmod 0640 {} \; +chmod 0750 "${NC_DATA_DIR}" + +# Required writable app dirs +install -d -o http -g http -m 0750 "${NC_DIR}/data" +install -d -o http -g http -m 0750 "${NC_DIR}/config" +install -d -o http -g http -m 0750 "${NC_DIR}/apps" + +# ====== Install Nextcloud ====== +sudo -u http 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 / HTTPS awareness ====== +sudo -u http php "${NC_DIR}/occ" config:system:set overwrite.cli.url --value="https://${DOMAIN}" +sudo -u http php "${NC_DIR}/occ" config:system:set overwriteprotocol --value="https" + +if [[ "${TRUST_LOCAL_PROXY}" == "true" ]]; then + sudo -u http php "${NC_DIR}/occ" config:system:set trusted_proxies 0 --value="127.0.0.1" + sudo -u http php "${NC_DIR}/occ" config:system:set trusted_proxies 1 --value="::1" + + if [[ "${REAL_IP_HEADER}" == "CF-Connecting-IP" ]]; then + sudo -u http php "${NC_DIR}/occ" config:system:set forwarded_for_headers 0 --value="HTTP_CF_CONNECTING_IP" + else + sudo -u http php "${NC_DIR}/occ" config:system:set forwarded_for_headers 0 --value="HTTP_X_FORWARDED_FOR" + fi +fi + +sudo -u http php "${NC_DIR}/occ" config:system:set trusted_domains 1 --value="${DOMAIN}" + +# ====== Memory cache / locking ====== +sudo -u http php "${NC_DIR}/occ" config:system:set memcache.local --value='\OC\Memcache\APCu' +sudo -u http php "${NC_DIR}/occ" config:system:set memcache.locking --value='\OC\Memcache\Redis' +sudo -u http php "${NC_DIR}/occ" config:system:set redis --type=json --value='{"host":"\/run\/redis\/redis.sock","port":0,"timeout":1.5}' + +# ====== Background jobs (recommended) ====== +systemctl enable --now cronie + +cat > /etc/cron.d/nextcloud <