NextCloud

More Raspberry Pi Projects

Project 1 — Personal Cloud with Nextcloud

What you will build A self-hosted Google Drive / Dropbox replacement — file sync, photos, calendar, and contacts on your own hardware
Difficulty Intermediate — builds on the web server skills from Course 1
Time to complete 1.5 – 3 hours
Recommended hardware Raspberry Pi 4 (4 GB RAM), USB SSD for storage, wired Ethernet

What is Nextcloud?

Nextcloud is a self-hosted cloud platform — think Google Drive, Google Photos, Google Calendar, and Google Contacts, all rolled into one, running entirely on your own Raspberry Pi. Your files never leave your home network unless you explicitly share them, and there are no storage limits beyond your hard drive.

It replaces a surprising number of cloud subscriptions:

📁 Files Replaces Dropbox / Google Drive Sync files across all devices. Desktop clients for Windows, Mac, Linux. Mobile apps for iOS and Android.
🖼 Photos Replaces Google Photos Auto-upload from your phone. Face recognition, albums, and shared galleries — all locally processed.
📅 Calendar Replaces Google Calendar CalDAV server. Sync with iOS Calendar, Android apps, and Thunderbird.
👤 Contacts Replaces Google Contacts CardDAV server. Sync contacts to your phone without a Google account.
📝 Notes & Tasks Replaces Keep / Todoist Markdown notes app and a Tasks app with CalDAV sync.
💬 Talk Replaces WhatsApp (partially) Encrypted chat and video calls between Nextcloud users — no third-party servers.

What You Will Need

🍓 Raspberry Pi 4 (4 GB+) Nextcloud's PHP processes are memory-hungry. 2 GB works but feels slow with more than one user.
💾 USB SSD SD cards are too slow and wear out quickly under Nextcloud's constant database writes. A USB SSD is essential.
🌐 Domain name + SSL Nextcloud requires HTTPS. If you completed Course 1 Project 1, you already have Apache + Let's Encrypt — this builds on that setup.
📡 Static local IP + port forwarding Port 443 must be forwarded to your Pi. Port 80 is also needed for Let's Encrypt renewal.
Good power supply The official Pi 4 power supply (USB-C, 3A) or better. Avoid cheap chargers — underpowered Pi causes corrupted uploads.
💻 Apache + MariaDB + PHP If you completed Course 1 Project 1 these are already installed. If not, follow Steps 1–3 of that project first.
Course 1 connection: This project assumes you have Apache, MariaDB, and a Let's Encrypt SSL certificate from Course 1, Project 1. If you are starting fresh, complete Steps 1–4 of that project before continuing here.

Step 1 — Install Required PHP Extensions

Nextcloud requires several PHP modules beyond the basic set installed in Course 1. Install them all at once:

pi@raspberrypi:~$ sudo apt install -y \
  php-gd php-json php-curl php-mbstring php-intl \
  php-imagick php-xml php-zip php-bcmath php-gmp \
  php-apcu php-redis php-memcached \
  libapache2-mod-php php-mysql

pi@raspberrypi:~$ sudo systemctl restart apache2

Verify the key modules are loaded:

pi@raspberrypi:~$ php -m | grep -E "gd|imagick|apcu|redis"
apcu
gd
imagick
redis

Step 2 — Create the Nextcloud Database

pi@raspberrypi:~$ sudo mysql -u root -p

MariaDB [(none)]> CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
MariaDB [(none)]> CREATE USER 'nextclouduser'@'localhost' IDENTIFIED BY 'StrongPassword123!';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextclouduser'@'localhost';
MariaDB [(none)]> FLUSH PRIVILEGES;
MariaDB [(none)]> EXIT;
The CHARACTER SET utf8mb4 is important — Nextcloud stores emoji and international characters in filenames, and the default MySQL utf8 charset doesn't support 4-byte Unicode characters. Using utf8mb4 from the start avoids a painful migration later.

Step 3 — Download and Install Nextcloud

Download the latest Nextcloud release from nextcloud.com. Always get the current version from the official site rather than apt — the apt version is often many releases out of date:

pi@raspberrypi:~$ cd /tmp
pi@raspberrypi:/tmp$ wget https://download.nextcloud.com/server/releases/latest.zip
pi@raspberrypi:/tmp$ unzip latest.zip
pi@raspberrypi:/tmp$ sudo mv nextcloud /var/www/nextcloud
pi@raspberrypi:/tmp$ sudo chown -R www-data:www-data /var/www/nextcloud
pi@raspberrypi:/tmp$ sudo chmod -R 755 /var/www/nextcloud

Set up a data directory on the external drive

Store your actual files on the external SSD rather than the system SD card:

pi@raspberrypi:~$ sudo mkdir -p /media/mediadrive/nextcloud-data
pi@raspberrypi:~$ sudo chown www-data:www-data /media/mediadrive/nextcloud-data
pi@raspberrypi:~$ sudo chmod 750 /media/mediadrive/nextcloud-data

Step 4 — Configure Apache

Create a virtual host for Nextcloud:

pi@raspberrypi:~$ sudo nano /etc/apache2/sites-available/nextcloud.conf
<VirtualHost *:80>
    ServerName   cloud.yourdomain.com
    DocumentRoot /var/www/nextcloud
    Redirect     permanent / https://cloud.yourdomain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName   cloud.yourdomain.com
    DocumentRoot /var/www/nextcloud

    SSLEngine            on
    SSLCertificateFile    /etc/letsencrypt/live/yourdomain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem

    <Directory /var/www/nextcloud/>
        Require all granted
        AllowOverride All
        Options FollowSymLinks MultiViews

        <IfModule mod_dav.c>
            Dav off
        </IfModule>
    </Directory>

    # Security headers recommended by Nextcloud
    Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains"
    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 "no-referrer"

    ErrorLog  ${APACHE_LOG_DIR}/nextcloud-error.log
    CustomLog ${APACHE_LOG_DIR}/nextcloud-access.log combined
</VirtualHost>

Enable the site and required Apache modules:

pi@raspberrypi:~$ sudo a2ensite nextcloud.conf
pi@raspberrypi:~$ sudo a2enmod rewrite headers env dir mime ssl
pi@raspberrypi:~$ sudo systemctl reload apache2

If you are using a subdomain (cloud.yourdomain.com), add it to your Let's Encrypt certificate:

pi@raspberrypi:~$ sudo certbot --apache -d yourdomain.com -d www.yourdomain.com -d cloud.yourdomain.com

Step 5 — Tune PHP for Nextcloud

Nextcloud's default PHP limits are too low for syncing large files. Edit the PHP configuration:

pi@raspberrypi:~$ sudo nano /etc/php/8.2/apache2/php.ini
# Adjust the version number to match yours: php --version

Find and update these values:

memory_limit       = 512M      # was 128M
upload_max_filesize = 10G       # was 2M  — allows large file uploads
post_max_size       = 10G       # was 8M  — must be >= upload_max_filesize
max_execution_time  = 3600     # was 30  — prevents timeout on large uploads
max_input_time      = 3600     # was 60
output_buffering    = Off      # required by Nextcloud
opcache.enable         = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files  = 10000
opcache.revalidate_freq        = 1
opcache.save_comments          = 1
pi@raspberrypi:~$ sudo systemctl restart apache2

Step 6 — Run the Nextcloud Setup Wizard

Open https://cloud.yourdomain.com in a browser. The setup wizard will appear:

  • Create an admin account — choose a username and a strong password. This is your Nextcloud administrator login.
  • Data folder — change this from the default to your external SSD path: /media/mediadrive/nextcloud-data
  • Database — select MySQL/MariaDB (not SQLite — SQLite is only suitable for testing). Enter:
    • Database user: nextclouduser
    • Database password: your password from Step 2
    • Database name: nextcloud
    • Database host: localhost
  • Install recommended apps — tick the box to install Calendar, Contacts, and Talk. You can add or remove apps later.
  • Click Install and wait — first setup takes 2–5 minutes.
If the wizard times out on slow hardware, don't panic. The installation is still running in the background. Wait a few minutes, then try loading the URL again — you should be taken straight to the login screen.

Step 7 — Set Up the Background Job (Cron)

Nextcloud runs maintenance tasks (sending notifications, cleaning the database, updating search indices) via a background job. The recommended method is a system cron job rather than AJAX:

pi@raspberrypi:~$ sudo crontab -u www-data -e

Add this line:

*/5  *  *  *  *  php -f /var/www/nextcloud/cron.php

Then tell Nextcloud to use cron instead of AJAX. In the Nextcloud admin panel go to Administration Settings → Basic Settings and change Background jobs to Cron.

Step 8 — Fix Security & Settings Warnings

After logging in, go to Administration Settings → Overview. Nextcloud performs a self-check and will flag any issues. The most common ones on a fresh Pi install:

Add trusted domain

If you see "You are accessing the server from an untrusted domain", edit the config file:

pi@raspberrypi:~$ sudo nano /var/www/nextcloud/config/config.php
'trusted_domains' =>
  array (
    0 => 'cloud.yourdomain.com',
    1 => '192.168.1.xx',         # optional: allow local IP access
  ),

Set the default phone region

# In config.php, add inside the array:
'default_phone_region' => 'GB',   # use your country code

Enable memory caching (APCu)

# In config.php, add:
'memcache.local' => '\OC\Memcache\APCu',

After editing config.php, reload Apache:

pi@raspberrypi:~$ sudo systemctl reload apache2

Step 9 — Install Sync Clients

🪟 Windows / 🍎 macOS / 🐧 Linux
Download the Nextcloud Desktop Client from nextcloud.com/install. Install it, click Log in to your Nextcloud, and enter your server URL (https://cloud.yourdomain.com). Choose which folders to sync. The client keeps a local copy of your files in sync with the server automatically.
📱 iOS
Install Nextcloud from the App Store (free). Log in with your server URL and credentials. Enable Auto Upload in Settings to automatically back up photos from your camera roll to Nextcloud — a direct replacement for iCloud Photo Library.
📱 Android
Install Nextcloud from Google Play or F-Droid (free, open source). Auto-upload backs up photos and videos automatically over Wi-Fi. The DAVx⁵ app (free on F-Droid, small fee on Play) syncs your Nextcloud calendar and contacts to the native Android calendar and contacts apps.
📅 Calendar & Contacts sync (all platforms)
Nextcloud exposes CalDAV and CardDAV endpoints. Use these URLs in your calendar/contacts app of choice:

CalDAV: https://cloud.yourdomain.com/remote.php/dav/principals/users/YOUR_USERNAME/
CardDAV: https://cloud.yourdomain.com/remote.php/dav/principals/users/YOUR_USERNAME/

On iOS: Settings → Calendar → Accounts → Add Account → Other → Add CalDAV Account.
On macOS: System Settings → Internet Accounts → Add Account → CalDAV.

Step 10 — Add External Storage

You can mount additional folders — network shares, USB drives, even Google Drive — as storage locations visible inside Nextcloud. Enable the External Storage Support app first:

Go to Apps → Your Apps → External Storage Support → Enable.

Then go to Administration Settings → External Storages and add a mount. Common options:

TypeUse caseNotes
LocalAnother folder on the Pi (e.g. a second drive)Path must be readable by the www-data user
SMB / CIFSA NAS or Windows share on your networkRequires sudo apt install smbclient
SFTPAnother SSH serverUseful for accessing a remote server's files
WebDAVAnother WebDAV serverCan also mount another Nextcloud instance

Performance Tips

⚡ Use Redis for file locking
Install Redis: sudo apt install redis-server php-redis. Add to config.php: 'memcache.locking' => '\OC\Memcache\Redis' and 'redis' => ['host' => 'localhost', 'port' => 6379]. This moves file lock handling out of the database, dramatically improving performance with multiple clients.
🗜 Enable preview generation
Install ImageMagick for better image previews: sudo apt install imagemagick. Then run sudo -u www-data php /var/www/nextcloud/occ preview:generate-all to pre-generate thumbnails for your existing files. Schedule it as a cron job for ongoing generation.
🗃 Regular database maintenance
Run these occ commands monthly to keep the database healthy:
sudo -u www-data php occ db:add-missing-indices
sudo -u www-data php occ db:convert-filecache-bigint
sudo -u www-data php occ maintenance:repair
📦 Limit app count
Every enabled app adds overhead. Disable apps you don't use in Apps → Your Apps. The biggest resource consumers are Talk (video calls), Recognize (AI photo tagging), and Full Text Search — disable them if you don't need them.

Keeping Nextcloud Updated

Nextcloud releases updates frequently. Never use apt to update it — always use the built-in updater:

Go to Administration Settings → Overview. When an update is available you will see a notification. Click Open Updater and follow the steps — it downloads the new version, backs up your old installation, and runs the upgrade automatically.

Alternatively, use the command line updater:

pi@raspberrypi:~$ sudo -u www-data php /var/www/nextcloud/updater/updater.phar

After any update, run the post-upgrade steps:

pi@raspberrypi:~$ sudo -u www-data php /var/www/nextcloud/occ upgrade
pi@raspberrypi:~$ sudo -u www-data php /var/www/nextcloud/occ db:add-missing-indices
pi@raspberrypi:~$ sudo -u www-data php /var/www/nextcloud/occ maintenance:mode --off

Troubleshooting Common Problems

⚠ 504 Gateway Timeout when uploading large files
The PHP execution time limit is being hit. Confirm max_execution_time = 3600 and max_input_time = 3600 are set in php.ini and that you restarted Apache after editing. Also check Apache's timeout: add Timeout 3600 to your virtual host config. For very large files (50 GB+), use the desktop client rather than the browser — it uploads in chunks and handles network interruptions gracefully.
⚠ "Access through untrusted domain" error
The URL you are accessing is not listed in trusted_domains in config.php. Add it as shown in Step 8. If you are accessing via the local IP (192.168.1.xx) and that is not in the list, add it. Changes take effect immediately — no Apache restart needed.
⚠ Files not syncing — desktop client shows errors
(1) Check Nextcloud's log: Administration Settings → Logging. (2) Check that the www-data user owns the data directory: ls -la /media/mediadrive/nextcloud-data. (3) If the error mentions "file locking", Redis may not be running: sudo systemctl status redis-server. (4) Run the filesystem scan to force Nextcloud to re-index: sudo -u www-data php /var/www/nextcloud/occ files:scan --all.
⚠ Calendar / Contacts not syncing to phone
Verify the CalDAV/CardDAV URL is correct — it must include your username and end in a trailing slash. On iOS, the most common cause is a self-signed certificate; make sure Let's Encrypt is configured and the certificate is valid. On Android with DAVx⁵, check the account settings and force a manual sync. Also confirm the Calendar or Contacts app is enabled in Nextcloud under Apps.
⚠ Nextcloud is very slow on the Pi
In order of impact: (1) Move from SD card to USB SSD if you haven't already — this alone makes the biggest difference. (2) Enable APCu memory caching in config.php ('memcache.local' => '\OC\Memcache\APCu'). (3) Enable Redis for file locking. (4) Disable unused apps, especially Talk and Recognize. (5) Check htop — if PHP processes are pegged, reduce MaxRequestWorkers in Apache's mpm config to avoid memory pressure.
⚠ "Your installation has no default phone region set" warning
Add 'default_phone_region' => 'GB' (or your ISO country code) to /var/www/nextcloud/config/config.php inside the config array. Save the file — the warning disappears immediately on next page load.
⚠ Updater fails mid-way — Nextcloud is in maintenance mode
Take maintenance mode off manually: sudo -u www-data php /var/www/nextcloud/occ maintenance:mode --off. Check the updater log at /var/www/nextcloud/data/updater.log for the cause. Most commonly: insufficient disk space (check with df -h) or a file permissions problem (sudo chown -R www-data:www-data /var/www/nextcloud).
⚠ External storage mount shows "Not available" or red dot
The www-data user cannot access the path. For a local folder, check ownership: sudo chown www-data:www-data /path/to/folder. For SMB shares, verify the smbclient package is installed and the credentials are correct. For network shares that may be temporarily offline, the red dot is expected — it clears when the share becomes available again.

Quick Reference

TaskCommand / Location
Nextcloud config file/var/www/nextcloud/config/config.php
Nextcloud data directory/media/mediadrive/nextcloud-data/
occ — admin command line toolsudo -u www-data php /var/www/nextcloud/occ
Scan all filessudo -u www-data php occ files:scan --all
Run DB repairssudo -u www-data php occ db:add-missing-indices
Enable maintenance modesudo -u www-data php occ maintenance:mode --on
Disable maintenance modesudo -u www-data php occ maintenance:mode --off
List installed appssudo -u www-data php occ app:list
Enable an appsudo -u www-data php occ app:enable appname
Disable an appsudo -u www-data php occ app:disable appname
View Nextcloud logsAdmin Settings → Logging, or tail -f /var/www/nextcloud/data/nextcloud.log
Restart Apachesudo systemctl restart apache2
Restart Redissudo systemctl restart redis-server
PHP config file/etc/php/8.2/apache2/php.ini
CalDAV URLhttps://cloud.yourdomain.com/remote.php/dav/
Admin panelhttps://cloud.yourdomain.com/settings/admin