Self-Hosting Your Cloud: Nextcloud Installation Guide

Self-Hosting Your Cloud: Nextcloud Installation Guide

Self-Hosting Your Cloud: Nextcloud Installation Guide

By Alex Torres | February 6, 2026 | Self-Hosting & Cloud

A complete Nextcloud installation guide covering Docker Compose deployment with MariaDB and Redis, reverse proxy configuration, essential apps, sync clients (see our Docker beginners guide) (see our Ansible automation), and performance tuning for your own self-hosted cloud storage.

Why I Ditched Google Drive for Nextcloud

I spent years trusting Google Drive and Dropbox with my files. Photos, tax documents, project backups, personal notes — everything lived on someone else’s server. Then one morning I woke up to a news story about another cloud provider scanning user files for “policy violations,” and something clicked. I did not want a corporation deciding what I could store, who could see it, or how long I could keep it.

That realization sent me down the self-hosted cloud rabbit hole, and Nextcloud was the clear winner. It has been running on my home server for over a year now, and I genuinely cannot imagine going back. In this Nextcloud installation guide, I will walk you through the entire setup process so you can take back control of your data too.

Why Self-Host Your Cloud Storage?

Before we get into the technical Nextcloud setup, let me make the case for self-hosting in general. There are three pillars that convinced me.

Privacy and Data Ownership

When your files sit on Google’s or Microsoft’s servers, those companies can scan, analyze, and use your data according to their terms of service. With a self-hosted cloud, your files live on hardware you own. Nobody mines your documents for advertising data. Nobody trains an AI model on your family photos. The data is yours, full stop.

Control and Flexibility

Commercial cloud services decide which features you get, when they change the interface, and what integrations are allowed. With Nextcloud, you choose your storage backend, your authentication method, your apps, and your update schedule. If you do not like something, you can change it or replace it entirely.

Cost Over Time

Google One charges $30 per year for 200 GB, or $100 per year for 2 TB. That sounds reasonable until you do the math over five or ten years. A decent 4 TB hard drive costs around $80 and lasts for years. The upfront investment in a small server pays for itself quickly, especially if you need multiple terabytes of storage. My entire Nextcloud setup cost less than two years of a 2 TB cloud subscription, and I now have 8 TB of usable space.

What Nextcloud Actually Offers

If you are picturing a basic file sync tool, think bigger. Nextcloud has evolved into a full-featured collaboration platform. Here is what you get out of the box or through its app ecosystem:

  • File sync and share — the core feature, with versioning, trash bin, and granular sharing controls.
  • Calendar and contacts — CalDAV and CardDAV support, syncs natively with phones and desktop clients.
  • Nextcloud Talk — video calls, screen sharing, and chat, essentially a self-hosted alternative to Zoom and Slack.
  • Nextcloud Office — collaborative document editing powered by Collabora or ONLYOFFICE.
  • Photos — automatic photo and video management with face recognition, timeline view, and album organization.
  • Notes and tasks — simple but effective productivity tools that sync across devices.
  • Email client — connect your existing email accounts into a unified inbox.
  • Deck — Kanban-style project management boards.

It is genuinely a Google Drive alternative that can replace most of the Google Workspace suite if you set it up right.

Prerequisites

Before we start the Nextcloud Docker deployment, make sure you have the following ready:

  • A Linux server (physical or virtual) with at least 2 GB of RAM and 2 CPU cores. Ubuntu Server 22.04 or 24.04 works perfectly.
  • Docker and Docker Compose installed. If you do not have them yet, install Docker from the official repository:
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
  • A domain name pointed at your server (required for HTTPS). Something like cloud.yourdomain.com works well.
  • Ports 80 and 443 open on your firewall and forwarded through your router if hosting from home.
  • A basic understanding of the command line. If you have made it this far, you are probably fine.

Step 1: Set Up the Project Directory

I like to keep all my Docker services organized under a common directory. Let us create the Nextcloud project folder and the necessary subdirectories for persistent data.

mkdir -p ~/nextcloud/{db,redis,html,config,data}
cd ~/nextcloud

The db directory will hold MariaDB data, redis stores the cache, and the html, config, and data directories hold Nextcloud’s application files, configuration, and user files respectively.

Step 2: Create the Docker Compose File

This is the heart of the Nextcloud setup. We are going to deploy three containers: Nextcloud itself, MariaDB as the database backend (much faster than the default SQLite), and Redis for caching. Create a file called docker-compose.yml in your ~/nextcloud directory:

version: "3.8"

services:
  db:
    image: mariadb:11
    container_name: nextcloud-db
    restart: always
    command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
    volumes:
      - ./db:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: ChangeMeRootPass2026
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
      MYSQL_PASSWORD: ChangeMeDbPass2026
    networks:
      - nextcloud-net

  redis:
    image: redis:7-alpine
    container_name: nextcloud-redis
    restart: always
    command: redis-server --requirepass ChangeMeRedisPass2026
    volumes:
      - ./redis:/data
    networks:
      - nextcloud-net

  app:
    image: nextcloud:29-apache
    container_name: nextcloud-app
    restart: always
    ports:
      - "8080:80"
    depends_on:
      - db
      - redis
    volumes:
      - ./html:/var/www/html
      - ./config:/var/www/html/config
      - ./data:/var/www/html/data
    environment:
      MYSQL_HOST: db
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
      MYSQL_PASSWORD: ChangeMeDbPass2026
      REDIS_HOST: redis
      REDIS_HOST_PASSWORD: ChangeMeRedisPass2026
      NEXTCLOUD_ADMIN_USER: admin
      NEXTCLOUD_ADMIN_PASSWORD: ChangeMeAdminPass2026
      NEXTCLOUD_TRUSTED_DOMAINS: cloud.yourdomain.com
      OVERWRITEPROTOCOL: https
      OVERWRITECLIURL: https://cloud.yourdomain.com
      PHP_UPLOAD_LIMIT: 16G
      PHP_MEMORY_LIMIT: 512M
    networks:
      - nextcloud-net

  cron:
    image: nextcloud:29-apache
    container_name: nextcloud-cron
    restart: always
    depends_on:
      - app
    volumes:
      - ./html:/var/www/html
      - ./config:/var/www/html/config
      - ./data:/var/www/html/data
    entrypoint: /cron.sh
    networks:
      - nextcloud-net

networks:
  nextcloud-net:
    driver: bridge

A few things to note about this compose file:

  • Change every password. I cannot stress this enough. Replace all instances of ChangeMe... with strong, unique passwords. Use a password manager to generate them.
  • MariaDB transaction isolation is set to READ-COMMITTED because Nextcloud specifically requires it. The binary logging format is also set to ROW for compatibility.
  • Redis provides server-side caching that dramatically improves Nextcloud performance, especially with multiple users.
  • The cron container runs Nextcloud’s background jobs on schedule. This is far more reliable than the default AJAX-based cron and is the officially recommended approach.
  • PHP_UPLOAD_LIMIT is set to 16 GB so you can upload large files without hitting arbitrary limits.
  • OVERWRITEPROTOCOL is set to https because we will put a reverse proxy in front of this. The app container itself listens on HTTP port 8080, but all external traffic will be HTTPS.

Step 3: Launch the Stack

With the compose file in place, bring everything up:

docker compose up -d

Watch the logs to make sure everything starts cleanly:

docker compose logs -f

The first startup takes a minute or two as Nextcloud initializes the database and creates the admin account. You will see MariaDB go through its initialization sequence, then Nextcloud will begin its installation. When you see Apache reporting that it is listening on port 80 inside the container, you are good to go. Press Ctrl+C to exit the log viewer.

At this point, you can already access Nextcloud at http://your-server-ip:8080 from your local network. But do not start using it yet — we need HTTPS first.

Step 4: Set Up a Reverse Proxy for HTTPS

Running Nextcloud over plain HTTP is a security risk and will trigger warnings throughout the interface. You need a reverse proxy that handles TLS termination. I will briefly cover the two most popular options.

Option A: Caddy (My Recommendation)

Caddy is the easiest reverse proxy to configure because it handles Let’s Encrypt certificates automatically. Create a Caddyfile in a separate directory or add Caddy to your existing infrastructure:

cloud.yourdomain.com {
    reverse_proxy localhost:8080

    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
        Referrer-Policy "strict-origin-when-cross-origin"
    }
}

That is the entire configuration. Caddy will automatically obtain and renew a Let’s Encrypt certificate for your domain. If you are new to reverse proxies, this is the path of least resistance.

Option B: Nginx

If you already run Nginx, add a server block like this:

server {
    listen 443 ssl http2;
    server_name cloud.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/cloud.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/cloud.yourdomain.com/privkey.pem;

    client_max_body_size 16G;
    fastcgi_buffers 64 4K;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_max_temp_file_size 16384m;
    }

    location /.well-known/carddav {
        return 301 $scheme://$host/remote.php/dav;
    }

    location /.well-known/caldav {
        return 301 $scheme://$host/remote.php/dav;
    }
}

server {
    listen 80;
    server_name cloud.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

With Nginx, you will need to obtain certificates separately using Certbot:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d cloud.yourdomain.com

Note the client_max_body_size 16G directive. Without it, Nginx will reject large file uploads regardless of what Nextcloud allows.

Step 5: Initial Configuration and Security Hardening

Open your browser and navigate to https://cloud.yourdomain.com. You should see the Nextcloud login page. Sign in with the admin credentials you set in the compose file.

Before you do anything else, head to Administration Settings and review the Security & setup warnings section. Nextcloud will tell you if anything needs attention. Common items include:

  1. Background jobs — make sure this is set to “Cron” since we deployed a dedicated cron container.
  2. Email server — configure outgoing email so Nextcloud can send notifications and password reset links. An SMTP relay like Mailgun or your ISP’s SMTP server works fine.
  3. Default phone region — set this under Basic settings to avoid a warning. Add the following to your config.php if it was not set automatically:
'default_phone_region' => 'US',

While you are in the config, verify that Redis caching is active. Open ./config/config.php on your host and confirm these lines exist (they should have been added automatically via the environment variables):

'memcache.distributed' => '\\OC\\Memcache\\Redis',
'memcache.locking' => '\\OC\\Memcache\\Redis',
'redis' => array (
  'host' => 'redis',
  'password' => 'ChangeMeRedisPass2026',
  'port' => 6379,
),

If they are missing, add them manually. Also add local memory caching for the best performance:

'memcache.local' => '\\OC\\Memcache\\APCu',

Step 6: Essential Apps to Install

Nextcloud’s app store is packed with useful additions. Head to your profile icon in the top right, then Apps. Here are the ones I consider essential for turning Nextcloud into a true Google Drive alternative:

  • Calendar — full CalDAV calendar with shared calendars, invitations, and recurring events. Syncs beautifully with iOS, Android, and Thunderbird.
  • Contacts — CardDAV address book. Once you set it up, your phone contacts sync to your own server instead of Google’s.
  • Notes — clean, Markdown-based note-taking app. Pairs with the Nextcloud Notes mobile app for on-the-go access.
  • Tasks — integrates with Calendar for task management with due dates and priorities.
  • Nextcloud Office — install either the Collabora Online or ONLYOFFICE connector for in-browser document, spreadsheet, and presentation editing.
  • Photos — automatic timeline organization, face recognition (via the Recognize app), and smart album creation.
  • Recognize — AI-powered image tagging and face recognition that runs entirely on your server. No cloud API calls.
  • Deck — Kanban boards for project management. I use it to track home lab projects and personal goals.
  • Two-Factor TOTP — adds time-based one-time password support for an extra layer of login security. Enable this immediately for your admin account.
  • Suspicious Login Detection — uses machine learning to detect unusual login patterns and alert you.

Do not go overboard installing apps you will never use. Each one consumes resources and adds maintenance overhead. Start with what you need and expand from there.

Step 7: Set Up Sync Clients

A self-hosted storage solution is only useful if your files are accessible everywhere. Nextcloud has sync clients for every major platform.

Desktop Clients

Download the Nextcloud desktop client from nextcloud.com/install for Windows, macOS (see our Pi-hole on your network), or Linux. On Ubuntu, you can install it from the official PPA:

sudo add-apt-repository ppa:nextcloud-devs/client
sudo apt update
sudo apt install nextcloud-desktop

During setup, enter your server URL (https://cloud.yourdomain.com), authenticate through the browser, and choose which folders to sync. I recommend selective sync rather than syncing everything — keep large media archives as server-only and sync active project folders to your workstation.

Mobile Clients

The Nextcloud mobile app is available on both the Google Play Store and Apple App Store. The Android app is also available on F-Droid for those who avoid the Play Store.

One feature I love is automatic photo upload. Configure the mobile app to automatically upload photos and videos to your Nextcloud instance as soon as you take them. It works just like Google Photos backup, except the photos land on your own server. You can set it to upload only on Wi-Fi to avoid burning through mobile data.

For calendar and contact sync on Android, install DAVx5 from the Play Store or F-Droid. It bridges Nextcloud’s CalDAV and CardDAV services with Android’s native calendar and contacts apps. On iOS, you can add CalDAV and CardDAV accounts directly through Settings without any additional app.

Step 8: Performance Tuning

Out of the box, Nextcloud is functional but not optimized. Here are the tweaks that made the biggest difference in my setup.

Enable APCu for Local Caching

We already added Redis for distributed caching and locking, but APCu handles local (single-server) caching more efficiently. Make sure 'memcache.local' => '\\OC\\Memcache\\APCu' is in your config.php as mentioned earlier.

Increase PHP Memory and OPcache Settings

Create a custom PHP configuration file that will be loaded by the container. Place it in ./config/php.ini or mount it into the container at /usr/local/etc/php/conf.d/custom.ini:

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

To mount this, add the following line to the volumes section of both the app and cron services in your compose file:

- ./config/php.ini:/usr/local/etc/php/conf.d/zzz-custom.ini:ro

Database Optimization

MariaDB benefits from tuning as well. Create a custom MariaDB config at ./db-config/custom.cnf:

[mysqld]
innodb_buffer_pool_size = 512M
innodb_io_capacity = 4000
innodb_read_io_threads = 8
innodb_write_io_threads = 8

Mount it in the db service:

- ./db-config/custom.cnf:/etc/mysql/conf.d/custom.cnf:ro

Adjust innodb_buffer_pool_size based on your available RAM. A good rule of thumb is to set it to about 50-70% of the RAM you can dedicate to the database. On a server with 4 GB of total RAM shared with Nextcloud, 512 MB is a reasonable starting point.

Preview Generation

Nextcloud generates image previews on the fly, which can be slow for large photo libraries. Install the Preview Generator app, then run the initial generation:

docker exec -u www-data nextcloud-app php occ preview:generate-all

After the initial generation, add a cron job on the host to pre-generate previews for newly uploaded files:

# Add to host crontab with: crontab -e
*/10 * * * * docker exec -u www-data nextcloud-app php occ preview:pre-generate

Enable HTTP/2 Push and HSTS

If you are using Caddy, HTTP/2 is enabled by default. With Nginx, make sure you have http2 in your listen directive (as shown in the config above). Add HSTS headers in your reverse proxy to tell browsers to always use HTTPS.

Keeping Nextcloud Updated

Updates are straightforward with Docker. Pull the latest images and recreate the containers:

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

After updating, run the upgrade command inside the container:

docker exec -u www-data nextcloud-app php occ upgrade
docker exec -u www-data nextcloud-app php occ maintenance:repair

I recommend checking the Nextcloud changelog before major version upgrades. Going from Nextcloud 28 to 29, for example, sometimes requires intermediate steps or introduces breaking changes with certain apps. Take a database backup before any major upgrade:

docker exec nextcloud-db mariadb-dump -u nextcloud -pChangeMeDbPass2026 nextcloud > nextcloud_backup_$(date +%Y%m%d).sql

Troubleshooting Common Issues

Here are the problems I ran into during my Nextcloud installation and how I fixed them:

  • “Access through untrusted domain” — your domain is not in the trusted_domains array in config.php. Add it manually or set the NEXTCLOUD_TRUSTED_DOMAINS environment variable and recreate the container.
  • 502 Bad Gateway from reverse proxy — Nextcloud has not finished starting up, or the proxy cannot reach port 8080. Check that the container is running with docker ps and verify the port mapping.
  • File upload fails for large files — check client_max_body_size in Nginx or the equivalent in your proxy. Also verify PHP_UPLOAD_LIMIT in the compose file.
  • Slow interface on first load — this usually means APCu and OPcache are not configured. Follow the performance tuning steps above.
  • CalDAV/CardDAV not syncing — make sure your reverse proxy passes the .well-known/caldav and .well-known/carddav redirects correctly. The Nginx config above handles this.

Final Thoughts

Running my own self-hosted cloud with Nextcloud has been one of the most rewarding projects in my home lab journey. The initial Nextcloud setup takes about an hour, and after that, it just works. My files sync across all my devices, my calendar and contacts are no longer tied to Google, and my photos upload automatically from my phone to a server I physically own.

Is it more work than paying for Google Drive? Honestly, yes, a little. You are responsible for backups, updates, and occasional troubleshooting. But the trade-off is complete ownership of your data, unlimited storage limited only by the size of your hard drives, and the satisfaction of knowing that no corporation can lock you out of your own files.

If you have been thinking about leaving the big cloud providers behind, Nextcloud is the best place to start. The Nextcloud Docker deployment we built today gives you a production-ready, performant setup that can grow with your needs. Start with file sync, add calendar and contacts, and before you know it you will be wondering why you ever paid for cloud storage in the first place.

Got questions about your Nextcloud installation or ran into something I did not cover? Drop a comment below or reach out on the IGNA Online community forum. Happy self-hosting.

Enjoying this post?

Get more guides like this delivered straight to your inbox. No spam, just tech and trails.