A default Nextcloud installation is not a secure Nextcloud installation. Out of the box, Nextcloud ships with sensible defaults for getting started quickly, but production deployments that handle real organizational data require hardening at every layer of the stack -- from the operating system up through the web server, PHP runtime, and the Nextcloud application itself.

This guide walks through a comprehensive security hardening process for Nextcloud deployments. It assumes you already have a working Nextcloud instance (if you don't, start with our production installation guide) and covers the security measures that separate a test environment from an infrastructure you can trust with sensitive data.

We will work from the bottom of the stack upward: OS-level hardening first, then web server and PHP configuration, then Nextcloud application settings, and finally infrastructure-level protections. Each section includes concrete configurations you can apply immediately.

OS-Level Hardening

The operating system is your first line of defense. If an attacker gains OS-level access, every layer above it -- Nginx, PHP, Nextcloud, your data -- is compromised. These measures reduce the attack surface of the underlying server.

SSH Hardening

SSH is the most common entry point for brute-force attacks against Linux servers. The default configuration on most distributions is permissive enough to allow password-based authentication from any IP address, which is an invitation for automated attack scripts.

Edit /etc/ssh/sshd_config and apply the following changes:

# Disable root login entirely
PermitRootLogin no

# Disable password authentication -- use keys only
PasswordAuthentication no
PubkeyAuthentication yes

# Restrict to SSH protocol 2
Protocol 2

# Limit authentication attempts
MaxAuthTries 3
MaxSessions 3

# Disable empty passwords
PermitEmptyPasswords no

# Disable X11 forwarding (not needed for servers)
X11Forwarding no

# Set idle timeout (disconnect after 5 minutes of inactivity)
ClientAliveInterval 300
ClientAliveCountMax 2

# Restrict SSH to specific users (replace with your admin username)
AllowUsers deployadmin

# Use strong key exchange algorithms only
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

Before restarting SSH, make sure you have your SSH key added to ~/.ssh/authorized_keys for the allowed user. Test the configuration syntax first:

sudo sshd -t
sudo systemctl restart sshd

Important: Always keep an active SSH session open while testing new SSH configurations. If you lock yourself out, you will need console access to recover.

UFW Firewall Configuration

Uncomplicated Firewall (UFW) provides a straightforward interface for managing iptables rules. For a Nextcloud server, you need exactly three ports open to the public internet: SSH, HTTP (for Let's Encrypt renewal redirects), and HTTPS.

# Reset to default deny
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH (change port if using non-standard)
sudo ufw allow 22/tcp

# Allow HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable the firewall
sudo ufw --force enable

# Verify rules
sudo ufw status verbose

If you are running Redis on a separate server (which is recommended for high-availability deployments), you will also need to allow port 6379 from that specific internal IP -- never from the public internet:

sudo ufw allow from 10.0.1.0/24 to any port 6379 proto tcp

Fail2ban for SSH Protection

Even with key-based authentication, SSH brute-force attempts consume resources and pollute your logs. Fail2ban monitors log files and automatically bans IP addresses that show malicious behavior.

sudo apt install -y fail2ban

Create a local configuration file at /etc/fail2ban/jail.local:

[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
backend = systemd

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400

This configuration bans any IP that fails SSH authentication three times within ten minutes, and the ban lasts 24 hours. Start and enable fail2ban:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Automatic Security Updates

Unattended security patches ensure that critical OS vulnerabilities are addressed promptly without waiting for manual intervention:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Edit /etc/apt/apt.conf.d/50unattended-upgrades to ensure security updates are enabled and optionally configure email notifications for applied patches.

Kernel Hardening with sysctl

Add the following to /etc/sysctl.d/99-nextcloud-hardening.conf:

# Prevent IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Disable source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0

# Enable SYN flood protection
net.ipv4.tcp_syncookies = 1

# Log suspicious packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Disable IPv6 if not needed
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

Apply the settings:

sudo sysctl -p /etc/sysctl.d/99-nextcloud-hardening.conf

Web Server Hardening (Nginx)

Nginx sits between the internet and your Nextcloud PHP application. Proper configuration here prevents information disclosure, enforces transport security, and blocks common attack vectors.

TLS 1.3 and Strong Cipher Configuration

Your Nginx SSL configuration should enforce modern TLS protocols and disable legacy ciphers. In the server block for your Nextcloud domain:

# TLS configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

TLS 1.0 and 1.1 are deprecated and should never be enabled. TLS 1.2 is the minimum acceptable version, and TLS 1.3 offers both improved security and better performance through its reduced handshake latency. OCSP stapling avoids the privacy concern of clients needing to contact the certificate authority directly to verify certificate revocation status.

Security Headers

HTTP security headers instruct browsers to enforce specific security policies. These are essential for preventing cross-site scripting, clickjacking, and content-type sniffing attacks:

# HSTS -- force HTTPS for 2 years, including subdomains
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# Prevent clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;

# Prevent MIME type sniffing
add_header X-Content-Type-Options "nosniff" always;

# Referrer policy -- don't leak URLs to external sites
add_header Referrer-Policy "no-referrer" always;

# Permissions policy -- disable unnecessary browser features
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;

# XSS protection (legacy browsers)
add_header X-XSS-Protection "1; mode=block" always;

# Prevent Adobe cross-domain requests
add_header X-Permitted-Cross-Domain-Policies "none" always;

# Prevent search engines from indexing your private cloud
add_header X-Robots-Tag "noindex, nofollow" always;

Note on HSTS preload: Only add the preload directive if you are certain your domain will always use HTTPS. HSTS preloading is essentially permanent -- removing your domain from browser preload lists takes months.

Content Security Policy

Content Security Policy (CSP) headers tell the browser which sources of content are allowed to load. Nextcloud sets its own CSP headers from the application layer, but you can add additional restrictions at the Nginx level. Be careful not to conflict with Nextcloud's own CSP directives -- overly restrictive policies will break Collabora Online, Talk video calls, and third-party apps.

A safe approach is to let Nextcloud manage its own CSP and focus on the other security headers at the Nginx level. If you do want to add CSP at the web server level, test thoroughly in a staging environment first.

Hide Server Information

By default, Nginx announces its version number in response headers and error pages. This gives attackers information about which specific CVEs might apply to your installation:

# In the http block of /etc/nginx/nginx.conf
server_tokens off;

# Also hide PHP version
fastcgi_hide_header X-Powered-By;

Rate Limiting

Rate limiting at the Nginx level protects against brute-force login attempts and denial-of-service attacks before requests even reach PHP:

# In the http block
limit_req_zone $binary_remote_addr zone=nextcloud_login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=nextcloud_general:10m rate=30r/s;

# In the server block -- apply to login endpoint
location /login {
    limit_req zone=nextcloud_login burst=3 nodelay;
    # ... rest of location config
}

# Apply general rate limit to all PHP requests
location ~ \.php(?:$|/) {
    limit_req zone=nextcloud_general burst=50 nodelay;
    # ... rest of fastcgi config
}

The login zone allows five requests per minute per IP address, with a burst of three. The general zone allows thirty requests per second, which is generous enough for normal Nextcloud operation (file syncs generate many rapid API calls) while still capping abusive traffic.

PHP Hardening

PHP is the runtime that executes all of Nextcloud's application code. Hardening PHP means limiting what that runtime can do -- and more importantly, what an attacker can do if they find a vulnerability in any PHP code running on the server.

Disable Dangerous Functions

PHP includes several functions that have legitimate uses but are commonly exploited in web application attacks. Disable any function that Nextcloud does not require. In /etc/php/8.3/fpm/conf.d/99-security.ini:

; Disable dangerous functions
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file,show_source,dl

; Restrict file access to the Nextcloud directory
open_basedir = /var/www/nextcloud:/tmp:/var/log/nextcloud:/dev/urandom

; Hide PHP version in response headers
expose_php = Off

; Disable remote file inclusion
allow_url_fopen = On
allow_url_include = Off

; Session security
session.cookie_httponly = On
session.cookie_secure = On
session.use_strict_mode = On
session.cookie_samesite = Strict

Warning: Some Nextcloud apps may require exec or proc_open. If you use Collabora Online, the document conversion process needs proc_open. If you use the preview generator app, it needs exec to call external programs like ffmpeg and LibreOffice. Test your specific app configuration after applying these restrictions. You may need to selectively re-enable certain functions.

open_basedir Restriction

The open_basedir directive is one of the most effective PHP security measures. It restricts which directories PHP can access on the filesystem. If an attacker exploits a vulnerability in a Nextcloud app or plugin, they cannot read /etc/passwd, access other websites on the server, or traverse outside the allowed paths.

The paths listed above cover what Nextcloud needs:

If your Nextcloud data directory is on a separate mount point (recommended for production as discussed in our performance tuning guide), add that path to the open_basedir directive as well.

PHP-FPM Pool Isolation

If you run any other PHP applications on the same server (which is discouraged for production Nextcloud), create a dedicated PHP-FPM pool for Nextcloud that runs under its own system user. This ensures process-level isolation:

[nextcloud]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm-nextcloud.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20

; Chroot the pool (advanced)
; chroot = /var/www/nextcloud
; chdir = /

; Environment cleanup
env[HOSTNAME] = $HOSTNAME
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

; Logging
php_admin_value[error_log] = /var/log/nextcloud/php-fpm.log
php_admin_flag[log_errors] = on

Nextcloud Application Hardening

With the OS, web server, and PHP layers secured, the next focus is Nextcloud's own security settings. These are configured through the admin panel, the config.php file, and the occ command-line tool.

Brute Force Protection

Nextcloud includes built-in brute force protection that throttles login attempts after repeated failures. This is enabled by default, but you should verify it is active:

sudo -u www-data php /var/www/nextcloud/occ config:system:get auth.bruteforce.protection.enabled

If this returns nothing or false, enable it:

sudo -u www-data php /var/www/nextcloud/occ config:system:set auth.bruteforce.protection.enabled --value=true --type=boolean

The built-in protection adds increasing delays after failed login attempts. After 10 failed attempts, the delay reaches approximately 25 seconds per attempt, making automated brute-force attacks impractical. However, this should complement -- not replace -- fail2ban protection at the OS level.

Two-Factor Authentication

Passwords alone are not sufficient for securing organizational data. Nextcloud supports multiple 2FA providers, and enforcing 2FA for all users should be a non-negotiable policy for production deployments.

Install and enable the TOTP (Time-based One-Time Password) provider:

sudo -u www-data php /var/www/nextcloud/occ app:enable twofactor_totp

To enforce 2FA for all users, install the "Two-Factor Admin Support" app:

sudo -u www-data php /var/www/nextcloud/occ app:enable twofactor_admin

From the Nextcloud admin panel, navigate to Security settings and enable "Enforce two-factor authentication." Users who have not configured 2FA will be prompted to set it up on their next login. For organizations using LDAP or Active Directory, consider TOTP, WebAuthn/FIDO2 hardware keys, or integration with your existing identity provider.

Password Policies

Configure strong password requirements through the Nextcloud admin panel or via occ:

# Minimum password length
sudo -u www-data php /var/www/nextcloud/occ config:app:set password_policy minLength --value=12

# Require uppercase letters
sudo -u www-data php /var/www/nextcloud/occ config:app:set password_policy enforceUpperLowerCase --value=1

# Require numbers
sudo -u www-data php /var/www/nextcloud/occ config:app:set password_policy enforceNumericCharacters --value=1

# Require special characters
sudo -u www-data php /var/www/nextcloud/occ config:app:set password_policy enforceSpecialCharacters --value=1

# Check against Have I Been Pwned database
sudo -u www-data php /var/www/nextcloud/occ config:app:set password_policy enforceHaveIBeenPwned --value=1

The "Have I Been Pwned" integration checks password hashes against a database of over 600 million compromised passwords. The check uses k-anonymity -- only a partial hash prefix is sent to the API, so the full password is never transmitted.

File Access Control

Nextcloud's File Access Control app lets you define rules that automatically restrict file operations based on criteria like file type, size, user group, IP address, or time of day. Common use cases include:

Enable the app and configure rules from the admin panel:

sudo -u www-data php /var/www/nextcloud/occ app:enable files_accesscontrol

For organizations subject to GDPR compliance requirements, file access control rules provide an auditable mechanism for enforcing data handling policies at the application layer.

Hardening config.php

Several config.php settings directly affect security. Add or verify these entries in /var/www/nextcloud/config/config.php:

// Restrict admin access to trusted proxies
'trusted_proxies' => ['10.0.1.0/24'],

// Force HTTPS
'overwriteprotocol' => 'https',

// Set trusted domains (only your actual domain)
'trusted_domains' => array(
    0 => 'cloud.yourdomain.com',
),

// Disable app installation from the store (recommended for production)
'appstoreenabled' => false,

// Require 2FA for all users
'twofactor_enforced' => 'true',

// Set stricter default share permissions (read-only)
'sharing.federation.allowHttpFallback' => false,

// Log security events
'loglevel' => 2,
'log_type' => 'file',
'logfile' => '/var/log/nextcloud/nextcloud.log',
'log_rotate_size' => 104857600,

// Disable public link sharing if not needed
// 'sharing.enable_link_sharing' => false,

Setting appstoreenabled to false prevents anyone -- including administrators -- from installing apps through the web interface. In a production environment, app installation should be a deliberate, tested process performed through the occ command line during maintenance windows, not an ad-hoc action from the browser.

Fail2ban for Nextcloud

While Nextcloud has built-in brute force protection, fail2ban provides OS-level IP banning that stops malicious traffic before it reaches PHP. This is significantly more efficient -- a banned IP at the firewall level consumes zero PHP-FPM workers.

Create the Nextcloud Filter

Create /etc/fail2ban/filter.d/nextcloud.conf:

[Definition]
_groupsre = (?:(?:,?\s*"\w+":(?:"[^"]*"|\w+))*)
failregex = ^\{%(_groupsre)s,?\s*"remoteAddr":""%(_groupsre)s,?\s*"message":"Login failed:
            ^\{%(_groupsre)s,?\s*"remoteAddr":""%(_groupsre)s,?\s*"message":"Trusted domain error.
datepattern = ,?\s*"time"\s*:\s*"%%Y-%%m-%%dT%%H:%%M:%%S(%%z)?"

Create the Nextcloud Jail

Add to /etc/fail2ban/jail.local:

[nextcloud]
enabled = true
port = 80,443
protocol = tcp
filter = nextcloud
logpath = /var/log/nextcloud/nextcloud.log
maxretry = 5
bantime = 86400
findtime = 3600

This configuration bans any IP that triggers five failed logins within one hour, with a 24-hour ban duration. Restart fail2ban to apply:

sudo systemctl restart fail2ban

Verify the jail is active:

sudo fail2ban-client status nextcloud

You should see output showing the jail is active with the correct log path. Monitor the ban list periodically:

sudo fail2ban-client get nextcloud banip

End-to-End Encryption

Nextcloud supports end-to-end encryption (E2EE) for folders that require the highest level of confidentiality. When E2EE is enabled on a folder, files are encrypted on the client device before upload and can only be decrypted by users who have been granted access. The server stores only ciphertext -- not even the server administrator can read the contents.

Enable the E2EE app:

sudo -u www-data php /var/www/nextcloud/occ app:enable end_to_end_encryption

Important considerations for E2EE deployment:

For most organizations, server-side encryption (enabled via the "Default encryption module" app) provides a more practical balance. It encrypts files at rest on the storage backend while still allowing server-side features like search and preview generation. The trade-off is that the server holds the encryption keys, so a compromise of the server could expose the keys.

Infrastructure-Level Security

Application-level hardening is necessary but not sufficient. The infrastructure your Nextcloud server runs on determines the baseline security posture that no amount of configuration can compensate for if it is absent.

DDoS Protection

A Nextcloud server is a web-facing application, which makes it a target for volumetric DDoS attacks. Even a modest attack can saturate your server's bandwidth and make the service unavailable to all users. Infrastructure-level DDoS mitigation -- not application-level rate limiting -- is the only effective defense against large-scale attacks.

MassiveGRID provides 12 Tbps DDoS protection across all hosting plans, including the managed Nextcloud hosting platform. This protection operates at the network edge, filtering malicious traffic before it reaches your server. Application-level attacks (L7 DDoS) are handled by intelligent traffic analysis that distinguishes between legitimate Nextcloud sync traffic and malicious request floods.

Storage Encryption

Beyond Nextcloud's application-level encryption, the underlying storage should provide encryption at rest. If your Nextcloud data resides on Ceph distributed storage, Ceph supports encryption at the OSD level using dm-crypt/LUKS. This protects against physical theft of storage media -- if a drive is removed from the data center, the data on it is unreadable without the encryption key.

On MassiveGRID's infrastructure, all Ceph storage is encrypted at rest using AES-256. The encryption keys are managed separately from the storage nodes, so physical access to a storage device does not grant access to the data.

Physical Security and Data Sovereignty

Infrastructure security extends to the physical data center. The facilities housing your Nextcloud server should provide:

For organizations with data residency requirements, the physical location of the data center determines which legal jurisdictions govern your data. MassiveGRID operates data centers in key locations including New York, London, Frankfurt, and Singapore, allowing you to choose the jurisdiction that matches your compliance obligations.

Network Segmentation

In a properly architected deployment, your Nextcloud web server, database server, and Redis cache server should be on separate network segments with firewall rules restricting communication to only the necessary ports and protocols. The database server should never be accessible from the public internet.

MassiveGRID's high-availability infrastructure implements network segmentation by default, with internal traffic between application and database tiers flowing over a private network that is not routable from the internet.

20-Point Security Audit Checklist

Use this checklist to audit the security posture of your Nextcloud deployment. Each item maps to a section of this guide:

# Security Control Layer Priority
1 SSH root login disabled, key-only authentication enforced OS Critical
2 UFW firewall active with only ports 22, 80, 443 open OS Critical
3 Fail2ban active for SSH with maximum 3 retries OS High
4 Automatic security updates enabled (unattended-upgrades) OS High
5 Kernel hardening sysctl parameters applied OS Medium
6 TLS 1.2+ only, strong ciphers, OCSP stapling enabled Web Server Critical
7 HSTS header set with includeSubDomains Web Server Critical
8 All security headers present (X-Frame-Options, X-Content-Type-Options, etc.) Web Server High
9 Server version information hidden (server_tokens off) Web Server Medium
10 Rate limiting configured for login and general endpoints Web Server High
11 PHP dangerous functions disabled (exec, shell_exec, system, etc.) PHP High
12 open_basedir restricting PHP filesystem access PHP High
13 PHP expose_php set to Off PHP Medium
14 Nextcloud brute force protection enabled Application High
15 Two-factor authentication enforced for all users Application Critical
16 Strong password policy configured (12+ characters, complexity, HIBP check) Application High
17 App store disabled in production (appstoreenabled = false) Application Medium
18 Fail2ban jail active for Nextcloud login failures Application High
19 DDoS protection active at infrastructure level Infrastructure Critical
20 Storage encryption at rest (Ceph dm-crypt/LUKS or equivalent) Infrastructure High

If your deployment passes all 20 checks, your Nextcloud instance is significantly more secure than the vast majority of deployments in production today. If any critical items are missing, address those first -- they represent the highest-impact risks.

Ongoing Security Maintenance

Security hardening is not a one-time activity. It requires ongoing attention:

Why Infrastructure Matters as Much as Configuration

You can follow every hardening step in this guide and still have a vulnerable deployment if the underlying infrastructure is compromised. A hypervisor-level vulnerability on a shared hosting platform can expose your server's memory to other tenants. A data center without proper physical security can have drives removed. A network without DDoS protection can be taken offline by a $50 booter service.

This is why MassiveGRID's managed Nextcloud hosting applies these hardening measures at every layer by default. The infrastructure includes single-tenant compute with no noisy-neighbor performance degradation, Ceph distributed storage with AES-256 encryption at rest, 12 Tbps DDoS protection, and data centers with ISO 27001-certified physical security. The OS, web server, and PHP layers are hardened according to the practices described in this guide, and the security configuration is maintained as part of the managed service -- including timely application of security patches and ongoing monitoring.

For organizations that want the security of a fully hardened Nextcloud deployment without maintaining the expertise to implement and monitor all 20 checklist items continuously, MassiveGRID's managed Nextcloud platform provides a production-ready solution with enterprise-grade security built into every layer of the stack.