Update arch_install.sh
This commit is contained in:
parent
c9d302fe44
commit
3e65763673
730
arch_install.sh
730
arch_install.sh
|
|
@ -1,474 +1,434 @@
|
|||
#!/usr/bin/env bash
|
||||
# Nextcloud + Apache + PHP 8.3 (php-legacy) + MariaDB + Valkey/Redis-compatible cache on Arch Linux
|
||||
# Production-oriented, reverse-proxy aware
|
||||
#
|
||||
# Run as root:
|
||||
# sudo ./arch_install.sh
|
||||
|
||||
set -Eeuo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
########################################
|
||||
# USER CONFIG
|
||||
########################################
|
||||
# =========================
|
||||
# EDIT THESE VARIABLES
|
||||
# =========================
|
||||
DOMAIN="domain.com"
|
||||
|
||||
NEXTCLOUD_DOMAIN="cloud.example.com"
|
||||
TRUSTED_DOMAINS=("cloud.example.com" "192.168.1.10")
|
||||
|
||||
NEXTCLOUD_WEBROOT="/usr/share/webapps/nextcloud"
|
||||
NEXTCLOUD_CONFIG_DIR="/etc/webapps/nextcloud"
|
||||
NEXTCLOUD_DATA_DIR="/var/lib/nextcloud/data"
|
||||
NC_DIR="/srv/http/nextcloud"
|
||||
NC_DATA_DIR="/srv/nextcloud-data"
|
||||
|
||||
DB_NAME="nextcloud"
|
||||
DB_USER="nextcloud"
|
||||
DB_PASS="CHANGE_ME_DB_PASSWORD"
|
||||
DB_PASS="changeMe"
|
||||
|
||||
NC_ADMIN_USER="admin"
|
||||
NC_ADMIN_PASS="CHANGE_ME_ADMIN_PASSWORD"
|
||||
ADMIN_USER="admin"
|
||||
ADMIN_PASS="changeMe"
|
||||
|
||||
PHP_MEMORY_LIMIT="1024M"
|
||||
PHP_UPLOAD_LIMIT="16G"
|
||||
PHP_MAX_EXECUTION_TIME="3600"
|
||||
PHP_TIMEZONE="America/New_York"
|
||||
# If you're behind Cloudflare Tunnel or another reverse proxy:
|
||||
TRUST_LOCAL_PROXY="true"
|
||||
REAL_IP_HEADER="CF-Connecting-IP" # use X-Forwarded-For if not Cloudflare
|
||||
|
||||
APACHE_RUN_USER="http"
|
||||
APACHE_RUN_GROUP="http"
|
||||
# Pin a specific release for production stability
|
||||
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"
|
||||
|
||||
ENABLE_SMB_MOUNT="false"
|
||||
SMB_REMOTE="//server/share"
|
||||
SMB_MOUNTPOINT="/mnt/nextcloud"
|
||||
SMB_CREDENTIALS_FILE="/root/.smbcredentials"
|
||||
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"
|
||||
# PHP legacy paths/services on Arch
|
||||
PHP_BIN="/usr/bin/php-legacy"
|
||||
PHP_INI="/etc/php-legacy/php.ini"
|
||||
PHP_CONF_DIR="/etc/php-legacy/conf.d"
|
||||
PHP_FPM_WWW_CONF="/etc/php-legacy/php-fpm.d/www.conf"
|
||||
PHP_FPM_SERVICE="php-fpm-legacy"
|
||||
|
||||
########################################
|
||||
# INTERNALS
|
||||
########################################
|
||||
|
||||
PHP_ETC_DIR="/etc/php-legacy"
|
||||
PHP_INI="${PHP_ETC_DIR}/php.ini"
|
||||
PHP_CONF_D="${PHP_ETC_DIR}/conf.d"
|
||||
PHP_FPM_POOL_CONF="/etc/php-legacy/php-fpm.d/www.conf"
|
||||
|
||||
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"
|
||||
# Valkey provides redis on current Arch
|
||||
REDIS_SERVICE="valkey"
|
||||
REDIS_CONF="/etc/valkey/valkey.conf"
|
||||
REDIS_SOCK="/run/valkey/valkey.sock"
|
||||
|
||||
# =========================
|
||||
# HELPER FUNCTIONS
|
||||
# =========================
|
||||
log() {
|
||||
echo
|
||||
echo "==== $* ===="
|
||||
printf '\n==== %s ====\n' "$1"
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "ERROR: $*" >&2
|
||||
printf '\nERROR: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_root() {
|
||||
[[ "${EUID}" -eq 0 ]] || die "Run this script as root."
|
||||
[[ $EUID -eq 0 ]] || die "Run this script as root."
|
||||
}
|
||||
|
||||
check_vars() {
|
||||
local vars=(
|
||||
DOMAIN NC_DIR NC_DATA_DIR
|
||||
DB_NAME DB_USER DB_PASS
|
||||
ADMIN_USER ADMIN_PASS
|
||||
NC_VERSION NC_TARBALL_URL NC_SHA512_URL
|
||||
)
|
||||
for v in "${vars[@]}"; do
|
||||
[[ -n "${!v}" ]] || die "Variable $v is empty. Edit the script first."
|
||||
done
|
||||
}
|
||||
|
||||
backup_file() {
|
||||
local f="$1"
|
||||
[[ -f "$f" ]] && cp -an "$f" "${f}.bak.$(date +%F-%H%M%S)" || true
|
||||
local file="$1"
|
||||
[[ -f "$file" ]] || return 0
|
||||
cp -a "$file" "${file}.bak.$(date +%Y%m%d-%H%M%S)"
|
||||
}
|
||||
|
||||
replace_or_append_ini() {
|
||||
set_ini_value() {
|
||||
local key="$1"
|
||||
local value="$2"
|
||||
local file="$3"
|
||||
if grep -Eq "^[;[:space:]]*${key}[[:space:]]*=" "$file"; then
|
||||
sed -ri "s|^[;[:space:]]*${key}[[:space:]]*=.*|${key} = ${value}|g" "$file"
|
||||
if grep -Eq "^[;[:space:]]*${key}[[:space:]]*=" "$PHP_INI"; then
|
||||
sed -ri "s|^[;[:space:]]*${key}[[:space:]]*=.*|${key} = ${value}|" "$PHP_INI"
|
||||
else
|
||||
echo "${key} = ${value}" >> "$file"
|
||||
printf "\n%s = %s\n" "$key" "$value" >> "$PHP_INI"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_line() {
|
||||
local line="$1"
|
||||
local file="$2"
|
||||
grep -Fqx "$line" "$file" || echo "$line" >> "$file"
|
||||
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
|
||||
}
|
||||
|
||||
write_ini() {
|
||||
write_conf_file() {
|
||||
local file="$1"
|
||||
shift
|
||||
cat > "$file" <<EOF
|
||||
$*
|
||||
EOF
|
||||
install -d -m 0755 "$PHP_CONF_DIR"
|
||||
printf '%s\n' "$@" > "$file"
|
||||
}
|
||||
|
||||
occ() {
|
||||
sudo -u "${APACHE_RUN_USER}" /usr/bin/php-legacy /usr/bin/occ "$@"
|
||||
verify_php_module() {
|
||||
local module="$1"
|
||||
"$PHP_BIN" -m 2>/dev/null | grep -qx "$module"
|
||||
}
|
||||
|
||||
########################################
|
||||
# START
|
||||
########################################
|
||||
|
||||
# =========================
|
||||
# PRECHECKS
|
||||
# =========================
|
||||
require_root
|
||||
check_vars
|
||||
|
||||
log "Validating variables"
|
||||
|
||||
[[ "${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 ${SMB_CREDENTIALS_FILE} does not exist."
|
||||
fi
|
||||
|
||||
log "Installing packages"
|
||||
|
||||
log "Updating system and installing packages"
|
||||
pacman -Syu --noconfirm
|
||||
|
||||
pacman -S --needed --noconfirm \
|
||||
apache \
|
||||
mariadb \
|
||||
nextcloud \
|
||||
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
|
||||
apache mariadb valkey cronie \
|
||||
php-legacy php-legacy-fpm php-legacy-gd php-legacy-intl php-legacy-sodium \
|
||||
php-legacy-apcu php-legacy-igbinary php-legacy-redis php-legacy-imagick \
|
||||
php-legacy-mysqli php-legacy-pdo php-legacy-zip \
|
||||
curl wget tar bzip2 unzip sudo
|
||||
|
||||
# =========================
|
||||
# DIRECTORIES
|
||||
# =========================
|
||||
log "Creating base directories"
|
||||
install -d -m 0755 /srv/http
|
||||
install -d -m 0750 "${NC_DATA_DIR}"
|
||||
|
||||
mkdir -p "${NEXTCLOUD_DATA_DIR}"
|
||||
mkdir -p /var/lib/nextcloud
|
||||
mkdir -p /var/log/httpd
|
||||
mkdir -p /run/httpd
|
||||
mkdir -p "${PHP_CONF_D}"
|
||||
|
||||
chown -R "${APACHE_RUN_USER}:${APACHE_RUN_GROUP}" /var/lib/nextcloud
|
||||
chmod 0750 /var/lib/nextcloud
|
||||
chmod 0750 "${NEXTCLOUD_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
|
||||
|
||||
for _ in {1..30}; do
|
||||
if mariadb-admin ping >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
mariadb-admin ping >/dev/null 2>&1 || die "MariaDB did not come up."
|
||||
|
||||
mariadb <<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}';
|
||||
ALTER USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
|
||||
|
||||
GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
mysql <<'SQL'
|
||||
DELETE FROM mysql.user WHERE User='';
|
||||
DROP DATABASE IF EXISTS test;
|
||||
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
|
||||
DELETE FROM mysql.db WHERE Db='test' OR Db LIKE 'test\_%';
|
||||
FLUSH PRIVILEGES;
|
||||
SQL
|
||||
|
||||
log "Configuring PHP legacy stack"
|
||||
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
|
||||
|
||||
backup_file "${PHP_INI}"
|
||||
backup_file "${PHP_FPM_POOL_CONF}"
|
||||
# =========================
|
||||
# PHP
|
||||
# =========================
|
||||
log "Configuring PHP 8.3 legacy stack"
|
||||
|
||||
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}"
|
||||
backup_file "$PHP_INI"
|
||||
|
||||
# Explicitly enable extensions needed by Nextcloud.
|
||||
# Arch php-legacy package layout is module-based, so make sure conf.d loads them.
|
||||
write_ini "${PHP_CONF_D}/20-nextcloud-core.ini" \
|
||||
"; Core DB and image modules for Nextcloud
|
||||
extension=mysqli
|
||||
extension=pdo_mysql
|
||||
extension=gd
|
||||
extension=intl
|
||||
extension=sodium
|
||||
"
|
||||
# Ensure extension dir is correct for php-legacy
|
||||
sed -ri 's|^[;[:space:]]*extension_dir[[:space:]]*=.*|extension_dir = "/usr/lib/php-legacy/modules/"|' "$PHP_INI"
|
||||
|
||||
write_ini "${PHP_CONF_D}/20-nextcloud-cache.ini" \
|
||||
"; Cache modules for Nextcloud
|
||||
extension=apcu
|
||||
extension=redis
|
||||
apc.enable_cli=1
|
||||
"
|
||||
# Remove any manual redis/igbinary/apcu extension lines from php.ini
|
||||
sed -i \
|
||||
-e '/^[[:space:]]*extension[[:space:]]*=[[:space:]]*"\{0,1\}igbinary\(.*\)\{0,1\}"\{0,1\}[[:space:]]*$/d' \
|
||||
-e '/^[[:space:]]*extension[[:space:]]*=[[:space:]]*"\{0,1\}redis\(.*\)\{0,1\}"\{0,1\}[[:space:]]*$/d' \
|
||||
-e '/^[[:space:]]*extension[[:space:]]*=[[:space:]]*"\{0,1\}apcu\(.*\)\{0,1\}"\{0,1\}[[:space:]]*$/d' \
|
||||
"$PHP_INI"
|
||||
|
||||
write_ini "${PHP_CONF_D}/10-opcache.ini" \
|
||||
"; Opcache
|
||||
zend_extension=opcache
|
||||
opcache.enable=1
|
||||
opcache.enable_cli=1
|
||||
opcache.interned_strings_buffer=16
|
||||
opcache.max_accelerated_files=10000
|
||||
opcache.memory_consumption=192
|
||||
opcache.save_comments=1
|
||||
opcache.revalidate_freq=60
|
||||
"
|
||||
# Write active extension files. igbinary must load before redis.
|
||||
write_conf_file "${PHP_CONF_DIR}/apcu.ini" \
|
||||
"extension=apcu"
|
||||
|
||||
sed -ri 's|^user\s*=.*|user = http|g' "${PHP_FPM_POOL_CONF}"
|
||||
sed -ri 's|^group\s*=.*|group = http|g' "${PHP_FPM_POOL_CONF}"
|
||||
write_conf_file "${PHP_CONF_DIR}/igbinary.ini" \
|
||||
"extension=igbinary"
|
||||
|
||||
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
|
||||
echo "listen = /run/php-fpm-legacy/php-fpm.sock" >> "${PHP_FPM_POOL_CONF}"
|
||||
fi
|
||||
write_conf_file "${PHP_CONF_DIR}/redis.ini" \
|
||||
"extension=redis"
|
||||
|
||||
if grep -Eq '^[;[:space:]]*listen.owner\s*=' "${PHP_FPM_POOL_CONF}"; then
|
||||
sed -ri 's|^[;[:space:]]*listen.owner\s*=.*|listen.owner = http|g' "${PHP_FPM_POOL_CONF}"
|
||||
else
|
||||
echo "listen.owner = http" >> "${PHP_FPM_POOL_CONF}"
|
||||
fi
|
||||
# Nextcloud-oriented php.ini tuning
|
||||
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\""
|
||||
|
||||
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
|
||||
# OPcache
|
||||
set_ini_value "zend_extension" "opcache"
|
||||
set_ini_value "opcache.enable" "1"
|
||||
set_ini_value "opcache.enable_cli" "0"
|
||||
set_ini_value "opcache.interned_strings_buffer" "16"
|
||||
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"
|
||||
|
||||
if grep -Eq '^[;[:space:]]*listen.mode\s*=' "${PHP_FPM_POOL_CONF}"; then
|
||||
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
|
||||
# PHP-FPM pool config for Apache's http user
|
||||
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"
|
||||
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-legacy
|
||||
systemctl restart php-fpm-legacy
|
||||
|
||||
log "Configuring Valkey (TCP localhost only)"
|
||||
|
||||
backup_file "${VALKEY_CONF}"
|
||||
|
||||
if grep -Eq '^[#[:space:]]*bind ' "${VALKEY_CONF}"; then
|
||||
sed -ri 's|^[#[:space:]]*bind .*|bind 127.0.0.1 ::1|g' "${VALKEY_CONF}"
|
||||
else
|
||||
echo "bind 127.0.0.1 ::1" >> "${VALKEY_CONF}"
|
||||
fi
|
||||
|
||||
if grep -Eq '^[#[:space:]]*port ' "${VALKEY_CONF}"; then
|
||||
sed -ri 's|^[#[:space:]]*port .*|port 6379|g' "${VALKEY_CONF}"
|
||||
else
|
||||
echo "port 6379" >> "${VALKEY_CONF}"
|
||||
fi
|
||||
|
||||
if grep -Eq '^[#[:space:]]*protected-mode ' "${VALKEY_CONF}"; then
|
||||
sed -ri 's|^[#[:space:]]*protected-mode .*|protected-mode yes|g' "${VALKEY_CONF}"
|
||||
else
|
||||
echo "protected-mode yes" >> "${VALKEY_CONF}"
|
||||
fi
|
||||
|
||||
sed -ri 's|^[#[:space:]]*unixsocket .*|# unixsocket disabled by install script|g' "${VALKEY_CONF}" || true
|
||||
sed -ri 's|^[#[:space:]]*unixsocketperm .*|# unixsocketperm disabled by install script|g' "${VALKEY_CONF}" || true
|
||||
|
||||
if grep -Eq '^[#[:space:]]*supervised ' "${VALKEY_CONF}"; then
|
||||
sed -ri 's|^[#[:space:]]*supervised .*|supervised systemd|g' "${VALKEY_CONF}"
|
||||
else
|
||||
echo "supervised systemd" >> "${VALKEY_CONF}"
|
||||
fi
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now valkey
|
||||
|
||||
if ! systemctl is-active --quiet valkey; then
|
||||
journalctl -u valkey.service -n 50 --no-pager || true
|
||||
die "valkey.service failed to start"
|
||||
fi
|
||||
|
||||
log "Configuring Apache"
|
||||
|
||||
backup_file "${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}"
|
||||
|
||||
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
|
||||
|
||||
cat > "${HTTPD_WELLKNOWN_CONF}" <<'EOF'
|
||||
Alias /.well-known/carddav /nextcloud/remote.php/dav/
|
||||
Alias /.well-known/caldav /nextcloud/remote.php/dav/
|
||||
EOF
|
||||
|
||||
cat > "${HTTPD_NEXTCLOUD_CONF}" <<EOF
|
||||
Alias /nextcloud "${NEXTCLOUD_WEBROOT}"
|
||||
|
||||
<Directory "${NEXTCLOUD_WEBROOT}">
|
||||
Options FollowSymLinks MultiViews
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
|
||||
<IfModule mod_dav.c>
|
||||
Dav off
|
||||
</IfModule>
|
||||
|
||||
SetEnv HOME ${NEXTCLOUD_CONFIG_DIR}
|
||||
SetEnv HTTP_HOME ${NEXTCLOUD_CONFIG_DIR}
|
||||
</Directory>
|
||||
|
||||
<FilesMatch \.php$>
|
||||
SetHandler "proxy:unix:/run/php-fpm-legacy/php-fpm.sock|fcgi://localhost/"
|
||||
</FilesMatch>
|
||||
|
||||
<IfModule mod_headers.c>
|
||||
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-Permitted-Cross-Domain-Policies "none"
|
||||
Header always set X-Robots-Tag "noindex, nofollow"
|
||||
Header always set X-XSS-Protection "1; mode=block"
|
||||
</IfModule>
|
||||
|
||||
<Directory "${NEXTCLOUD_WEBROOT}/config">
|
||||
Require all denied
|
||||
</Directory>
|
||||
<Directory "${NEXTCLOUD_WEBROOT}/data">
|
||||
Require all denied
|
||||
</Directory>
|
||||
EOF
|
||||
|
||||
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
|
||||
|
||||
log "Preparing Nextcloud config and permissions"
|
||||
|
||||
mkdir -p "${NEXTCLOUD_CONFIG_DIR}/config"
|
||||
mkdir -p "${NEXTCLOUD_CONFIG_DIR}/apps"
|
||||
mkdir -p "${NEXTCLOUD_CONFIG_DIR}/data"
|
||||
|
||||
chown -R "${APACHE_RUN_USER}:${APACHE_RUN_GROUP}" "${NEXTCLOUD_CONFIG_DIR}"
|
||||
chmod 0750 "${NEXTCLOUD_CONFIG_DIR}"
|
||||
chmod 0750 "${NEXTCLOUD_CONFIG_DIR}/config"
|
||||
|
||||
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
|
||||
|
||||
chown -R "${APACHE_RUN_USER}:${APACHE_RUN_GROUP}" "${NEXTCLOUD_DATA_DIR}"
|
||||
find "${NEXTCLOUD_DATA_DIR}" -type d -exec chmod 0750 {} \;
|
||||
find "${NEXTCLOUD_DATA_DIR}" -type f -exec chmod 0640 {} \; 2>/dev/null || true
|
||||
|
||||
log "Optional SMB mount setup"
|
||||
|
||||
if [[ "${ENABLE_SMB_MOUNT}" == "true" ]]; then
|
||||
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
|
||||
fi
|
||||
mount -a
|
||||
chown "${APACHE_RUN_USER}:${APACHE_RUN_GROUP}" "${SMB_MOUNTPOINT}" || true
|
||||
fi
|
||||
systemctl enable --now "${PHP_FPM_SERVICE}"
|
||||
|
||||
log "Verifying PHP modules before install"
|
||||
verify_php_module "igbinary" || die "PHP igbinary module is not loaded."
|
||||
verify_php_module "redis" || die "PHP redis module is not loaded."
|
||||
verify_php_module "apcu" || die "PHP apcu module is not loaded."
|
||||
|
||||
php-legacy -m | grep -qi '^gd$' || die "PHP GD module is still not loaded."
|
||||
php-legacy -m | grep -qi '^mysqli$' || die "PHP mysqli module is still not loaded."
|
||||
php-legacy -m | grep -qi '^PDO$' || die "PHP PDO core is still not loaded."
|
||||
php-legacy -m | grep -qi '^pdo_mysql$' || die "PHP pdo_mysql module is still not loaded."
|
||||
php-legacy -m | grep -qi '^intl$' || die "PHP intl module is still not loaded."
|
||||
php-legacy -m | grep -qi '^redis$' || die "PHP redis module is still not loaded."
|
||||
php-legacy -m | grep -qi '^apcu$' || die "PHP apcu module is still not loaded."
|
||||
systemctl restart "${PHP_FPM_SERVICE}"
|
||||
|
||||
systemctl restart php-fpm-legacy
|
||||
systemctl restart httpd
|
||||
# =========================
|
||||
# VALKEY / REDIS-COMPAT
|
||||
# =========================
|
||||
log "Configuring Valkey (Redis-compatible cache)"
|
||||
backup_file "$REDIS_CONF"
|
||||
|
||||
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
|
||||
sudo -u "${APACHE_RUN_USER}" /usr/bin/php-legacy /usr/bin/occ maintenance:install \
|
||||
--database "mysql" \
|
||||
--database-name "${DB_NAME}" \
|
||||
--database-user "${DB_USER}" \
|
||||
--database-pass "${DB_PASS}" \
|
||||
--admin-user "${NC_ADMIN_USER}" \
|
||||
--admin-pass "${NC_ADMIN_PASS}" \
|
||||
--data-dir "${NEXTCLOUD_DATA_DIR}"
|
||||
# Listen only on localhost TCP for safety and compatibility
|
||||
if grep -Eq '^[#[:space:]]*bind[[:space:]]+' "$REDIS_CONF"; then
|
||||
sed -ri 's|^[#[:space:]]*bind[[:space:]]+.*|bind 127.0.0.1 ::1|' "$REDIS_CONF"
|
||||
else
|
||||
printf '\nbind 127.0.0.1 ::1\n' >> "$REDIS_CONF"
|
||||
fi
|
||||
|
||||
log "Applying Nextcloud config"
|
||||
if grep -Eq '^[#[:space:]]*port[[:space:]]+' "$REDIS_CONF"; then
|
||||
sed -ri 's|^[#[:space:]]*port[[:space:]]+.*|port 6379|' "$REDIS_CONF"
|
||||
else
|
||||
printf '\nport 6379\n' >> "$REDIS_CONF"
|
||||
fi
|
||||
|
||||
for i in "${!TRUSTED_DOMAINS[@]}"; do
|
||||
occ config:system:set trusted_domains "${i}" --value="${TRUSTED_DOMAINS[$i]}"
|
||||
done
|
||||
# Disable socket use to avoid path/group drift between redis/valkey packaging changes
|
||||
sed -i '/^[#[:space:]]*unixsocket[[:space:]]\+/d' "$REDIS_CONF"
|
||||
sed -i '/^[#[:space:]]*unixsocketperm[[:space:]]\+/d' "$REDIS_CONF"
|
||||
|
||||
occ config:system:set overwrite.cli.url --value="http://${NEXTCLOUD_DOMAIN}/nextcloud"
|
||||
occ config:system:set htaccess.RewriteBase --value="/nextcloud"
|
||||
occ maintenance:update:htaccess
|
||||
systemctl enable --now "${REDIS_SERVICE}"
|
||||
systemctl restart "${REDIS_SERVICE}"
|
||||
|
||||
occ config:system:set memcache.local --value='\OC\Memcache\APCu'
|
||||
occ config:system:set memcache.locking --value='\OC\Memcache\Redis'
|
||||
occ config:system:set filelocking.enabled --type=boolean --value=true
|
||||
occ config:system:set redis host --value="127.0.0.1"
|
||||
occ config:system:set redis port --type=integer --value=6379
|
||||
# =========================
|
||||
# APACHE
|
||||
# =========================
|
||||
log "Configuring Apache"
|
||||
HTTPD_CONF="/etc/httpd/conf/httpd.conf"
|
||||
|
||||
occ config:system:set default_phone_region --value="US" || true
|
||||
occ config:system:set maintenance_window_start --type=integer --value=1 || true
|
||||
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 env_module modules/mod_env.so)|\1|' "$HTTPD_CONF" || true
|
||||
sed -ri 's|^#(LoadModule mime_module modules/mod_mime.so)|\1|' "$HTTPD_CONF" || true
|
||||
sed -ri 's|^#(LoadModule setenvif_module modules/mod_setenvif.so)|\1|' "$HTTPD_CONF" || true
|
||||
|
||||
log "Enabling cron"
|
||||
if ! grep -Eq '^[[:space:]]*ServerName[[:space:]]+' "$HTTPD_CONF"; then
|
||||
printf "\nServerName %s\n" "$DOMAIN" >> "$HTTPD_CONF"
|
||||
fi
|
||||
|
||||
systemctl enable --now nextcloud-cron.service || true
|
||||
systemctl enable --now nextcloud-cron.timer || true
|
||||
install -d -m 0755 /etc/httpd/conf/extra
|
||||
|
||||
log "Final service restarts"
|
||||
if ! grep -Fq "IncludeOptional conf/extra/*.conf" "$HTTPD_CONF"; then
|
||||
printf "\nIncludeOptional conf/extra/*.conf\n" >> "$HTTPD_CONF"
|
||||
fi
|
||||
|
||||
systemctl restart mariadb
|
||||
systemctl restart valkey
|
||||
systemctl restart php-fpm-legacy
|
||||
systemctl restart httpd
|
||||
cat > /etc/httpd/conf/extra/remoteip-nextcloud.conf <<EOF
|
||||
RemoteIPHeader ${REAL_IP_HEADER}
|
||||
RemoteIPTrustedProxy 127.0.0.1
|
||||
RemoteIPTrustedProxy ::1
|
||||
EOF
|
||||
|
||||
log "Post-install checks"
|
||||
cat > /etc/httpd/conf/extra/nextcloud.conf <<EOF
|
||||
<VirtualHost *:80>
|
||||
ServerName ${DOMAIN}
|
||||
DocumentRoot ${NC_DIR}
|
||||
|
||||
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
|
||||
<Directory ${NC_DIR}>
|
||||
Require all granted
|
||||
AllowOverride All
|
||||
Options FollowSymLinks MultiViews
|
||||
|
||||
<IfModule mod_dav.c>
|
||||
Dav off
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_headers.c>
|
||||
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-Robots-Tag "noindex, nofollow"
|
||||
Header always set X-Permitted-Cross-Domain-Policies "none"
|
||||
Header always set X-Download-Options "noopen"
|
||||
Header always set X-XSS-Protection "1; mode=block"
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
LimitRequestBody 0
|
||||
SetEnv HOME ${NC_DIR}
|
||||
SetEnv HTTP_HOME ${NC_DIR}
|
||||
|
||||
<FilesMatch "\.php$">
|
||||
SetHandler "proxy:unix:/run/php-fpm-legacy/php-fpm.sock|fcgi://localhost/"
|
||||
</FilesMatch>
|
||||
|
||||
ErrorLog "/var/log/httpd/nextcloud_error.log"
|
||||
CustomLog "/var/log/httpd/nextcloud_access.log" combined
|
||||
</VirtualHost>
|
||||
EOF
|
||||
|
||||
httpd -t
|
||||
systemctl enable --now httpd
|
||||
systemctl reload httpd
|
||||
|
||||
# =========================
|
||||
# DOWNLOAD NEXTCLOUD
|
||||
# =========================
|
||||
log "Downloading official Nextcloud release"
|
||||
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}"
|
||||
|
||||
sha512sum -c nextcloud.tar.bz2.sha512
|
||||
|
||||
tar -xjf nextcloud.tar.bz2
|
||||
|
||||
log "Deploying Nextcloud"
|
||||
rm -rf "${NC_DIR}"
|
||||
mv nextcloud "${NC_DIR}"
|
||||
|
||||
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}"
|
||||
|
||||
install -d -o http -g http -m 0750 "${NC_DIR}/config"
|
||||
install -d -o http -g http -m 0750 "${NC_DIR}/apps"
|
||||
|
||||
# =========================
|
||||
# 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
|
||||
|
||||
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set trusted_domains 1 --value="${DOMAIN}"
|
||||
|
||||
# =========================
|
||||
# CACHE / LOCKING
|
||||
# =========================
|
||||
log "Configuring APCu and Redis"
|
||||
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 host --value="127.0.0.1"
|
||||
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set redis port --type=integer --value=6379
|
||||
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" config:system:set redis timeout --type=float --value=1.5
|
||||
|
||||
# =========================
|
||||
# CRON
|
||||
# =========================
|
||||
log "Configuring cron background jobs"
|
||||
systemctl enable --now cronie
|
||||
|
||||
cat > /etc/cron.d/nextcloud <<EOF
|
||||
*/5 * * * * http ${PHP_BIN} -f ${NC_DIR}/cron.php
|
||||
EOF
|
||||
|
||||
chmod 0644 /etc/cron.d/nextcloud
|
||||
systemctl restart cronie
|
||||
|
||||
# =========================
|
||||
# FINALIZE
|
||||
# =========================
|
||||
log "Finalizing"
|
||||
sudo -u http "${PHP_BIN}" "${NC_DIR}/occ" maintenance:update:htaccess || true
|
||||
|
||||
echo
|
||||
echo "=============================================="
|
||||
echo "Nextcloud install completed."
|
||||
echo "URL: http://${NEXTCLOUD_DOMAIN}/nextcloud"
|
||||
echo "Admin user: ${NC_ADMIN_USER}"
|
||||
echo "Data dir: ${NEXTCLOUD_DATA_DIR}"
|
||||
echo "Web root: ${NEXTCLOUD_WEBROOT}"
|
||||
echo "Config dir: ${NEXTCLOUD_CONFIG_DIR}"
|
||||
echo "Valkey: 127.0.0.1:6379"
|
||||
echo "=============================================="
|
||||
echo
|
||||
echo "IMPORTANT:"
|
||||
echo "1) This sets up HTTP only."
|
||||
echo "2) Add TLS separately or put it behind a reverse proxy."
|
||||
echo "3) Edit the variables at the top before running."
|
||||
echo "================================================================="
|
||||
echo " Nextcloud installed successfully"
|
||||
echo " URL: https://${DOMAIN}"
|
||||
echo " Admin user: ${ADMIN_USER}"
|
||||
echo " Admin pass: ${ADMIN_PASS}"
|
||||
echo " Web root: ${NC_DIR}"
|
||||
echo " Data dir: ${NC_DATA_DIR}"
|
||||
echo " PHP: ${PHP_BIN}"
|
||||
echo " FPM svc: ${PHP_FPM_SERVICE}"
|
||||
echo "-----------------------------------------------------------------"
|
||||
echo " Services enabled:"
|
||||
echo " - httpd"
|
||||
echo " - ${PHP_FPM_SERVICE}"
|
||||
echo " - mariadb"
|
||||
echo " - ${REDIS_SERVICE}"
|
||||
echo " - cronie"
|
||||
echo "================================================================="
|
||||
Loading…
Reference in New Issue