Nextcloud is the closest thing the FOSS world has to Google Drive, Office 365 and a contacts app in one box. Files sync across desktop, web and mobile, and it adds document editing, shared calendars, contacts, video calls and an app store on top.
What it is
Files land on your own disk and stay there. Clients sync opportunistically, so a flaky mobile connection doesn't lose work. You get versioning, end-to-end-encrypted folders, CalDAV/CardDAV, Talk video calls, and a plugin ecosystem that's been compounding for a decade.
Before you start
- A domain with an A record pointing at the host. Trustworthy TLS is not optional for Nextcloud — the clients refuse plain HTTP.
- Generate real secrets now:
openssl rand -base64 24, four times, one per placeholder. - Pick a stable data directory on a real disk. If
./appis on the root filesystem you'll eventually fill it and corrupt your install.
1 — Create the data directories
mkdir -p ~/services/nextcloud/{app,db}
cd ~/services/nextcloud
2 — Write the compose file
services:
db:
image: mariadb:11.4
container_name: nextcloud-db
restart: unless-stopped
command: >-
--transaction-isolation=READ-COMMITTED
--log-bin=binlog
--binlog-format=ROW
volumes:
- ./db:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: CHANGE_ME_root
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
MYSQL_PASSWORD: CHANGE_ME_nextcloud
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 30s
timeout: 5s
retries: 3
redis:
image: redis:7-alpine
container_name: nextcloud-redis
restart: unless-stopped
command: redis-server --requirepass CHANGE_ME_redis --save ""
healthcheck:
test: ["CMD", "redis-cli", "-a", "CHANGE_ME_redis", "ping"]
interval: 30s
timeout: 5s
retries: 3
app:
image: nextcloud:apache
container_name: nextcloud
restart: unless-stopped
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
ports:
- "127.0.0.1:8080:80"
volumes:
- ./app:/var/www/html
environment:
MYSQL_HOST: db
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
MYSQL_PASSWORD: CHANGE_ME_nextcloud
REDIS_HOST: redis
REDIS_PASSWORD: CHANGE_ME_redis
NEXTCLOUD_ADMIN_USER: CHANGE_ME_admin
NEXTCLOUD_ADMIN_PASSWORD: CHANGE_ME_adminpass
TRUSTED_PROXIES: 172.16.0.0/12
OVERWRITEPROTOCOL: https
OVERWRITEHOST: cloud.example.com
OVERWRITECLIURL: https://cloud.example.com/
OVERWRITECLIURL_PORT: 443
PHP_MEMORY_LIMIT: 512M
PHP_UPLOAD_LIMIT: 16G
172.16.0.0/12 in TRUSTED_PROXIESIf anything sits in front of Nextcloud, it has to be declared trusted or you'll spend an afternoon debugging "client IP is 172.20.0.1" errors in the security settings.3 — Start it
docker compose up -d
docker compose logs -f app | grep -i "Nextcloud is now ready\|finished"
4 — First-run setup
- Put a reverse proxy in front of
127.0.0.1:8080and issue a real certificate. See Nginx Proxy Manager for the easy route, or Caddy if you'd rather not manage a UI. - Create the first admin account in the browser. The
NEXTCLOUD_ADMIN_*values above only apply if the database was completely empty at boot — if the install wizard still shows, the installer is running normally and you can ignore them. - Run the security and integrity checks from the admin panel. Fix anything red. Setup warnings are almost always the admin password being weak or a missing
setdefaultmail config. - Add
cloud.example.comto Settings → Administration → Security → Trusted domains if you ever see "untrusted domain" on any client.
5 — Lock it down and maintain it
docker exec -u www-data -it nextcloud php occ config:system:set \
mail_smtpmode smtp
docker exec -u www-data -it nextcloud php occ background:cron
docker exec -u www-data -it nextcloud php occ security:setup-app-password admin
config/ + data/ + database dump is all you need. 2. Leaving OVERWRITECLIURL on the default — cron jobs and share links then generate http://localhost URLs that nobody can click.