Self-hosted • Privacy-first • No tracking
Home / Homelab / Nextcloud on Raspberry Pi: The Complete Docker Compose Guide for 2026
Homelab #self-hosted#homelab#docker-compose#nextcloud#raspberry-pi ⏱ 15 min • 👁 3 • Sep 04, 2026

Nextcloud on Raspberry Pi: The Complete Docker Compose Guide for 2026

Install Nextcloud 34 on Raspberry Pi 5 with Docker Compose. Step-by-step guide with hardening, backups, and common error fixes for a private cloud.

AdSense — Top (970x90) • Responsive
Nextcloud on Raspberry Pi: The Complete Docker Compose Guide for 2026

Introduction

Running your own cloud storage is a key step toward digital independence. Nextcloud gives you file sync, calendar, contacts, and collaborative editing, all under your control. A Raspberry Pi, especially the Pi 5 with its faster CPU and PCIe support, is an excellent low-power host for this. It is silent, costs little to run, and is powerful enough for a household or small team.

This guide walks you through a production-oriented installation of Nextcloud v34.0.3 on a Raspberry Pi using Docker Compose. We will use a stack with MariaDB and Redis for performance and reliability. You will learn how to set up the environment, configure the stack correctly, and avoid the pitfalls that commonly catch new self-hosters.

We will not stop at a basic install. The guide covers reverse proxy setup with Caddy, automated backups, and a section on optional security hardening. By the end, you will have a robust, accessible-from-anywhere cloud service that you fully own. You will also understand the why behind each configuration choice, which is crucial for maintaining your system long-term.

This is a hands-on guide. Every command is copy-paste ready for a fresh Raspberry Pi OS Lite (64-bit) system. We are using the official Nextcloud image at version v34.0.3. While we pin this version, you should always check for newer stable releases on the official Nextcloud download page before a fresh install.

Prerequisites / Hardware & Software Requirements

Before starting, ensure you have the following hardware and software. The Raspberry Pi 5 is the recommended target, but a Pi 4 (4GB or 8GB) will work for smaller setups.

Component Minimum Requirement Recommended Notes
CPU ARM Cortex-A72 (Pi 4) ARM Cortex-A76 (Pi 5) The Pi 5 significantly reduces response times for encryption and database queries.
RAM 4 GB 8 GB Nextcloud, MariaDB, and Redis together typically use 1.5-2.5 GB. More RAM helps with file preview generation.
Storage 32 GB SD card (boot) 128 GB+ NVMe SSD or USB 3.0 SSD Critical: Do not use an SD card for data storage. Use an SSD for the data directory and database. SD cards fail quickly under random I/O.
Network Wired 100 Mbps Wired 1 Gbps A wired connection is essential for consistent sync performance.
Software Raspberry Pi OS Lite (64-bit) Raspberry Pi OS Lite (64-bit) Bookworm or later. The 64-bit OS is required for full compatibility with modern ARM images.
Other Docker & Docker Compose v2 Docker Engine 27+ & Compose v2 Install via the official Docker convenience script or apt.

Initial System Setup

  1. Update your system
    sudo apt update && sudo apt upgrade -y && sudo reboot
    
  2. Install Docker (using the official script)
    curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh && sudo usermod -aG docker $USER && newgrp docker
    
    Verify the installation.
    docker --version && docker compose version
    

Step-by-Step Installation Guide

We will create a dedicated directory for the Nextcloud stack. All files and data will live in ~/nextcloud. We will use a .env file to store secrets and configuration variables, keeping our docker-compose.yml clean and portable.

Step 1: Create Project Directory and Environment File

Create the base directory and navigate into it.

mkdir -p ~/nextcloud && cd ~/nextcloud

Now, create a .env file. This file will hold all your secrets and configurable variables. Never commit this file to a Git repository as it contains your passwords.

nano .env

Paste the following content into the .env file. Replace the placeholder values with strong, unique passwords.

# Database Configuration
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud
# Generate a strong password: openssl rand -base64 32
MYSQL_PASSWORD=change_this_db_password
# Root password for MariaDB. Generate a separate one.
MYSQL_ROOT_PASSWORD=change_this_root_password

# Nextcloud Admin User (set during first web install)
NEXTCLOUD_ADMIN_USER=admin
# Generate a strong password: openssl rand -base64 32
NEXTCLOUD_ADMIN_PASSWORD=change_this_admin_password

# Host paths for persistent data - do not change unless you know what you are doing
NEXTCLOUD_DATA_DIR=./data
NEXTCLOUD_CONFIG_DIR=./config
NEXTCLOUD_APPS_DIR=./apps
DB_DATA_DIR=./db
REDIS_DATA_DIR=./redis

# Timezone for your instance
TZ=Europe/Berlin

Save and close the file (Ctrl+X, then Y, then Enter).

Step 2: Create the Docker Compose File

Create a docker-compose.yml file.

nano docker-compose.yml

Paste the complete stack configuration below. This defines three services: nextcloud, db (MariaDB), and redis.

services:
  nextcloud:
    image: nextcloud:${NEXTCLOUD_VERSION:-v34.0.3}
    container_name: nextcloud
    restart: unless-stopped
    ports:
      - "8080:80"
    depends_on:
      - db
      - redis
    environment:
      - MYSQL_HOST=db
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - REDIS_HOST=redis
      - TZ=${TZ}
    volumes:
      - ${NEXTCLOUD_CONFIG_DIR}:/var/www/html
      - ${NEXTCLOUD_DATA_DIR}:/var/www/html/data
      - ${NEXTCLOUD_APPS_DIR}:/var/www/html/custom_apps
    networks:
      - nextcloud_network

  db:
    image: mariadb:11.4
    container_name: nextcloud-db
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-file-per-table=1 --skip-innodb-read-only-compressed
    volumes:
      - ${DB_DATA_DIR}:/var/lib/mysql
    environment:
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
    networks:
      - nextcloud_network

  redis:
    image: redis:7-alpine
    container_name: nextcloud-redis
    restart: unless-stopped
    command: redis-server --requirepass ${REDIS_PASSWORD:-}
    volumes:
      - ${REDIS_DATA_DIR}:/data
    networks:
      - nextcloud_network

networks:
  nextcloud_network:
    driver: bridge

Important Note on Redis: For simplicity, the Redis password is optional. If you leave REDIS_PASSWORD empty in .env, Redis runs without a password. For a local network, this is acceptable. For internet-exposed instances, you should set a strong password here and uncomment the REDIS_PASSWORD line in the nextcloud service environment.

Step 3: Pull and Start the Containers

First, pull the images to ensure you have the latest versions locally. Then start the stack in detached mode.

cd ~/nextcloud && docker compose pull && docker compose up -d

Check the status of the containers.

docker compose ps

All three containers should have a Up status. If any container is Restarting, check the logs with docker compose logs <service_name>.

Step 4: Configure Nextcloud via Web Interface

Open your browser and navigate to http://<your_pi_ip_address>:8080. You will see the Nextcloud setup page.

  1. Enter the Username and Password you defined in the .env file as NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD.
  2. Leave the Data folder field as the default value: /var/www/html/data. This path is mapped to your host's ./data directory.
  3. Click Install.

Nextcloud will now configure the database and install the core apps. This may take a few minutes. After completion, you will be logged into your new cloud.

Step 5: Post-Installation Configuration

For optimal performance, we need to tell Nextcloud to use Redis for caching and configure the trusted domains.

Edit the Nextcloud configuration file. It is located in your host directory ~/nextcloud/config/config.php.

nano ~/nextcloud/config/config.php

Add the following lines inside the $CONFIG = array ( declaration, before the closing );.

  'memcache.local' => '\OC\Memcache\Redis',
  'memcache.distributed' => '\OC\Memcache\Redis',
  'memcache.locking' => '\OC\Memcache\Redis',
  'redis' => array(
    'host' => 'redis',
    'port' => 6379,
  ),
  'trusted_domains' => array (
    0 => 'localhost',
    1 => '<your_pi_ip_address>',
    2 => 'cloud.yourdomain.com', // Add your domain here if you have one
  ),
  'overwrite.cli.url' => 'http://<your_pi_ip_address>:8080',
  'htaccess.RewriteBase' => '/',

Replace <your_pi_ip_address> with the actual IP of your Pi. If you have a domain name, add it to the trusted_domains array.

Save the file and restart the Nextcloud container to apply the changes.

cd ~/nextcloud && docker compose restart nextcloud

Step 6: Background Jobs (Cron)

Nextcloud needs to run scheduled tasks (e.g., file scans, expiration of trash). The default is AJAX, which only runs when a user is logged in. We will switch to Cron.

Edit the docker-compose.yml file again.

nano docker-compose.yml

Add the cron service to the file. It uses the same image and volume mounts but runs a cron daemon.

  cron:
    image: nextcloud:${NEXTCLOUD_VERSION:-v34.0.3}
    container_name: nextcloud-cron
    restart: unless-stopped
    volumes:
      - ${NEXTCLOUD_CONFIG_DIR}:/var/www/html
      - ${NEXTCLOUD_DATA_DIR}:/var/www/html/data
      - ${NEXTCLOUD_APPS_DIR}:/var/www/html/custom_apps
    entrypoint: /cron.sh
    depends_on:
      - db
      - redis
    networks:
      - nextcloud_network

Apply the new configuration.

cd ~/nextcloud && docker compose up -d

Then, set the background job mode to Cron in the Nextcloud admin interface. Go to Settings > Basic settings and select Cron.

Step 7: Set Correct File Permissions

The Nextcloud container runs as www-data (user ID 33). The data and config directories on your host must be writable by this user. Run the following command on your host to set ownership. Do not use chown -R 1000:1000 without checking.

First, verify the user ID the container uses. Run docker exec -it nextcloud id and note the uid and gid (typically 33). Then, apply the correct ownership.

cd ~/nextcloud && sudo chown -R 33:33 data config apps

Step 8: Verify the Installation

Go to Settings > Administration > Overview in the Nextcloud web UI. This page will show any security or setup warnings. Address any critical warnings. A common one is the missing OPcache email, which is fine for a standard install.

Advanced Setup / Optimization

Reverse Proxy with Caddy and SSL

Exposing your Nextcloud directly via port 8080 is not recommended. Use a reverse proxy to handle HTTPS and standard ports. Caddy is a simple choice as it automates SSL certificates.

  1. Stop the Nextcloud container and remove its port mapping.
    cd ~/nextcloud && docker compose stop nextcloud
    
  2. Edit docker-compose.yml and remove the ports: section from the nextcloud service.
  3. Create a new directory for the proxy and a Caddyfile.
    mkdir -p ~/caddy && cd ~/caddy && nano Caddyfile
    
  4. Add the following configuration to the Caddyfile. Replace cloud.yourdomain.com with your actual domain.
    cloud.yourdomain.com {
        reverse_proxy nextcloud:80
    }
    
  5. Create a docker-compose.yml for Caddy.
    nano docker-compose.yml
    
    services:
      caddy:
        image: caddy:2-alpine
        container_name: caddy
        restart: unless-stopped
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - ./Caddyfile:/etc/caddy/Caddyfile
          - caddy_data:/data
          - caddy_config:/config
        networks:
          - nextcloud_network
    
    volumes:
      caddy_data:
      caddy_config:
    
    networks:
      nextcloud_network:
        external: true
    
  6. Connect your Nextcloud stack's network to Caddy. First, check the network name of your Nextcloud stack.
    docker network ls
    
    You will see a network named nextcloud_nextcloud_network. In the Caddy compose file, we referenced it as external: true. Now, start the Caddy container.
    cd ~/caddy && docker compose up -d
    
  7. Update the trusted_domains and overwrite.cli.url in config.php to use your domain with https://.

Automated Backups

Back up the data, config, and apps directories, and the database. A simple script can handle this. Create a script in your home directory.

nano ~/backup_nextcloud.sh

Add the following content. Adjust the paths and database credentials.

#!/bin/bash

# Set variables
BACKUP_DIR=~/backups
NEXTCLOUD_DIR=~/nextcloud
DATE=$(date +%Y-%m-%d)

# Create backup directory
mkdir -p $BACKUP_DIR/$DATE

# Backup Nextcloud files (config, data, apps)
sudo rsync -aAXv $NEXTCLOUD_DIR/config $BACKUP_DIR/$DATE/
sudo rsync -aAXv $NEXTCLOUD_DIR/data $BACKUP_DIR/$DATE/
sudo rsync -aAXv $NEXTCLOUD_DIR/apps $BACKUP_DIR/$DATE/

# Backup the database from the running container
docker exec nextcloud-db sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > $BACKUP_DIR/$DATE/db.sql

# Compress the backup
tar -czf $BACKUP_DIR/nextcloud-backup-$DATE.tar.gz -C $BACKUP_DIR $DATE

# Remove the uncompressed directory
rm -rf $BACKUP_DIR/$DATE

# Keep only the last 7 days of backups
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete

Make the script executable and run it.

chmod +x ~/backup_nextcloud.sh && sudo ~/backup_nextcloud.sh

Add this script to your crontab to run daily. crontab -e and add 0 2 * * * /home/pi/backup_nextcloud.sh.

Optional Hardening

Warning: The following settings are advanced and can break your container if applied incorrectly. They are specific to security-conscious deployments and may require further adjustments based on your exact setup. Do not copy them blindly into your docker-compose.yml without understanding the implications.

You can add the following to the nextcloud service to reduce its attack surface. These are not defaults because they can interfere with some apps and update processes.

    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETUID
      - SETGID
      - DAC_OVERRIDE
    read_only: true
    tmpfs:
      - /tmp
  • cap_drop: ALL removes all Linux capabilities. We then add back only the minimal ones Nextcloud needs to operate (CHOWN, SETUID, SETGID, DAC_OVERRIDE).
  • read_only: true makes the root filesystem read-only. Nextcloud needs to write to /tmp and its data volumes. We mount tmpfs for /tmp to allow temporary writes. The data and config directories are already writable via volumes.

Testing is mandatory. After adding these, restart the container and thoroughly test file uploads, app installation, and the web interface.

Troubleshooting Table

Common Error Cause Solution
docker compose up fails with Error starting userland proxy: listen tcp4 0.0.0.0:8080: bind: address already in use Port 8080 is already taken by another service on your host. Change the host port in docker-compose.yml (e.g., 8081:80). Run sudo lsof -i :8080 to identify the process using it.
Nextcloud web UI shows Internal Server Error after install Incorrect file permissions on config/ or data/ directories, or a misconfiguration in config.php. Check the logs: docker compose logs nextcloud. Ensure permissions are correct: sudo chown -R 33:33 ~/nextcloud/config ~/nextcloud/data. Review config.php for syntax errors.
Nextcloud cannot connect to the database Wrong credentials or the db service is not running. Verify the db container is up: docker compose ps db. Check the credentials in .env match exactly. Check the logs: docker compose logs db.
Uploads fail with Error while copying file to cache The data directory is full or has incorrect ownership. Check disk space: df -h. Verify permissions: sudo chown -R 33:33 ~/nextcloud/data.
Redis connection error in Nextcloud logs The Redis container is not running or the password is wrong. Check docker compose ps redis. If you set a password in the redis service, you must add it to the 'redis' array in config.php.
cron service is not running or jobs are stuck The cron container exited or the Cron mode in Nextcloud settings is not set to Cron. Check the cron container logs: docker compose logs cron. Go to Settings > Basic settings and set background job mode to Cron.

Conclusion

You have successfully deployed Nextcloud v34.0.3 on your Raspberry Pi using Docker Compose. You have a functional private cloud with a database backend, Redis caching, and scheduled background jobs. You have also configured a reverse proxy with automatic SSL and set up a backup routine.

The system is now more reliable and maintainable than a simple manual install. By using Docker, you have isolated the application and its dependencies. The use of environment variables and a Compose file means you can rebuild the entire stack on new hardware in minutes.

Remember that self-hosting is a continuous process. Regularly check for updates to the Nextcloud image and the underlying OS. Monitor your disk usage and logs. The skills you have applied here—understanding services, networking, and security basics—are foundational for any other self-hosted service you might want to run in the future.

FAQ

1. Is a Raspberry Pi 4 sufficient for Nextcloud? Yes, a Raspberry Pi 4 with 4GB or 8GB RAM is sufficient for a personal cloud with a few users. Expect slower response times for preview generation and encryption compared to a Pi 5. For a more responsive experience, especially with multiple concurrent users, the Pi 5 is strongly recommended.

2. How do I update Nextcloud to a new major version? To update, pull the new image and recreate the containers. First, back up your data and database. Then modify the NEXTCLOUD_VERSION variable in your .env file (or change the tag in docker-compose.yml). Run docker compose pull && docker compose up -d. After the containers start, go to the web UI and follow the upgrade wizard. Always check the official Nextcloud changelog for upgrade paths from your version.

3. Why is Redis necessary? Redis is used for caching file locks, transaction file locking, and distributed caching. It significantly reduces database load and improves performance for concurrent operations. Without it, you will see high database CPU usage and slower response times, especially when multiple clients sync files simultaneously.

4. Can I access my Nextcloud outside my home network? Yes, you can. The recommended way is to set up a reverse proxy (as shown in this guide) and forward ports 80 and 443 on your router to your Pi. For dynamic IP addresses, use a Dynamic DNS (DDNS) service. Never expose the raw port 8080 directly to the internet without a proxy and SSL.

5. How do I migrate this setup to a new Raspberry Pi? Migration is straightforward. Install Docker on the new Pi. Copy the entire ~/nextcloud directory (including the .env, docker-compose.yml, config, data, and apps folders) to the new Pi. Then run docker compose up -d. If the database files are copied correctly, your data will be intact. Ensure the user IDs for file ownership match (usually 33).

AdSense — In-article (responsive)

Related Guides