How to Install Nextcloud with Docker (Your Own Private Cloud)

Nextcloud is Dropbox, Google Photos, a calendar and contacts, all on your own server. Phone photos upload automatically, files sync to every computer, and nobody is mining it for advertising. With Docker Compose it's one file and one command, plus a reverse proxy if you want to reach it from outside.
Quick reference
| Task | What |
|---|---|
| Folder | ~/docker/nextcloud/compose.yaml |
| Start | docker compose up -d |
| First visit | http://server-ip:8080 |
| Apps | Nextcloud on iOS/Android; desktop client for Windows/Mac/Linux |
| Run a Nextcloud command | docker compose exec -u www-data app php occ ... |
| Update | docker compose pull && docker compose up -d |
1. The compose file
mkdir -p ~/docker/nextcloud && cd ~/docker/nextcloud
nano compose.yaml
services:
db:
image: mariadb:11
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
environment:
MARIADB_ROOT_PASSWORD: change-this-root-password
MARIADB_DATABASE: nextcloud
MARIADB_USER: nextcloud
MARIADB_PASSWORD: change-this-password
volumes:
- ./db:/var/lib/mysql
restart: unless-stopped
redis:
image: redis:alpine
restart: unless-stopped
app:
image: nextcloud:30
ports:
- "127.0.0.1:8080:80"
environment:
MYSQL_HOST: db
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
MYSQL_PASSWORD: change-this-password
REDIS_HOST: redis
NEXTCLOUD_TRUSTED_DOMAINS: cloud.example.com 192.168.1.50
OVERWRITEPROTOCOL: https
PHP_UPLOAD_LIMIT: 10G
volumes:
- ./html:/var/www/html
- /mnt/data/nextcloud:/var/www/html/data
depends_on:
- db
- redis
restart: unless-stopped
Change both passwords, the trusted domains, and the data path (put it on your biggest drive). If you'll only use it inside your network and not through Nginx, change the ports line to "8080:80" and remove OVERWRITEPROTOCOL.
docker compose up -d
2. First run
Open http://192.168.1.50:8080. Create the admin account. The database is already filled in from the environment variables, so just click Install. Skip the recommended apps for now — they can be added later.
3. Reach it from outside
Add a server block in Nginx (tutorial 28) for cloud.example.com pointing at 127.0.0.1:8080, with client_max_body_size 10G; and the WebSocket lines, then certbot --nginx -d cloud.example.com.
4. The apps
- Phone: install Nextcloud, enter https://cloud.example.com, log in. Turn on Auto upload for the camera folder.
- Desktop: the Nextcloud client puts a folder in your home directory that syncs both ways, like Dropbox.
- Calendar and contacts: install the Calendar and Contacts apps from inside Nextcloud, then add the account on your phone as a CalDAV/CardDAV account (iOS: Settings → Calendar → Accounts → Add → Other).
5. Background jobs
In Administration settings → Basic settings, set background jobs to Cron, then on the server:
sudo crontab -e
*/5 * * * * docker compose -f /home/john/docker/nextcloud/compose.yaml exec -u www-data app php cron.php
Updating
docker compose pull && docker compose up -d
Nextcloud only upgrades one major version at a time — change nextcloud:30 to 31, update, then 32, and so on. Back up ./db and ./html first.
Troubleshooting
"Access through untrusted domain". Add the name or IP you're using to NEXTCLOUD_TRUSTED_DOMAINS and docker compose up -d.
Warnings on the admin overview page. Most are about headers or the proxy. Run docker compose exec -u www-data app php occ db:add-missing-indices for the database ones; the rest are fixed by the Nginx headers from tutorial 28.
Uploads fail at around 1 MB or 100 MB. client_max_body_size in Nginx, and PHP_UPLOAD_LIMIT in the compose file.
Slow with lots of files. Make sure redis is running (docker compose ps) and background jobs are on cron.
Phone app says the server is on http. OVERWRITEPROTOCOL: https is missing or you're hitting the raw port instead of going through Nginx.
Wrapping up
One compose file with a database, Redis and Nextcloud; data on your big drive; Nginx and Certbot in front. Install the apps, turn on auto-upload, and you've replaced a cloud subscription with a box in the cupboard.
