You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On the community website, there are only two options available for Nextcloud:
1- Nextcloud VM (Turnkey)
2- Nextcloudpi LXC
Due to my limited knowledge of implementing the scripts you have here, I would like to contribute my small contribution with a bash script for those interested in having Nextcloud installed natively on Debian and configured for a minimum of security.
I'm also leaving it in case anyone in the community understands more than I do about implementing it and incorporating it into the other scripts.
#!/bin/bash
# ALL-IN-ONE script to install Nextcloud on Debian LXC (Proxmox) for PRODUCTION v2
# - Asks for Nextcloud Admin username/password and domain.
# - WITHOUT firewall rule for SSH (assumes access only via Proxmox console).
# Installs: Apache, MariaDB, PHP (generic modules), Redis, APCu.
# Configures: Nextcloud, Apache VirtualHost (HTTP for reverse proxy), Firewall (ufw),
# Basic MariaDB hardening, Nextcloud Cron Task.
# Generates: Secure passwords for NC DB User, MariaDB Root.
# DOES NOT include: Local SSL configuration (uses Cloudflare), Backups (uses Proxmox Backup).
# --- Security and Robustness Options ---
set -e # Exit immediately if a command fails
set -o pipefail # Consider failures in pipelines
# set -u # Treat undefined variables as an error
# --- Configuration Variables (DB Passwords are generated) ---
DB_NAME="nextcloud_db"
DB_USER="nextcloud_user"
DB_PASSWORD=$(openssl rand -base64 15) # Nextcloud DB Password (Generated)
DB_ROOT_PASSWORD=$(openssl rand -base64 15) # MariaDB Root Password (Generated)
# Paths and Webserver
NC_PARENT_PATH="/var/www/html"
NC_DIR_NAME="nextcloud"
NC_PATH="${NC_PARENT_PATH}/${NC_DIR_NAME}"
WEB_USER="www-data"
WEB_GROUP="www-data"
# Mail Configuration (Optional - adjust or use environment variables)
MAIL_FROM_ADDRESS="no-reply"
MAIL_DOMAIN="" # Will be set with the Nextcloud domain if left empty
# --- Essential Dependency Check ---
#echo "--- Checking basic dependencies ---"
#for cmd in wget unzip openssl mysql apache2ctl php redis-server ufw; do
# if ! command -v $cmd &> /dev/null; then
# echo "Error: Essential command '$cmd' not found. Install the corresponding package." >&2
# exit 1
# fi
#done
# --- Initial Check ---
if [ "$(id -u)" -ne 0 ]; then
echo "Error: This script must be run as root." >&2
exit 1
fi
# --- Get User Data ---
# Domain
while [ -z "$NEXTCLOUD_DOMAIN" ]; do
read -p "Enter the EXACT domain to access Nextcloud (e.g., cloud.your-domain.com): " NEXTCLOUD_DOMAIN
if [ -z "$NEXTCLOUD_DOMAIN" ]; then
echo "Error: The domain cannot be empty."
fi
done
if [ -z "$MAIL_DOMAIN" ]; then
MAIL_DOMAIN="$NEXTCLOUD_DOMAIN"
fi
# Nextcloud Admin User
while [ -z "$ADMIN_USER" ]; do
read -p "Enter the username for the Nextcloud Administrator: " ADMIN_USER
if [ -z "$ADMIN_USER" ]; then
echo "Error: The username cannot be empty."
fi
done
# Nextcloud Admin Password (with confirmation)
while true; do
read -sp "Enter the password for user '${ADMIN_USER}': " ADMIN_PASS
echo # New line after hidden prompt
if [ -z "$ADMIN_PASS" ]; then
echo "Error: The password cannot be empty."
continue
fi
read -sp "Confirm the password: " ADMIN_PASS_CONFIRM
echo # New line
if [ "$ADMIN_PASS" = "$ADMIN_PASS_CONFIRM" ]; then
break
else
echo "Error: Passwords do not match. Try again."
fi
done
# --- Show Generated Passwords (Important for the user to see them NOW) ---
echo "------------------------------------------------------------------------"
echo "Confirmed Configuration and Generated Passwords:"
echo " - Nextcloud Domain : ${NEXTCLOUD_DOMAIN}"
echo " - Nextcloud Admin User : ${ADMIN_USER} (Password ${ADMIN_PASS})"
echo "IMPORTANT! Save these DB passwords in a safe place NOW:"
echo " - Nextcloud DB User : ${DB_USER}"
echo " - Nextcloud DB Password : ${DB_PASSWORD}"
echo " - MariaDB Root Password : ${DB_ROOT_PASSWORD}"
echo "------------------------------------------------------------------------"
read -p "Passwords shown. Press [Enter] to continue or Ctrl+C to cancel..."
# --- Helper Functions ---
wait_for_apt_lock() {
# Waits for apt/dpkg locks to be released.
while fuser /var/lib/dpkg/lock >/dev/null 2>&1 || fuser /var/lib/apt/lists/lock >/dev/null 2>&1 || fuser /var/cache/apt/archives/lock >/dev/null 2>&1; do
echo "Waiting for apt/dpkg lock to be released..."
sleep 5
done
}
detect_php_version() {
# Detects the installed PHP version and sets paths.
PHP_VERSION=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
PHP_INI_PATH="/etc/php/${PHP_VERSION}/apache2/php.ini"
PHP_CLI_INI_PATH="/etc/php/${PHP_VERSION}/cli/php.ini"
echo "--- Detected PHP version: ${PHP_VERSION} ---"
if [ ! -f "$PHP_INI_PATH" ]; then
echo "Warning: Could not find php.ini for Apache at the expected path (${PHP_INI_PATH}). Searching..."
PHP_INI_PATH=$(find /etc/php/ -name php.ini | grep apache2 | head -n 1)
if [ -z "$PHP_INI_PATH" ]; then echo "Error: Unable to locate php.ini for Apache." >&2; fi
fi
if [ ! -f "$PHP_CLI_INI_PATH" ]; then
echo "Warning: Could not find php.ini for CLI at the expected path (${PHP_CLI_INI_PATH}). Searching..."
PHP_CLI_INI_PATH=$(find /etc/php/ -name php.ini | grep cli | head -n 1)
if [ -z "$PHP_CLI_INI_PATH" ]; then echo "Warning: Unable to locate php.ini for CLI."; fi
fi
}
# --- Start of Installation ---
echo "--- Starting FULL Nextcloud installation for production ---"
export DEBIAN_FRONTEND=noninteractive
# 1. Update system and install dependencies (including ufw)
echo "--- [1/12] Updating packages and installing dependencies ---"
wait_for_apt_lock
apt update
wait_for_apt_lock
apt install -y apache2 mariadb-server libapache2-mod-php \
php-gd php-mysql php-curl php-mbstring php-intl php-imagick php-xml \
php-zip php-bcmath php-gmp php-apcu php-redis redis-server \
wget unzip sudo imagemagick librsvg2-bin ffmpeg php-bz2 php-ldap \
ufw # Ensure ufw is installed
echo "--- Dependencies installed successfully ---"
# 2. Detect PHP version
detect_php_version
# 3. Configure and Harden MariaDB (Basic)
echo "--- [2/12] Configuring and Hardening MariaDB (Basic) ---"
systemctl start mariadb
systemctl enable mariadb
echo "Setting MariaDB root password..."
mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '${DB_ROOT_PASSWORD}'; FLUSH PRIVILEGES;"
echo "MariaDB root password set."
echo "Removing anonymous users and test DB..."
mysql -u root -p"${DB_ROOT_PASSWORD}" -e "DELETE FROM mysql.user WHERE User=''; \
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'); \
DROP DATABASE IF EXISTS test; \
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'; \
FLUSH PRIVILEGES;"
echo "Anonymous users and test DB removed."
echo "Creating database and user for Nextcloud..."
mysql -u root -p"${DB_ROOT_PASSWORD}" <<MYSQL_SCRIPT
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_PASSWORD}';
GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'localhost';
FLUSH PRIVILEGES;
MYSQL_SCRIPT
echo "--- Nextcloud database and user created ---"
echo "--- BASIC MariaDB hardening completed. REVIEW MANUALLY with 'sudo mysql_secure_installation' if you want more security. ---"
# 4. Configure PHP
echo "--- [3/12] Adjusting PHP configuration ---"
# (PHP adjustment code unchanged... uses detected $PHP_INI_PATH and $PHP_CLI_INI_PATH)
if [ -n "$PHP_INI_PATH" ] && [ -f "$PHP_INI_PATH" ]; then
echo "Adjusting ${PHP_INI_PATH}..."
sed -i "s/memory_limit = .*/memory_limit = 1024M/" $PHP_INI_PATH
sed -i "s/upload_max_filesize = .*/upload_max_filesize = 1024M/" $PHP_INI_PATH
sed -i "s/post_max_size = .*/post_max_size = 1024M/" $PHP_INI_PATH
sed -i "s/max_execution_time = .*/max_execution_time = 360/" $PHP_INI_PATH
sed -i "s/max_input_time = .*/max_input_time = 360/" $PHP_INI_PATH
sed -i "s/;date.timezone =.*/date.timezone = UTC/" $PHP_INI_PATH
sed -i "s/;opcache.enable=.*/opcache.enable=1/" $PHP_INI_PATH
sed -i "s/;opcache.enable_cli=.*/opcache.enable_cli=1/" $PHP_INI_PATH
sed -i "s/;opcache.interned_strings_buffer=.*/opcache.interned_strings_buffer=32/" $PHP_INI_PATH
sed -i "s/;opcache.max_accelerated_files=.*/opcache.max_accelerated_files=10000/" $PHP_INI_PATH
sed -i "s/;opcache.memory_consumption=.*/opcache.memory_consumption=128/" $PHP_INI_PATH
sed -i "s/;opcache.save_comments=.*/opcache.save_comments=1/" $PHP_INI_PATH
sed -i "s/;opcache.revalidate_freq=.*/opcache.revalidate_freq=1/" $PHP_INI_PATH
else
echo "Warning: Could not adjust PHP configuration for Apache (${PHP_INI_PATH}). Review manually."
fi
if [ -n "$PHP_CLI_INI_PATH" ] && [ -f "$PHP_CLI_INI_PATH" ]; then
echo "Adjusting ${PHP_CLI_INI_PATH}..."
sed -i "s/memory_limit = .*/memory_limit = 1024M/" $PHP_CLI_INI_PATH
sed -i "s/;date.timezone =.*/date.timezone = UTC/" $PHP_CLI_INI_PATH
sed -i "s/;opcache.enable_cli=.*/opcache.enable_cli=1/" $PHP_CLI_INI_PATH # Enable opcache for CLI
else
echo "Warning: Could not adjust PHP configuration for CLI (${PHP_CLI_INI_PATH}). Review manually."
fi
systemctl restart apache2
echo "--- PHP configuration adjusted ---"
# 5. Configure Apache
echo "--- [4/12] Configuring Apache ---"
# (Apache VirtualHost configuration code unchanged...)
cat <<EOF > /etc/apache2/sites-available/${NEXTCLOUD_DOMAIN}.conf
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName ${NEXTCLOUD_DOMAIN}
DocumentRoot ${NC_PATH}
Alias / "/${NC_PATH}/"
<Directory ${NC_PATH}>
Options +FollowSymlinks
AllowOverride All
Require all granted
<IfModule mod_dav.c>
Dav off
</IfModule>
SetEnv HOME ${NC_PATH}
SetEnv HTTP_HOME ${NC_PATH}
</Directory>
ErrorLog \${APACHE_LOG_DIR}/error_${NEXTCLOUD_DOMAIN}.log
CustomLog \${APACHE_LOG_DIR}/access_${NEXTCLOUD_DOMAIN}.log combined
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains" env=HTTPS
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-SSL "on"
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} DavClnt
RewriteRule ^$ /remote.php/webdav/ [L,R=302]
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteRule ^\.well-known/carddav /remote.php/dav/ [R=301,L]
RewriteRule ^\.well-known/caldav /remote.php/dav/ [R=301,L]
RewriteRule ^remote/(.*) /remote.php [L]
RewriteRule ^(?:build|tests|config|lib|3rdparty|templates)/.* - [R=404,L]
RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
RewriteRule ^(?:\.(?!well-known)|autotest|occ|issue|indie|db_|console).* - [R=404,L]
</IfModule>
<IfModule mod_env.c>
SetEnv MOD_X_ACCEL_REDIRECT_ENABLED off
</IfModule>
</VirtualHost>
EOF
a2enmod rewrite headers env dir mime expires remoteip socache_shmcb ssl
a2ensite ${NEXTCLOUD_DOMAIN}.conf
a2dissite 000-default.conf
systemctl restart apache2
echo "--- Apache configured and restarted ---"
# 6. Download Nextcloud
echo "--- [5/12] Downloading the latest stable version of Nextcloud ---"
# (Download code unchanged...)
LATEST_NC_ZIP_URL="https://download.nextcloud.com/server/releases/latest.zip"
wget --progress=bar:force ${LATEST_NC_ZIP_URL} -O /tmp/nextcloud.zip
echo "--- Download completed ---"
# 7. Extract and move Nextcloud
echo "--- [6/12] Extracting Nextcloud files ---"
# (Extraction code unchanged...)
mkdir -p ${NC_PARENT_PATH}
unzip -q /tmp/nextcloud.zip -d ${NC_PARENT_PATH}/
rm /tmp/nextcloud.zip
if [ ! -d "${NC_PATH}" ]; then echo "Error: Directory ${NC_PATH} was not created after extraction." >&2; exit 1; fi
echo "--- Files extracted to ${NC_PATH} ---"
# 8. Set permissions
echo "--- [7/12] Setting correct permissions for Nextcloud ---"
# (Permissions code unchanged...)
mkdir -p ${NC_PATH}/data
chown -R ${WEB_USER}:${WEB_GROUP} ${NC_PATH}/
find ${NC_PATH}/ -type d -exec chmod 750 {} \;
find ${NC_PATH}/ -type f -exec chmod 640 {} \;
chown -R ${WEB_USER}:${WEB_GROUP} ${NC_PATH}/config ${NC_PATH}/data ${NC_PATH}/apps
chmod 750 ${NC_PATH}/config ${NC_PATH}/data ${NC_PATH}/apps
echo "--- Permissions set ---"
# 9. Run Nextcloud installation via occ (Uses the entered $ADMIN_USER and $ADMIN_PASS variables)
echo "--- [8/12] Running the Nextcloud command-line installer (occ) ---"
cd ${NC_PATH}
sudo -u ${WEB_USER} php occ maintenance:install \
--database "mysql" \
--database-name "${DB_NAME}" \
--database-user "${DB_USER}" \
--database-pass "${DB_PASSWORD}" \
--admin-user "${ADMIN_USER}" \
--admin-pass "${ADMIN_PASS}" \
--data-dir "${NC_PATH}/data"
# Configure trusted domains and reverse proxy
sudo -u ${WEB_USER} php occ config:system:set trusted_domains 0 --value="${NEXTCLOUD_DOMAIN}"
sudo -u ${WEB_USER} php occ config:system:set overwrite.cli.url --value="http://${NEXTCLOUD_DOMAIN}"
sudo -u ${WEB_USER} php occ config:system:set overwriteprotocol --value='https'
# Configure Redis and APCu cache
sudo -u ${WEB_USER} php occ config:system:set memcache.local --value '\OC\Memcache\APCu'
sudo -u ${WEB_USER} php occ config:system:set memcache.distributed --value '\OC\Memcache\Redis'
sudo -u ${WEB_USER} php occ config:system:set memcache.locking --value '\OC\Memcache\Redis'
sudo -u ${WEB_USER} php occ config:system:set redis host --value 'localhost'
sudo -u ${WEB_USER} php occ config:system:set redis port --value 6379
# Optimize database
sudo -u ${WEB_USER} php occ db:add-missing-indices
echo "--- Installation with 'occ' completed ---"
# 10. Optimize and configure Nextcloud (General)
echo "--- [9/12] Applying additional configurations and optimizations ---"
# (occ optimization code unchanged...)
sudo -u ${WEB_USER} php occ config:system:set mail_smtpmode --value 'sendmail'
sudo -u ${WEB_USER} php occ config:system:set mail_sendmailmode --value 'smtp'
sudo -u ${WEB_USER} php occ config:system:set mail_from_address --value "${MAIL_FROM_ADDRESS}"
sudo -u ${WEB_USER} php occ config:system:set mail_domain --value "${MAIL_DOMAIN}"
sudo -u ${WEB_USER} php occ config:system:set default_phone_region --value='ES' # Keep 'ES' or change to desired region code
sudo -u ${WEB_USER} php occ config:system:set maintenance_window_start --value="1"
# Final repair
sudo -u ${WEB_USER} php occ maintenance:repair --include-expensive
echo "--- Additional configuration applied ---"
# 11. Configure Firewall (ufw) - WITHOUT SSH RULE
echo "--- [10/12] Configuring the Firewall (ufw) ---"
ufw default deny incoming
ufw default allow outgoing
# echo "Allowing SSH on port ${SSH_PORT}/tcp..." # RULE REMOVED
# ufw allow ${SSH_PORT}/tcp # RULE REMOVED
echo "Allowing HTTP (Port 80/tcp) for Cloudflare..."
ufw allow 80/tcp
echo "Enabling UFW..."
yes | ufw enable || echo "ufw enable failed, it might already be active or require interaction. Enable manually with 'sudo ufw enable'"
echo "Current firewall status:"
ufw status verbose
echo "--- Firewall configured (WITHOUT SSH access allowed by UFW) ---"
# 12. Configure Nextcloud Cron Task
echo "--- [11/12] Configuring the Nextcloud Cron task ---"
# (Cron configuration code unchanged...)
CRON_FILE="/etc/cron.d/nextcloud"
CRON_JOB="*/5 * * * * ${WEB_USER} /usr/bin/php -f ${NC_PATH}/cron.php"
echo "${CRON_JOB}" > "${CRON_FILE}"
chown root:root "${CRON_FILE}"
chmod 644 "${CRON_FILE}"
systemctl restart cron
echo "--- Cron task configured in ${CRON_FILE} ---"
# 13. Final cleanup and message
echo "--- [12/12] Final Cleanup and Message ---"
systemctl restart apache2
echo "========================================================================"
echo " Basic Nextcloud installation and configuration for production completed! "
echo "========================================================================"
echo ""
echo " Web Access (make sure Cloudflare points to the IP of this LXC):"
echo " https://${NEXTCLOUD_DOMAIN}"
echo ""
echo " Nextcloud Administrator Credentials:"
echo " User: ${ADMIN_USER}"
echo " Password: ${ADMIN_PASS}"
echo ""
echo " !!! SAVE THESE DATABASE CREDENTIALS IN A VERY SAFE PLACE !!!"
echo " Nextcloud DB User : ${DB_USER}"
echo " Nextcloud DB Password : ${DB_PASSWORD}"
echo ""
echo " MariaDB Root User : root@localhost"
echo " MariaDB Root Password : ${DB_ROOT_PASSWORD}"
echo ""
echo " RECOMMENDED next steps:"
echo " 1. Check the Firewall status: sudo ufw status verbose (Confirm there is NO rule for SSH)"
echo " 2. Check the 'Administration -> Overview' section in Nextcloud for potential warnings."
echo " 3. Consider running 'sudo mysql_secure_installation' for more thorough MariaDB hardening."
echo " 4. Configure 'trusted_proxies' in Nextcloud with Cloudflare's IP ranges if you need to see the real IP of visitors."
echo " 5. Verify that the Cron task is working (check in 'Overview' that it says 'Run with Cron')."
echo " 6. Implement monitoring for the server and services."
echo " 7. Remember that Proxmox Backup Server handles backups of the entire container."
echo "========================================================================"
exit 0
Greetings to everyone, and thanks for the great work.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Hello everyone
On the community website, there are only two options available for Nextcloud:
1- Nextcloud VM (Turnkey)
2- Nextcloudpi LXC
Due to my limited knowledge of implementing the scripts you have here, I would like to contribute my small contribution with a bash script for those interested in having Nextcloud installed natively on Debian and configured for a minimum of security.
I'm also leaving it in case anyone in the community understands more than I do about implementing it and incorporating it into the other scripts.
Greetings to everyone, and thanks for the great work.
Beta Was this translation helpful? Give feedback.
All reactions