Nextcloud

Installing Nextcloud manually. No turnkey Linux, no community script. We install Nextcloud manually. Step by step. Just like they used to do it in the old days. So you can understand why certain things work the way they do. You'll also learn something about Linux, which is a good thing.

Part 1: Creating the VM and Installing Debian 13

Proxmox VM Erstellung

Objective of This Section

In this first part, we create a virtual machine in Proxmox and install a minimal Debian 13 system on it.

At the end of this section:


Prerequisites

Hardware Recommendations

VM Parameters (Example)

Note:
The data disk is not used during the Debian installation,
but will be mounted separately at a later stage.


Required Credentials (Example)

⚠️ Note:
In a production environment, use secure, unique passwords
and store them in a password manager.


Debian Installation Medium

We use Debian 13 (amd64).

Download source (ISO): https://debian.snt.utwente.nl/debian-cd/13.3.0/amd64/iso-cd/ 


Step 1: Create the VM in Proxmox

  1. Create a new VM
  2. Assign the desired VM ID
  3. Select the previously downloaded Debian ISO


Step 2: VM System Configuration

Machine Type and Agent

Why q35 instead of i440fx:
The q35 machine type emulates a modern Intel chipset with native PCIe support. This enables proper PCIe passthrough (e.g., for GPUs or NVMe devices), AHCI controllers, and vIOMMU emulation. Compared to the legacy i440fx, it is significantly better suited for modern guest systems and extensions.

QEMU Guest Agent:
The QEMU Guest Agent is a small daemon running inside the guest system that enables direct communication with Proxmox. It allows clean shutdowns (instead of ACPI force-off), freezes file systems before snapshots/backups (ensuring consistency), and provides accurate status information such as IP addresses and memory usage.


Configure the System Disk


Add Second Disk (Data)

We now add a second disk, which will later be used exclusively for Nextcloud data.

We deliberately start the data disk at 200 GB. It can later be expanded easily in Proxmox and within the guest system to demonstrate dynamic storage growth in a homelab environment.


CPU Configuration

Why host:
The CPU type host passes all features and extensions of the physical host CPU (e.g., AVX, AES-NI) directly to the VM. This provides maximum performance. However, it is only recommended if you do not plan live migration between hosts with different CPU types, as this can cause migration failures.


Memory


Network

The default network configuration can remain unchanged.


Review Configuration

If everything is configured correctly, the VM summary should look similar to this.

Now start the VM and begin the Debian installation.


Step 3: Install Debian

Language & Region

To select Germany:

  1. Other
  2. Europe
  3. Germany

The keyboard layout can then be accepted as proposed.


Hostname & Domain

In this example, I chose:


Set Root Password

Assign a strong root password.

Since direct SSH login as root poses a security risk, we will disable this capability after installation.


Create a Regular User

In addition to the root user, we require a regular user account.
In this example, the username is ncadmin. Assign a strong password here as well.


Partitioning

Then write the changes to disk.


Partitioning Notes

During Debian installation, the commonly selected option is
“Guided – use entire disk.”

An alternative is:
“Guided – use entire disk and set up LVM.”

This creates Logical Volume Manager (LVM) volumes, allowing more flexible resizing of partitions (especially the root filesystem) later without repartitioning the disk.


Swap Area

Regardless of the partitioning method, a swap partition or swap file should be configured. In the screenshot above, a 1.8 GB swap partition is shown.

Typical guidelines:


Package Sources & Updates


Software Selection

We install no desktop environment.

The web server will be installed manually later.


Bootloader

The Debian installation is now complete.


Step 4: Verify Boot Order

Remove the ISO from the VM’s CD/DVD drive and set the boot order to prioritize the hard disk. Otherwise, the VM may continuously attempt to boot from the empty ISO.

If the VM boots from the ISO again:

  1. Power off the VM
  2. Options → Boot Order
  3. Move the system disk to the top
  4. Move the ISO down or disable it

Boot order incorrect

Boot order correct


Result

If everything was completed correctly, you should now see the Debian 13 login console.


Next Step

Continue with:
Part 2: Configure IP, User Permissions, and Second Data Disk

Part 2: Configuring IP, User Privileges, and the Second Data Disk

Nextcloud on Proxmox

Objective of This Section

In this section, we further configure the freshly installed Debian VM. We assign a static IP address, establish proper user privileges, and permanently mount the second disk for Nextcloud data.

All packages will be updated to the latest state, and clean administrative privileges will be prepared.

At the end of this section:


Step 1: Log In to the VM and Initial Overview

Prerequisites

Hardware Recommendations

VM Parameters (Example)

Required Credentials (Example)

Log In via SSH

Start the VM in Proxmox and determine the currently assigned IP address.

Then connect via SSH using the admin user ncadmin (or the user created in Part 1):

# Use your VM’s name and IP address
ssh ncadmin@192.168.10.120

On first connection, confirm the fingerprint with yes, then enter the password.


Step 2: Configure a Static IP Address

Objective

The VM must always be reachable under the same IP address. This is a prerequisite for DNS configuration, reverse proxy usage, and later for Nextcloud itself.

Edit Network Configuration

Open the file: /etc/network/interfaces:

sudo nano /etc/network/interfaces

Modify the primary interface as follows (the interface name may differ, often ens18):

# The primary network interface
allow-hotplug ens18
#iface ens18 inet dhcp
iface ens18 inet static
    address 192.168.10.120
    netmask 255.255.255.0
    gateway 192.168.10.1
    dns-nameservers 192.168.10.6 1.1.1.1

Adjust the IP addresses to match your network.

Save with CTRL+O, confirm with Enter, exit with CTRL+X.

To ensure that the dns-nameservers defined in the interfaces file are actually applied, the resolvconf package must be installed and enabled:

sudo apt install resolvconf
sudo systemctl enable resolvconf
sudo systemctl start resolvconf

Restart networking:

sudo systemctl restart networking

Important: Do not close the current terminal.

Instead, open a new terminal and test whether SSH login works again.


Step 3: Update the System and Root Access

Switch to Root Mode

su -

Update the System

apt update
apt full-upgrade

This updates both the package lists and all installed packages.

Optionally, the hostname can also be adjusted at this stage.


Step 4: Configure sudo Privileges

The regular user should be able to perform administrative tasks without remaining logged in as root.

Install sudo

apt install sudo

Add User to sudo Group

usermod -aG sudo ncadmin

Afterward, log out from root. Future administrative commands can be executed using sudo.


Step 5: Prepare the Second Disk

The second virtual disk will be partitioned, formatted, and mounted as the data directory for Nextcloud.

⚠️ The mount point /srv/cloud.zn80.net is only an example.
You may use any suitable path, such as /srv/nextcloud/data, /var/lib/nextcloud, or /home/ncadmin/cloud-data. Choose a structure that aligns with your system design and remains intuitive.

Overview of Available Drives

lsblk

The second disk is usually /dev/sdb.

Create Partition

sudo fdisk /dev/sdb

Within fdisk, enter:

Create Filesystem

sudo mkfs.ext4 -L cloud.zn80.net /dev/sdb1

Create Mount Directory

sudo mkdir -p /srv/cloud.zn80.net

Step 6: Permanently Mount the Disk

Objective

The data disk should automatically mount at system startup.

Determine UUID

blkid

Note the UUID of /dev/sdb1.

The UUID is important because device names may change after reboot, whereas UUIDs remain constant.

Edit /etc/fstab

sudo nano /etc/fstab

Add or modify the following line:

# nextcloud data
UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX  /srv/cloud.zn80.net  ext4  defaults,noatime  0  2

Save and close the editor.

Test Mount

sudo mount -a
df -h

The disk should now be mounted under /srv/cloud.zn80.net.


The system is now fully prepared. The actual Nextcloud installation follows in:

Part 3: Downloading, Installing, and Configuring Nextcloud


Step 7: Resize the Disk (Optional)

⚠️ Important Notice Before Resizing
Before resizing the data disk, create a backup of the VM or critical data. A mistake (e.g., selecting the wrong partition) can result in complete data loss. The VM must be powered off and on again for the rescan and parted steps. Live resizing using resize2fs works only with ext4 and a mounted filesystem, but it is riskier and not always recommended. Proceed carefully and verify the partition before modifying it.

Objective

If additional storage is required later, the existing partition can be expanded without data loss.

Resize Disk in Proxmox

Rescan in Debian

echo 1 > /sys/block/sdb/device/rescan

Reboot the VM if necessary.

Check Free Space

parted -s -a opt /dev/sdb "print free"

Resize Partition

parted -s -a opt /dev/sdb "resizepart 1 100%"

Resize Filesystem

e2fsck -f /dev/sdb1
resize2fs /dev/sdb1

Afterward, lsblk and df -h will reflect the new size.

Note: Differences in displayed sizes are due to GB vs. GiB.

Teil 3: Downloading, installing and configuring Nextcloud

Objective of This Section

In this section, we install Nextcloud completely on the prepared Debian 13 system. We set up the LAMP stack, configure Apache and PHP specifically for Nextcloud, integrate the data directory outside the webroot, and complete the installation including essential optimizations.

At the end of this section:


Important Security Notice

For secure operation on the public internet, a reverse proxy with HTTPS is mandatory (e.g., Nginx Proxy Manager, Traefik, or a standalone Nginx setup with Let’s Encrypt).

Without HTTPS (and HSTS), it is strongly discouraged to expose the Nextcloud instance beyond the local network. You may operate it internally first and enable external access later with a proxy and certificate at any time.

Further information:


Update the System

Before beginning the installation, ensure the system is fully up to date:

sudo apt update && sudo apt full-upgrade -y

Install and Secure MariaDB

Install the database server and client:

sudo apt install mariadb-server mariadb-client-compat

Enter the MariaDB shell and create the Nextcloud database:

sudo mariadb

Inside the MariaDB shell:

CREATE DATABASE nextcloud;
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost' IDENTIFIED BY '<DATABASE_PASSWORD>';
FLUSH PRIVILEGES;
EXIT;

Secure the MariaDB installation:

sudo mysql_secure_installation

Install Apache, PHP, and Required Extensions

Install Apache indirectly via PHP packages along with all required extensions:

sudo apt install imagemagick-7.q16 php php-apcu php-bcmath php-cli php-common php-curl php-gd php-gmp php-imagick php-intl php-mbstring php-mysql php-zip php-bz2 php-xml

Enable required PHP modules:

sudo phpenmod apcu bcmath gmp imagick intl unzip

Ensure unzip and wget are installed:

sudo apt install unzip wget

Download and Prepare Nextcloud

Download and extract the latest Nextcloud version:

wget https://download.nextcloud.com/server/releases/latest.zip
unzip latest.zip

Rename the extracted directory to the service FQDN and move it into Apache’s web directory:

mv nextcloud cloud.zn80.net
sudo chown -R www-data:www-data cloud.zn80.net
sudo mv cloud.zn80.net /var/www/

Disable the Apache default site:

sudo a2dissite 000-default.conf

Enable required Apache modules:

sudo a2enmod dir env headers mime rewrite ssl
sudo systemctl restart apache2

Note: Instead of latest.zip, specific previous versions (e.g., nextcloud-29.zip or nextcloud-30.zip) can be downloaded from the official release archive if required for compatibility reasons. However, running outdated versions on the public internet is not recommended.


Create Apache Virtual Host for Nextcloud

Create the configuration file:

sudo nano /etc/apache2/sites-available/cloud.zn80.net.conf

Insert the following content:

<VirtualHost *:80>
    ServerAdmin mail@example.com
    DocumentRoot "/var/www/cloud.zn80.net"
    ServerName cloud.zn80.net

    <Directory "/var/www/cloud.zn80.net/">
        Options FollowSymLinks
        AllowOverride All
        Header always set Referrer-Policy "no-referrer"
        Require all granted
        SetEnv HOME /var/www/cloud.zn80.net
        SetEnv HTTP_HOME /var/www/cloud.zn80.net
    </Directory>

    TransferLog /var/log/apache2/cloud.zn80.net_access.log
    ErrorLog /var/log/apache2/cloud.zn80.net_error.log
</VirtualHost>

Do not enable the site yet.


Optimize PHP for Nextcloud

Edit PHP configuration:

sudo nano /etc/php/8.4/apache2/php.ini

Adjust the following values:

memory_limit = 512M
upload_max_filesize = 200M
post_max_size = 200M
max_execution_time = 360
date.timezone = Europe/Amsterdam

opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=1
opcache.save_comments=1

Enable the site and restart Apache:

sudo a2ensite cloud.zn80.net.conf
sudo systemctl restart apache2

Enable APCu for CLI:

sudo nano /etc/php/8.4/mods-available/apcu.ini

Append:

apc.enable_cli=1

Restart Apache again:

sudo systemctl restart apache2

Prepare the Data Directory

The Nextcloud data directory must not be located inside the webroot.

Ensure the mount point exists:

sudo mkdir -p /srv/cloud.zn80.net

Test mounting:

sudo mount -a
df -h /srv/cloud.zn80.net

Create the actual data directory and apply secure permissions:

sudo mkdir /srv/cloud.zn80.net/data
sudo chown -R www-data:www-data /srv/cloud.zn80.net/data
sudo chmod -R 750 /srv/cloud.zn80.net/data

Web-Based Nextcloud Installation

Open in your browser:

http://cloud.zn80.net

Provide the following:

Admin user:

Data directory:

/srv/cloud.zn80.net/data

Database:

After installation, return to the command line.


Post-Installation Optimizations

Optimize the Nextcloud Database

Temporarily make the occ CLI tool executable:

sudo chmod +x /var/www/cloud.zn80.net/occ

Add missing database indices:

sudo /var/www/cloud.zn80.net/occ db:add-missing-indices

Run repair tasks:

sudo /var/www/cloud.zn80.net/occ maintenance:repair --include-expensive

Remove executable permission again:

sudo chmod -x /var/www/cloud.zn80.net/occ

Secure configuration file:

sudo chown root:www-data /var/www/cloud.zn80.net/config/config.php
sudo chmod 660 /var/www/cloud.zn80.net/config/config.php

Configure Trusted Proxies, Domains, and Caching

Edit configuration file:

sudo nano /var/www/cloud.zn80.net/config/config.php

Add:

'trusted_proxies' => [
    '192.168.10.105',
],

'trusted_domains' => [
    'cloud.zn80.net',
    '192.168.10.120',
],

'overwrite.cli.url' => 'https://cloud.zn80.net',
'overwriteprotocol' => 'https',
'memcache.local' => '\\OC\\Memcache\\APCu',
'default_phone_region' => 'DE',

Run repair command:

sudo -u www-data php occ maintenance:repair

Install Redis (Optional, Recommended)

Install:

sudo apt install redis-server php-redis

Add configuration in config.php:

'filelocking.enabled' => true,
'memcache.locking' => '\\OC\\Memcache\\Redis',
'redis' => [
    'host' => '/run/redis/redis-server.sock',
    'port' => 0,
    'timeout' => 0.0,
],

Restart services:

sudo systemctl restart redis
sudo systemctl restart apache2

The Nextcloud installation is now complete and properly configured.

In Part 4, additional security hardening and recommended configuration adjustments will be implemented.

Part 4: Recommended Security Settings and System Hardening

Recommended Nextcloud Security Settings

Below are several items you should review again after completing the setup. You may already have configured many of them, but a second verification is always advisable.


Update the System and Install Base Packages

After the first boot, log in as root or ncadmin (depending on console or SSH access) and immediately run:

apt update && apt full-upgrade -y

This installs all security updates and bug fixes released since the ISO was built.

Then install useful base utilities:

apt install sudo vim htop curl wget net-tools -y

This ensures sudo availability for regular users and provides improved system and networking tools.


Harden SSH – Disable Password Login and Use Keys

SSH is enabled during installation but not yet hardened.

Edit:

sudo nano /etc/ssh/sshd_config

Set:

PermitRootLogin prohibit-password
PasswordAuthentication no

Generate an SSH key on your client:

ssh-keygen

Copy the public key to the server:

ssh-copy-id ncadmin@your-vm-ip

Restart SSH:

systemctl restart ssh

From this point forward, only key-based authentication is allowed, effectively preventing password brute-force attacks.


Configure Cron for Nextcloud

Nextcloud requires a recurring background job (file scanning, mail delivery, app updates, etc.).

Create a cron job:

crontab -e

Add:

*/5 * * * * php -f /var/www/cloud.zn80.net/cron.php

Alternatively, use a systemd timer.

Without cron, background tasks run only during active web sessions, which can cause delays or stuck jobs.

Note: Normally, the cron job is created with:

crontab -u www-data -e

This may not work in this setup if the ownership of the configuration file has been changed earlier.


Install Fail2Ban Against Brute-Force Attacks

Install Fail2Ban:

apt install fail2ban -y

Enable and start it:

systemctl enable --now fail2ban

Fail2Ban monitors SSH logs and bans IP addresses after multiple failed login attempts (default: 5 attempts within 10 minutes). The Debian defaults are typically sufficient for a homelab environment.

Optional: Adjust /etc/fail2ban/jail.local for longer ban durations or email notifications.


.htaccess Optimization and Security Headers

After installation, update the .htaccess file:

sudo -u www-data php occ maintenance:repair

Add security headers in the Apache VirtualHost configuration (preferably under *:443) or in your reverse proxy configuration:

Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"

If running behind Nginx Proxy Manager, add the following under the proxy host’s custom configuration:

add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

These headers mitigate:


Enable HSTS (Strict-Transport-Security)

Within the proxy host SSL settings, enable:

Nextcloud expects at least:

max-age=15552000

If necessary, manually add:

add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;

Important: Only enable HSTS if HTTPS is permanently available.


Additional Reverse Proxy Adjustments (Optional)

To prevent header conflicts or WebSocket upgrade issues:

proxy_hide_header Upgrade;
proxy_hide_header Connection;

For additional protection:

add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

After saving, test the Nextcloud instance (Admin → Overview / Security scan).


Adjust Data Directory Permissions

The data directory /srv/cloud.zn80.net/data should preferably use:

chmod 770 /srv/cloud.zn80.net/data
chown -R www-data:www-data /srv/cloud.zn80.net/data

While 750 may work, 770 is recommended to prevent permission issues during app installation or large uploads.


Enable Firewall with UFW

If the server is directly exposed to the internet, install UFW:

apt install ufw -y

Allow necessary ports:

ufw allow OpenSSH
ufw allow 80,443/tcp

Enable and verify:

ufw enable
ufw status verbose

UFW blocks all other ports by default.


Additional Security Recommendations

apt install unattended-upgrades -y

Review configuration in:

/etc/apt/apt.conf.d/50unattended-upgrades

Check for updates regularly:

apt list --upgradable

With these measures in place, your Nextcloud instance should achieve strong security ratings (e.g., A/A+ on securityheaders.com or Mozilla Observatory) and display no major warnings in the Nextcloud admin security overview.