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.comworks 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-COMMITTEDbecause Nextcloud specifically requires it. The binary logging format is also set toROWfor 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
httpsbecause 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:
- Background jobs — make sure this is set to “Cron” since we deployed a dedicated cron container.
- 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.
- Default phone region — set this under Basic settings to avoid a warning. Add the following to your
config.phpif 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_domainsarray inconfig.php. Add it manually or set theNEXTCLOUD_TRUSTED_DOMAINSenvironment 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 psand verify the port mapping. - File upload fails for large files — check
client_max_body_sizein Nginx or the equivalent in your proxy. Also verifyPHP_UPLOAD_LIMITin 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/caldavand.well-known/carddavredirects 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.