Install Nextcloud on Raspberry Pi

Running Nextcloud on a Raspberry Pi

Nextcloud runs on a Raspberry Pi, but the experience depends heavily on your hardware choices. A Pi 4 with 4 GB RAM and a USB SSD handles 1-3 users well. A Pi 5 with 8 GB and NVMe is genuinely comfortable for a small family. Running Nextcloud on an SD card or a Pi with 1-2 GB RAM leads to frustration — slow page loads, failed file syncs, and database corruption.

This guide covers the Pi-specific setup: ARM64 Docker installation, SSD boot, memory tuning for constrained hardware, and realistic expectations for what a Pi can handle.

For Nextcloud’s full feature guide and troubleshooting, see the main Nextcloud guide.

Prerequisites

  • Raspberry Pi 4 (4 GB) or Pi 5 (4-8 GB). Pi 3B+ works but is marginal.
  • Raspberry Pi OS Lite (64-bit / ARM64) — not the 32-bit version
  • USB SSD or NVMe (strongly recommended — SD cards are too slow for database writes)
  • Docker and Docker Compose installed (guide)
  • 2 GB of free RAM
  • 10 GB of free disk space for the application, plus storage for files
  • SSH access enabled

Platform Setup

Install Docker

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

Log out and back in, then verify:

docker run --rm hello-world
uname -m   # Should show: aarch64

SSD Storage (Critical for Performance)

Running Nextcloud’s PostgreSQL database on an SD card causes write amplification, slow queries, and eventual card failure. Move Docker’s data root to SSD:

Option A: Boot entirely from SSD (recommended). Flash Raspberry Pi OS directly to the SSD and boot from USB/NVMe. No SD card needed on Pi 4 (with updated bootloader) or Pi 5.

Option B: Keep boot on SD, move Docker data to SSD.

# Mount SSD
sudo mkdir -p /mnt/ssd
sudo mount /dev/sda1 /mnt/ssd   # adjust device as needed
echo "/dev/sda1 /mnt/ssd ext4 defaults,noatime 0 2" | sudo tee -a /etc/fstab

# Move Docker data root to SSD
sudo systemctl stop docker
sudo mkdir -p /mnt/ssd/docker
sudo rsync -aP /var/lib/docker/ /mnt/ssd/docker/

# Configure Docker to use SSD
sudo tee /etc/docker/daemon.json << 'EOF'
{
  "data-root": "/mnt/ssd/docker",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "5m",
    "max-file": "2"
  }
}
EOF

sudo systemctl start docker

Add Swap

Even with 4 GB RAM, swap is important for Nextcloud on a Pi. PostgreSQL, Redis, and the PHP application compete for memory:

sudo fallocate -l 2G /mnt/ssd/swapfile   # Put swap on SSD, not SD card
sudo chmod 600 /mnt/ssd/swapfile
sudo mkswap /mnt/ssd/swapfile
sudo swapon /mnt/ssd/swapfile
echo '/mnt/ssd/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Docker Compose Configuration

Create the project directory:

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

Create docker-compose.yml:

services:
  db:
    image: postgres:17-alpine
    container_name: nextcloud-db
    restart: unless-stopped
    volumes:
      - nextcloud-db:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: nextcloud
      POSTGRES_USER: nextcloud
      # CHANGE THIS — use a strong password
      POSTGRES_PASSWORD: "change-this-db-password"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U nextcloud"]
      interval: 10s
      timeout: 5s
      retries: 5
    # Pi-specific: limit PostgreSQL memory usage
    deploy:
      resources:
        limits:
          memory: 256M

  redis:
    image: redis:7-alpine
    container_name: nextcloud-redis
    restart: unless-stopped
    # Limit Redis to 64MB — enough for session and file lock caching
    command: redis-server --maxmemory 64mb --maxmemory-policy allkeys-lru
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  app:
    image: nextcloud:33.0.0-apache
    container_name: nextcloud
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - nextcloud-html:/var/www/html
    environment:
      # Database
      POSTGRES_HOST: db
      POSTGRES_DB: nextcloud
      POSTGRES_USER: nextcloud
      POSTGRES_PASSWORD: "change-this-db-password"
      # Cache
      REDIS_HOST: redis
      # Admin account (first run only)
      NEXTCLOUD_ADMIN_USER: admin
      NEXTCLOUD_ADMIN_PASSWORD: "change-this-admin-password"
      # Trusted domains — replace with your Pi's IP
      NEXTCLOUD_TRUSTED_DOMAINS: "localhost your-pi-ip"
      # PHP tuning — conservative for Pi hardware
      PHP_MEMORY_LIMIT: "384M"
      PHP_UPLOAD_LIMIT: "4G"
      APACHE_BODY_LIMIT: "0"
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy

  cron:
    image: nextcloud:33.0.0-apache
    container_name: nextcloud-cron
    restart: unless-stopped
    volumes:
      - nextcloud-html:/var/www/html
    entrypoint: /cron.sh
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy

volumes:
  nextcloud-db:
  nextcloud-html:

Start the stack:

docker compose up -d

First startup takes 2-4 minutes on a Pi (slower than x86 due to ARM’s lower single-thread performance).

Initial Setup

  1. Open http://your-pi-ip:8080 in a browser
  2. The admin account is created from the environment variables
  3. Install only the apps you need — each app adds memory and CPU overhead on constrained Pi hardware
  4. Go to Administration > Basic settings and confirm background jobs is set to Cron

Raspberry Pi Optimization

Memory Monitoring

With Nextcloud, PostgreSQL, Redis, and the cron container all running, memory usage on a Pi 4 (4 GB) looks approximately like:

ComponentApproximate RAM
Nextcloud (Apache + PHP)200-400 MB
PostgreSQL100-200 MB
Redis30-64 MB
Cron container100-200 MB (shares image)
OS + Docker300-400 MB
Total730 MB - 1.3 GB

Monitor with:

free -m
docker stats --no-stream

On a 4 GB Pi, you have ~2.7-3.3 GB free for file operations and other containers. On a 2 GB Pi, this is tight — consider skipping Collabora/OnlyOffice and limiting concurrent users to 1.

Disable Unnecessary Nextcloud Features

Reduce CPU and memory usage by disabling features you do not need:

# Disable apps that consume resources
docker compose exec -u www-data app php occ app:disable activity
docker compose exec -u www-data app php occ app:disable weather_status
docker compose exec -u www-data app php occ app:disable dashboard

Reduce Preview Generation Load

Image previews are CPU-intensive on ARM. Limit preview sizes:

docker compose exec -u www-data app php occ config:system:set preview_max_x --value="1024"
docker compose exec -u www-data app php occ config:system:set preview_max_y --value="1024"
docker compose exec -u www-data app php occ config:system:set jpeg_quality --value="60"

SD Card Wear (If Not Using SSD)

If you must run on an SD card, reduce write frequency:

# Increase cron interval to reduce database writes
docker compose exec -u www-data app php occ config:system:set maintenance_window_start --value="1" --type=integer

Use a high-endurance SD card (Samsung PRO Endurance, SanDisk MAX Endurance). Standard SD cards can fail within months under database write load.

Reverse Proxy

For HTTPS access, use Nginx Proxy Manager or Caddy on the same Pi or a separate device:

  1. Point your domain at the Pi’s IP
  2. Proxy to http://nextcloud:80 (or pi-ip:8080)
  3. Enable SSL with Let’s Encrypt
  4. Configure Nextcloud trusted proxies:
docker compose exec -u www-data app php occ config:system:set overwriteprotocol --value="https"
docker compose exec -u www-data app php occ config:system:set trusted_proxies 0 --value="172.16.0.0/12"

See Reverse Proxy Setup.

Backup

# Database
docker compose exec nextcloud-db pg_dump -U nextcloud nextcloud > nextcloud-db-$(date +%Y%m%d).sql

# Application data
docker compose stop app cron
docker run --rm -v nextcloud-html:/data -v $(pwd):/backup alpine tar czf /backup/nextcloud-data-$(date +%Y%m%d).tar.gz /data
docker compose start app cron

On a Pi, back up to a USB drive or network storage — not to the same SD card or SSD that Nextcloud runs on. See Backup Strategy.

Troubleshooting

Very slow first page load after startup

The first page load on a Pi triggers PHP OPcache compilation. This can take 30-60 seconds. Subsequent loads are much faster. If every page load is slow, check that Redis is connected (Admin > Overview) and OPcache is active.

Out of memory — containers killed by OOM

Check dmesg | grep -i oom. If PostgreSQL or Nextcloud is being OOM-killed:

  1. Reduce PHP_MEMORY_LIMIT to 256M
  2. Add or increase swap
  3. Remove unnecessary containers from the Pi
  4. Upgrade to a Pi with more RAM

Wrong architecture image pulled

If Docker pulls an amd64 image instead of ARM64:

docker inspect nextcloud | grep Architecture
# Should show: arm64

Force the platform in Compose:

    platform: linux/arm64

File sync errors with desktop/mobile clients

Nextcloud’s sync client is sensitive to server response time. On a Pi, large file scans can cause timeouts. Increase the client’s timeout setting and avoid syncing folders with thousands of files.

SD card corruption

Symptoms: random read errors, containers failing to start, database errors. The only fix is to flash a new SD card from your backup. Migrate to SSD to prevent recurrence.

Resource Requirements

  • RAM: ~1 GB minimum (Nextcloud + PostgreSQL + Redis + cron). 4 GB Pi recommended.
  • CPU: Medium. Page loads are noticeably slower than x86. Preview generation is CPU-bound.
  • Disk: 1 GB for the application. SSD strongly recommended for database performance.
  • Power: ~5-7W for Pi 4 with SSD, ~8-10W for Pi 5 with NVMe

Realistic Expectations

Pi ModelUsersExperience
Pi 3B+ (1 GB)1Barely usable. Constant swapping. File sync works but UI is painful.
Pi 4 (2 GB)1Functional but tight. No Collabora/OnlyOffice.
Pi 4 (4 GB)1-3Good for file sync and basic apps. Preview generation is slow.
Pi 4 (8 GB)2-5Comfortable. Can run Collabora with modest usage.
Pi 5 (8 GB)3-8Best Pi experience. NVMe support. Handles concurrent users well.

For more than 5 regular users, consider an Intel N100 mini PC — 3-4x the single-thread performance at similar power consumption.

Comments