Update arch_install.sh

This commit is contained in:
RomanNum3ral 2026-03-18 17:56:38 +00:00
parent e6b6f1ae86
commit 88433fd523
1 changed files with 341 additions and 298 deletions

View File

@ -1,390 +1,433 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Nextcloud + Apache + PHP 8.3 (php-legacy) + MariaDB + Redis on Arch Linux set -Eeuo pipefail
# Production-oriented, reverse-proxy aware
#
# Run as root:
# sudo ./arch_install.sh
set -euo pipefail ########################################
IFS=$'\n\t' # USER CONFIG
########################################
# ========================= # Site / domain
# EDIT THESE VARIABLES NEXTCLOUD_DOMAIN="cloud.example.com"
# ========================= TRUSTED_DOMAINS=("cloud.example.com" "192.168.1.10")
DOMAIN="domain.com"
NC_DIR="/srv/http/nextcloud" # Paths
NC_DATA_DIR="/srv/nextcloud-data" NEXTCLOUD_WEBROOT="/usr/share/webapps/nextcloud"
NEXTCLOUD_CONFIG_DIR="/etc/webapps/nextcloud"
NEXTCLOUD_DATA_DIR="/var/lib/nextcloud/data"
# Database
DB_NAME="nextcloud" DB_NAME="nextcloud"
DB_USER="nextcloud" DB_USER="nextcloud"
DB_PASS="changeMe" DB_PASS="CHANGE_ME_DB_PASSWORD"
ADMIN_USER="admin" # Nextcloud admin user
ADMIN_PASS="changeMe" NC_ADMIN_USER="admin"
NC_ADMIN_PASS="CHANGE_ME_ADMIN_PASSWORD"
# If you're behind Cloudflare Tunnel or another reverse proxy: # PHP / timezone
TRUST_LOCAL_PROXY="true" PHP_MEMORY_LIMIT="1024M"
REAL_IP_HEADER="CF-Connecting-IP" # use X-Forwarded-For if not Cloudflare PHP_UPLOAD_LIMIT="16G"
PHP_MAX_EXECUTION_TIME="3600"
PHP_TIMEZONE="America/New_York"
# Pin a specific release for production stability # Apache
NC_VERSION="33.0.0" APACHE_RUN_USER="http"
NC_TARBALL_URL="https://download.nextcloud.com/server/releases/nextcloud-${NC_VERSION}.tar.bz2" APACHE_RUN_GROUP="http"
NC_SHA512_URL="https://download.nextcloud.com/server/releases/nextcloud-${NC_VERSION}.tar.bz2.sha512"
# HTTPS note:
# This script configures HTTP on port 80 only.
# Put it behind your TLS reverse proxy or add your cert/vhost later.
# SMB external storage mount (optional)
ENABLE_SMB_MOUNT="false"
SMB_REMOTE="//server/share"
SMB_MOUNTPOINT="/mnt/nextcloud"
SMB_CREDENTIALS_FILE="/root/.smbcredentials"
# If ENABLE_SMB_MOUNT=true, this gets added to /etc/fstab
# Arch uses user/group "http", not "www-data"
SMB_FSTAB_OPTIONS="rw,credentials=${SMB_CREDENTIALS_FILE},uid=http,gid=http,iocharset=utf8,file_mode=0770,dir_mode=0770,noserverino,nounix,_netdev,x-systemd.automount"
########################################
# INTERNALS
########################################
# PHP legacy paths/services on Arch
PHP_BIN="/usr/bin/php-legacy"
PHP_INI="/etc/php-legacy/php.ini" PHP_INI="/etc/php-legacy/php.ini"
PHP_FPM_WWW_CONF="/etc/php-legacy/php-fpm.d/www.conf" PHP_FPM_POOL_CONF="/etc/php-legacy/php-fpm.d/www.conf"
PHP_FPM_SERVICE="php-fpm-legacy" HTTPD_CONF="/etc/httpd/conf/httpd.conf"
HTTPD_NEXTCLOUD_CONF="/etc/httpd/conf/extra/nextcloud.conf"
HTTPD_WELLKNOWN_CONF="/etc/httpd/conf/extra/nextcloud-wellknown.conf"
VALKEY_CONF="/etc/valkey/valkey.conf"
MYSQL_SOCKET="/run/mysqld/mysqld.sock"
# Redis socket
REDIS_SOCK="/run/redis/redis.sock"
# =========================
# HELPER FUNCTIONS
# =========================
log() { log() {
printf '\n==== %s ====\n' "$1" echo
echo "==== $* ===="
}
die() {
echo "ERROR: $*" >&2
exit 1
} }
require_root() { require_root() {
if [[ $EUID -ne 0 ]]; then [[ "${EUID}" -eq 0 ]] || die "Run this script as root."
echo "Run this script as root."
exit 1
fi
} }
check_vars() { backup_file() {
local vars=( local f="$1"
DOMAIN NC_DIR NC_DATA_DIR [[ -f "$f" ]] && cp -an "$f" "${f}.bak.$(date +%F-%H%M%S)" || true
DB_NAME DB_USER DB_PASS
ADMIN_USER ADMIN_PASS
NC_VERSION NC_TARBALL_URL NC_SHA512_URL
)
for v in "${vars[@]}"; do
if [[ -z "${!v}" ]]; then
echo "Variable $v is empty. Edit the script first."
exit 1
fi
done
} }
enable_php_ext() { replace_or_append_ini() {
local ext="$1"
if ! grep -Eq "^[[:space:]]*extension=${ext}\.so" "$PHP_INI"; then
sed -i "/^;extension=${ext}\.so/s/^;//" "$PHP_INI" || true
if ! grep -Eq "^[[:space:]]*extension=${ext}\.so" "$PHP_INI"; then
printf "\nextension=%s.so\n" "$ext" >> "$PHP_INI"
fi
fi
}
set_ini_value() {
local key="$1" local key="$1"
local value="$2" local value="$2"
if grep -Eq "^[;[:space:]]*${key}[[:space:]]*=" "$PHP_INI"; then local file="$3"
sed -ri "s|^[;[:space:]]*${key}[[:space:]]*=.*|${key} = ${value}|" "$PHP_INI" if grep -Eq "^[;[:space:]]*${key}[[:space:]]*=" "$file"; then
sed -ri "s|^[;[:space:]]*${key}[[:space:]]*=.*|${key} = ${value}|g" "$file"
else else
printf "\n%s = %s\n" "$key" "$value" >> "$PHP_INI" echo "${key} = ${value}" >> "$file"
fi fi
} }
set_fpm_value() { ensure_line() {
local key="$1" local line="$1"
local value="$2" local file="$2"
if grep -Eq "^[;[:space:]]*${key}[[:space:]]*=" "$PHP_FPM_WWW_CONF"; then grep -Fqx "$line" "$file" || echo "$line" >> "$file"
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
} }
# ========================= random_secret() {
# PRECHECKS tr -dc 'A-Za-z0-9!@#%^*_+=' < /dev/urandom | head -c 32
# ========================= }
occ() {
sudo -u "${APACHE_RUN_USER}" php-legacy "${NEXTCLOUD_WEBROOT}/occ" "$@"
}
########################################
# START
########################################
require_root require_root
check_vars
log "Updating system and installing packages" log "Validating variables"
[[ "${NEXTCLOUD_DOMAIN}" != "cloud.example.com" ]] || echo "WARNING: NEXTCLOUD_DOMAIN still set to default example value."
[[ "${DB_PASS}" != "CHANGE_ME_DB_PASSWORD" ]] || die "Set DB_PASS at the top of the script."
[[ "${NC_ADMIN_PASS}" != "CHANGE_ME_ADMIN_PASSWORD" ]] || die "Set NC_ADMIN_PASS at the top of the script."
if [[ "${ENABLE_SMB_MOUNT}" == "true" ]]; then
[[ -f "${SMB_CREDENTIALS_FILE}" ]] || die "ENABLE_SMB_MOUNT=true but credentials file ${SMB_CREDENTIALS_FILE} does not exist."
fi
log "Installing packages"
pacman -Syu --noconfirm pacman -Syu --noconfirm
pacman -S --needed --noconfirm \ pacman -S --needed --noconfirm \
apache mariadb redis cronie \ apache \
php-legacy php-legacy-fpm php-legacy-gd php-legacy-intl php-legacy-sodium \ mariadb \
php-legacy-apcu php-legacy-redis php-legacy-imagick \ nextcloud \
curl wget tar bzip2 unzip sudo php-legacy \
php-legacy-fpm \
php-legacy-gd \
php-legacy-apcu \
php-legacy-redis \
php-legacy-intl \
php-legacy-sodium \
valkey \
cifs-utils \
smbclient \
curl \
sudo \
unzip \
bzip2 \
tar
# =========================
# DIRECTORIES
# =========================
log "Creating base directories" log "Creating base directories"
install -d -m 0755 /srv/http
install -d -m 0750 "${NC_DATA_DIR}"
# ========================= mkdir -p "${NEXTCLOUD_DATA_DIR}"
# MARIADB chown -R "${APACHE_RUN_USER}:${APACHE_RUN_GROUP}" /var/lib/nextcloud
# ========================= chmod 0750 /var/lib/nextcloud
chmod 0750 "${NEXTCLOUD_DATA_DIR}"
mkdir -p /var/log/httpd
mkdir -p /run/httpd
log "Initializing and configuring MariaDB" log "Initializing and configuring MariaDB"
if [[ ! -d /var/lib/mysql/mysql ]]; then if [[ ! -d /var/lib/mysql/mysql ]]; then
mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql
fi fi
systemctl enable --now mariadb systemctl enable --now mariadb
mysql <<'SQL' # Wait for MariaDB
DELETE FROM mysql.user WHERE User=''; for _ in {1..30}; do
DROP DATABASE IF EXISTS test; if mariadb-admin ping >/dev/null 2>&1; then
DELETE FROM mysql.db WHERE Db='test' OR Db LIKE 'test\_%'; break
FLUSH PRIVILEGES; fi
SQL sleep 1
mysql <<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
# =========================
log "Configuring PHP 8.3 legacy stack"
# Required/recommended extensions for Nextcloud
for ext in gd intl mysqli pdo_mysql sodium zip apcu redis imagick; do
enable_php_ext "$ext"
done done
# Nextcloud-oriented php.ini tuning mariadb-admin ping >/dev/null 2>&1 || die "MariaDB did not come up."
set_ini_value "memory_limit" "512M"
set_ini_value "upload_max_filesize" "1024M"
set_ini_value "post_max_size" "1024M"
set_ini_value "max_execution_time" "360"
set_ini_value "max_input_time" "360"
set_ini_value "output_buffering" "Off"
set_ini_value "date.timezone" "UTC"
# OPcache # Secure-ish local MariaDB setup and create DB/user
set_ini_value "zend_extension" "opcache" mariadb <<SQL
set_ini_value "opcache.enable" "1" CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\`
set_ini_value "opcache.enable_cli" "0" CHARACTER SET utf8mb4
set_ini_value "opcache.interned_strings_buffer" "16" COLLATE utf8mb4_general_ci;
set_ini_value "opcache.max_accelerated_files" "10000"
set_ini_value "opcache.memory_consumption" "256"
set_ini_value "opcache.save_comments" "1"
set_ini_value "opcache.revalidate_freq" "60"
# PHP-FPM pool config for Apache's http user CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
set_fpm_value "user" "http" ALTER USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
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"
set_fpm_value "pm" "dynamic"
set_fpm_value "pm.max_children" "64"
set_fpm_value "pm.start_servers" "8"
set_fpm_value "pm.min_spare_servers" "4"
set_fpm_value "pm.max_spare_servers" "16"
systemctl enable --now "${PHP_FPM_SERVICE}" GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost';
systemctl restart "${PHP_FPM_SERVICE}" FLUSH PRIVILEGES;
# ========================= DELETE FROM mysql.user WHERE User='';
# REDIS DROP DATABASE IF EXISTS test;
# ========================= DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
log "Configuring Redis" FLUSH PRIVILEGES;
REDIS_CONF="/etc/redis/redis.conf" SQL
sed -ri 's|^port .*|port 0|' "$REDIS_CONF" log "Configuring PHP legacy stack"
if grep -Eq '^[[:space:]]*unixsocket[[:space:]]+' "$REDIS_CONF"; then backup_file "${PHP_INI}"
sed -ri "s|^[[:space:]]*unixsocket[[:space:]]+.*|unixsocket ${REDIS_SOCK}|" "$REDIS_CONF" backup_file "${PHP_FPM_POOL_CONF}"
replace_or_append_ini "memory_limit" "${PHP_MEMORY_LIMIT}" "${PHP_INI}"
replace_or_append_ini "upload_max_filesize" "${PHP_UPLOAD_LIMIT}" "${PHP_INI}"
replace_or_append_ini "post_max_size" "${PHP_UPLOAD_LIMIT}" "${PHP_INI}"
replace_or_append_ini "max_execution_time" "${PHP_MAX_EXECUTION_TIME}" "${PHP_INI}"
replace_or_append_ini "max_input_time" "${PHP_MAX_EXECUTION_TIME}" "${PHP_INI}"
replace_or_append_ini "output_buffering" "Off" "${PHP_INI}"
replace_or_append_ini "date.timezone" "${PHP_TIMEZONE}" "${PHP_INI}"
replace_or_append_ini "cgi.fix_pathinfo" "0" "${PHP_INI}"
# FPM pool/socket for Apache proxy_fcgi
sed -ri 's|^user\s*=.*|user = http|g' "${PHP_FPM_POOL_CONF}"
sed -ri 's|^group\s*=.*|group = http|g' "${PHP_FPM_POOL_CONF}"
if grep -Eq '^[;[:space:]]*listen\s*=' "${PHP_FPM_POOL_CONF}"; then
sed -ri 's|^[;[:space:]]*listen\s*=.*|listen = /run/php-fpm-legacy/php-fpm.sock|g' "${PHP_FPM_POOL_CONF}"
else else
printf "\nunixsocket %s\n" "$REDIS_SOCK" >> "$REDIS_CONF" echo "listen = /run/php-fpm-legacy/php-fpm.sock" >> "${PHP_FPM_POOL_CONF}"
fi fi
if grep -Eq '^[[:space:]]*unixsocketperm[[:space:]]+' "$REDIS_CONF"; then if grep -Eq '^[;[:space:]]*listen.owner\s*=' "${PHP_FPM_POOL_CONF}"; then
sed -ri 's|^[[:space:]]*unixsocketperm[[:space:]]+.*|unixsocketperm 770|' "$REDIS_CONF" sed -ri 's|^[;[:space:]]*listen.owner\s*=.*|listen.owner = http|g' "${PHP_FPM_POOL_CONF}"
else else
printf "unixsocketperm 770\n" >> "$REDIS_CONF" echo "listen.owner = http" >> "${PHP_FPM_POOL_CONF}"
fi fi
usermod -aG redis http || true if grep -Eq '^[;[:space:]]*listen.group\s*=' "${PHP_FPM_POOL_CONF}"; then
sed -ri 's|^[;[:space:]]*listen.group\s*=.*|listen.group = http|g' "${PHP_FPM_POOL_CONF}"
else
echo "listen.group = http" >> "${PHP_FPM_POOL_CONF}"
fi
systemctl enable --now redis if grep -Eq '^[;[:space:]]*listen.mode\s*=' "${PHP_FPM_POOL_CONF}"; then
systemctl restart redis sed -ri 's|^[;[:space:]]*listen.mode\s*=.*|listen.mode = 0660|g' "${PHP_FPM_POOL_CONF}"
else
echo "listen.mode = 0660" >> "${PHP_FPM_POOL_CONF}"
fi
systemctl enable --now php-fpm-legacy
log "Configuring Valkey"
backup_file "${VALKEY_CONF}"
sed -ri \
-e 's|^#?\s*port\s+.*|port 0|g' \
-e 's|^#?\s*unixsocket\s+.*|unixsocket /run/redis/redis.sock|g' \
-e 's|^#?\s*unixsocketperm\s+.*|unixsocketperm 770|g' \
-e 's|^#?\s*supervised\s+.*|supervised systemd|g' \
"${VALKEY_CONF}"
# Make sure the web user can access the socket
if getent group valkey >/dev/null 2>&1; then
usermod -aG valkey "${APACHE_RUN_USER}" || true
fi
systemctl enable --now valkey
systemctl restart valkey
systemctl restart php-fpm-legacy
# =========================
# APACHE
# =========================
log "Configuring Apache" log "Configuring Apache"
HTTPD_CONF="/etc/httpd/conf/httpd.conf"
sed -ri 's|^#(LoadModule proxy_module modules/mod_proxy.so)|\1|' "$HTTPD_CONF" backup_file "${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
if ! grep -Eq '^[[:space:]]*ServerName[[:space:]]+' "$HTTPD_CONF"; then # Ensure useful modules are enabled
printf "\nServerName %s\n" "$DOMAIN" >> "$HTTPD_CONF" sed -ri 's|^#(LoadModule mpm_event_module modules/mod_mpm_event.so)|\1|g' "${HTTPD_CONF}"
sed -ri 's|^#(LoadModule rewrite_module modules/mod_rewrite.so)|\1|g' "${HTTPD_CONF}"
sed -ri 's|^#(LoadModule headers_module modules/mod_headers.so)|\1|g' "${HTTPD_CONF}"
sed -ri 's|^#(LoadModule env_module modules/mod_env.so)|\1|g' "${HTTPD_CONF}"
sed -ri 's|^#(LoadModule dir_module modules/mod_dir.so)|\1|g' "${HTTPD_CONF}"
sed -ri 's|^#(LoadModule mime_module modules/mod_mime.so)|\1|g' "${HTTPD_CONF}"
sed -ri 's|^#(LoadModule alias_module modules/mod_alias.so)|\1|g' "${HTTPD_CONF}"
sed -ri 's|^#(LoadModule setenvif_module modules/mod_setenvif.so)|\1|g' "${HTTPD_CONF}"
sed -ri 's|^#(LoadModule proxy_module modules/mod_proxy.so)|\1|g' "${HTTPD_CONF}"
sed -ri 's|^#(LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so)|\1|g' "${HTTPD_CONF}"
# Keep ServerName quiet
if grep -Eq '^[#[:space:]]*ServerName ' "${HTTPD_CONF}"; then
sed -ri "s|^[#[:space:]]*ServerName .*|ServerName ${NEXTCLOUD_DOMAIN}:80|g" "${HTTPD_CONF}"
else
echo "ServerName ${NEXTCLOUD_DOMAIN}:80" >> "${HTTPD_CONF}"
fi fi
install -d -m 0755 /etc/httpd/conf/extra cat > "${HTTPD_WELLKNOWN_CONF}" <<'EOF'
Alias /.well-known/carddav /nextcloud/remote.php/dav/
if ! grep -Fq "IncludeOptional conf/extra/*.conf" "$HTTPD_CONF"; then Alias /.well-known/caldav /nextcloud/remote.php/dav/
printf "\nIncludeOptional conf/extra/*.conf\n" >> "$HTTPD_CONF"
fi
cat > /etc/httpd/conf/extra/remoteip-nextcloud.conf <<EOF
RemoteIPHeader ${REAL_IP_HEADER}
RemoteIPTrustedProxy 127.0.0.1
RemoteIPTrustedProxy ::1
EOF EOF
cat > /etc/httpd/conf/extra/nextcloud.conf <<EOF cat > "${HTTPD_NEXTCLOUD_CONF}" <<EOF
<VirtualHost *:80> Alias /nextcloud "${NEXTCLOUD_WEBROOT}"
ServerName ${DOMAIN}
DocumentRoot ${NC_DIR}
<Directory ${NC_DIR}> <Directory "${NEXTCLOUD_WEBROOT}">
Require all granted Options FollowSymLinks MultiViews
AllowOverride All AllowOverride All
Options FollowSymLinks MultiViews Require all granted
<IfModule mod_dav.c> <IfModule mod_dav.c>
Dav off Dav off
</IfModule> </IfModule>
<IfModule mod_headers.c> SetEnv HOME ${NEXTCLOUD_CONFIG_DIR}
Header always set Referrer-Policy "no-referrer" SetEnv HTTP_HOME ${NEXTCLOUD_CONFIG_DIR}
Header always set X-Content-Type-Options "nosniff" </Directory>
Header always set X-Frame-Options "SAMEORIGIN"
</IfModule>
</Directory>
LimitRequestBody 0 <FilesMatch \.php$>
SetEnv HOME ${NC_DIR} SetHandler "proxy:unix:/run/php-fpm-legacy/php-fpm.sock|fcgi://localhost/"
SetEnv HTTP_HOME ${NC_DIR} </FilesMatch>
<FilesMatch "\.php$"> <IfModule mod_headers.c>
SetHandler "proxy:unix:/run/php-fpm-legacy/php-fpm.sock|fcgi://localhost/" Header always set Referrer-Policy "no-referrer"
</FilesMatch> Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Permitted-Cross-Domain-Policies "none"
Header always set X-Robots-Tag "noindex, nofollow"
Header always set X-XSS-Protection "1; mode=block"
</IfModule>
ErrorLog "/var/log/httpd/nextcloud_error.log" # Deny access to sensitive paths
CustomLog "/var/log/httpd/nextcloud_access.log" combined <Directory "${NEXTCLOUD_WEBROOT}/config">
</VirtualHost> Require all denied
</Directory>
<Directory "${NEXTCLOUD_WEBROOT}/data">
Require all denied
</Directory>
EOF EOF
httpd -t ensure_line "Include conf/extra/nextcloud-wellknown.conf" "${HTTPD_CONF}"
ensure_line "Include conf/extra/nextcloud.conf" "${HTTPD_CONF}"
apachectl configtest || die "Apache config test failed."
systemctl enable --now httpd systemctl enable --now httpd
systemctl reload httpd
# ========================= log "Preparing Nextcloud config and permissions"
# DOWNLOAD NEXTCLOUD
# =========================
log "Downloading official Nextcloud release"
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT
cd "$TMPDIR" mkdir -p "${NEXTCLOUD_CONFIG_DIR}/config"
curl -fsSLo nextcloud.tar.bz2 "${NC_TARBALL_URL}" mkdir -p "${NEXTCLOUD_CONFIG_DIR}/apps"
curl -fsSLo nextcloud.tar.bz2.sha512 "${NC_SHA512_URL}" mkdir -p "${NEXTCLOUD_CONFIG_DIR}/data"
sha512sum -c nextcloud.tar.bz2.sha512 chown -R "${APACHE_RUN_USER}:${APACHE_RUN_GROUP}" "${NEXTCLOUD_CONFIG_DIR}"
chmod 0750 "${NEXTCLOUD_CONFIG_DIR}"
chmod 0750 "${NEXTCLOUD_CONFIG_DIR}/config"
tar -xjf nextcloud.tar.bz2 # Ensure package config dir is owned correctly
chown -R "${APACHE_RUN_USER}:${APACHE_RUN_GROUP}" /etc/webapps/nextcloud
chmod 0750 /etc/webapps/nextcloud
chmod 0640 /etc/webapps/nextcloud/config/config.php || true
log "Deploying Nextcloud" # Data dir ownership
rm -rf "${NC_DIR}" chown -R "${APACHE_RUN_USER}:${APACHE_RUN_GROUP}" "${NEXTCLOUD_DATA_DIR}"
mv nextcloud "${NC_DIR}" find "${NEXTCLOUD_DATA_DIR}" -type d -exec chmod 0750 {} \;
find "${NEXTCLOUD_DATA_DIR}" -type f -exec chmod 0640 {} \; 2>/dev/null || true
chown -R http:http "${NC_DIR}" "${NC_DATA_DIR}" log "Optional SMB mount setup"
find "${NC_DIR}" -type d -exec chmod 0750 {} \;
find "${NC_DIR}" -type f -exec chmod 0640 {} \;
chmod 0750 "${NC_DATA_DIR}"
install -d -o http -g http -m 0750 "${NC_DIR}/config" if [[ "${ENABLE_SMB_MOUNT}" == "true" ]]; then
install -d -o http -g http -m 0750 "${NC_DIR}/apps" mkdir -p "${SMB_MOUNTPOINT}"
if ! grep -Fq "${SMB_MOUNTPOINT} " /etc/fstab; then
# ========================= echo "${SMB_REMOTE} ${SMB_MOUNTPOINT} cifs ${SMB_FSTAB_OPTIONS} 0 0" >> /etc/fstab
# INSTALL NEXTCLOUD
# =========================
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}"
# =========================
# REVERSE PROXY / HTTPS
# =========================
log "Applying reverse-proxy and HTTPS settings"
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set overwrite.cli.url --value="https://${DOMAIN}"
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set overwriteprotocol --value="https"
if [[ "${TRUST_LOCAL_PROXY}" == "true" ]]; then
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set trusted_proxies 0 --value="127.0.0.1"
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set trusted_proxies 1 --value="::1"
if [[ "${REAL_IP_HEADER}" == "CF-Connecting-IP" ]]; then
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set forwarded_for_headers 0 --value="HTTP_CF_CONNECTING_IP"
else
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set forwarded_for_headers 0 --value="HTTP_X_FORWARDED_FOR"
fi fi
mount -a
chown "${APACHE_RUN_USER}:${APACHE_RUN_GROUP}" "${SMB_MOUNTPOINT}" || true
fi fi
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set trusted_domains 1 --value="${DOMAIN}" log "Installing Nextcloud non-interactively"
# ========================= if [[ ! -f "${NEXTCLOUD_CONFIG_DIR}/config/config.php" ]] || grep -q "CAN_INSTALL" "${NEXTCLOUD_CONFIG_DIR}/config/config.php" 2>/dev/null; then
# CACHE / LOCKING sudo -u "${APACHE_RUN_USER}" php-legacy "${NEXTCLOUD_WEBROOT}/occ" maintenance:install \
# ========================= --database "mysql" \
log "Configuring APCu and Redis" --database-name "${DB_NAME}" \
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set memcache.local --value='\OC\Memcache\APCu' --database-user "${DB_USER}" \
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set memcache.locking --value='\OC\Memcache\Redis' --database-pass "${DB_PASS}" \
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set redis --type=json --value="{\"host\":\"${REDIS_SOCK}\",\"port\":0,\"timeout\":1.5}" --admin-user "${NC_ADMIN_USER}" \
--admin-pass "${NC_ADMIN_PASS}" \
--data-dir "${NEXTCLOUD_DATA_DIR}"
fi
# ========================= log "Applying Nextcloud config"
# CRON
# =========================
log "Configuring cron background jobs"
systemctl enable --now cronie
cat > /etc/cron.d/nextcloud <<EOF occ config:system:set trusted_domains 0 --value="${TRUSTED_DOMAINS[0]}"
*/5 * * * * http ${PHP_BIN} -f ${NC_DIR}/cron.php for i in "${!TRUSTED_DOMAINS[@]}"; do
EOF occ config:system:set trusted_domains "${i}" --value="${TRUSTED_DOMAINS[$i]}"
done
chmod 0644 /etc/cron.d/nextcloud occ config:system:set overwrite.cli.url --value="http://${NEXTCLOUD_DOMAIN}/nextcloud"
systemctl restart cronie occ config:system:set htaccess.RewriteBase --value="/nextcloud"
occ maintenance:update:htaccess
# ========================= occ config:system:set memcache.local --value='\OC\Memcache\APCu'
# FINALIZE occ config:system:set memcache.locking --value='\OC\Memcache\Redis'
# ========================= occ config:system:set filelocking.enabled --type=boolean --value=true
log "Finalizing" occ config:system:set redis host --value="/run/redis/redis.sock"
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" maintenance:update:htaccess || true occ config:system:set redis port --type=integer --value=0
# Sensible extras
occ config:system:set default_phone_region --value="US" || true
occ config:system:set maintenance_window_start --type=integer --value=1 || true
log "Enabling system cron"
systemctl enable --now nextcloud-cron.service || true
systemctl list-timers --all | grep -i nextcloud || true
log "Final service restarts"
systemctl restart mariadb
systemctl restart valkey
systemctl restart php-fpm-legacy
systemctl restart httpd
log "Post-install checks"
apachectl configtest
systemctl --no-pager --full status mariadb | sed -n '1,12p' || true
systemctl --no-pager --full status valkey | sed -n '1,12p' || true
systemctl --no-pager --full status php-fpm-legacy | sed -n '1,12p' || true
systemctl --no-pager --full status httpd | sed -n '1,12p' || true
if [[ -S /run/redis/redis.sock ]]; then
ls -l /run/redis/redis.sock
else
echo "WARNING: /run/redis/redis.sock not found"
fi
echo echo
echo "=================================================================" echo "=============================================="
echo " Nextcloud installed successfully" echo "Nextcloud install completed."
echo " URL: https://${DOMAIN}" echo "URL: http://${NEXTCLOUD_DOMAIN}/nextcloud"
echo " Admin user: ${ADMIN_USER}" echo "Admin user: ${NC_ADMIN_USER}"
echo " Admin pass: ${ADMIN_PASS}" echo "Data dir: ${NEXTCLOUD_DATA_DIR}"
echo " Web root: ${NC_DIR}" echo "Web root: ${NEXTCLOUD_WEBROOT}"
echo " Data dir: ${NC_DATA_DIR}" echo "Config dir: ${NEXTCLOUD_CONFIG_DIR}"
echo " PHP: ${PHP_BIN}" echo "=============================================="
echo " FPM svc: ${PHP_FPM_SERVICE}" echo
echo "-----------------------------------------------------------------" echo "IMPORTANT:"
echo " Services enabled:" echo "1) This script sets up HTTP only."
echo " - httpd" echo "2) Put TLS in front of it or add an HTTPS vhost."
echo " - ${PHP_FPM_SERVICE}" echo "3) If you use a reverse proxy, update overwritehost/overwriteprotocol."
echo " - mariadb" echo
echo " - redis"
echo " - cronie"
echo "================================================================="