Add compose/nginx/env changes for Talk HPB + notify_push integration, and document deployment + hardening commands in README. Co-Authored-By: Oz <oz-agent@warp.dev>
10 KiB
Nextcloud on Ubuntu via Docker for nxt.bhatfamily.in
This repository deploys Nextcloud behind Nginx using Docker Compose.
Exposed ports:
- HTTP:
8082 - HTTPS:
8446
Target hostname:
nxt.bhatfamily.in
What changed
The stack now includes:
- Fixed Nginx mount path (
nginx/nginx.confmapped correctly) - Fixed MariaDB command (
mariadbd) - Nginx reverse proxy mode for
nextcloud:apache(no FastCGI mismatch) - Production TLS provisioning using Let's Encrypt DNS-01 with Cloudflare
- Automated TLS renewal job support (cron)
- Nextcloud app startup fixes for Apache
ServerNameand writable Fontconfig cache - Persistent web-updater enablement (
upgrade-disable-web.config.phpforced tofalse) - Reverse-proxy trust configuration in Nextcloud (
trusted_proxies,forwarded_for_headers) - Nginx hardening (
server_tokens off, stronger HSTS, hideX-Powered-By, TLS session hardening) - Brute-force protection explicitly enabled and maintenance window configured
- Scripted Nextcloud Hub upgrade workflow:
scripts/update-nextcloud-hub.sh - Automated Hub update scheduler:
scripts/setup-hub-update-cron.sh - Redis service for transactional file locking and distributed cache
- Floating app image tag enabled:
nextcloud:apache(major upgrades supported with staged path) - Setup warning remediation integrated (missing indices, mimetype migrations, log-noise cleanup)
- Nextcloud Talk high-performance backend service (
talk-hpb) with signaling endpoint - Nextcloud desktop client push via
notify_pushapp andnotify-pushservice
Current baseline (Apr 2026)
- App image:
nextcloud:apache - DB image:
mariadb:11.4 - Cache/locking:
redis:7-alpine - Nextcloud version at last validation:
33.0.2 - Talk HPB:
ghcr.io/nextcloud-releases/aio-talk:latestvia/standalone-signaling/ - Client push:
notify_pushapp +nextcloud-notify-pushservice via/push/
Prerequisites
- Ubuntu host with Docker + Docker Compose plugin (or
docker-compose) - Domain
nxt.bhatfamily.inin Cloudflare DNS - DNS A record for
nxtpointing to your server public IP (DNS-only) - Router/firewall forwarding for ports
8082and8446
Initial setup
- Create runtime env file:
cp .env.example .env
- Edit
.envwith strong values. - Start stack with bootstrap TLS:
./scripts/install.sh
- Validate:
./scripts/test.sh
Enable web updater (one-time verification)
Web updater is enabled by design for this deployment.
Check values:
docker exec --user www-data nextcloud-app php occ config:list system | grep -E "upgrade.disable-web|updater.release.channel"
Expected:
upgrade.disable-web: falseupdater.release.channel: stable
Update Nextcloud Hub (scripted)
Use the upgrade helper script to pull images, apply upgrades, run repairs, and validate endpoints.
Run update:
./scripts/update-nextcloud-hub.sh
Optional flags:
- Skip app marketplace updates:
RUN_APP_UPDATES=0 ./scripts/update-nextcloud-hub.sh
- Skip expensive repairs/mimetype migration pass:
RUN_EXPENSIVE_REPAIR=0 ./scripts/update-nextcloud-hub.sh
- Require strict TLS validation during smoke tests (no
-k):
STRICT_TLS=1 ./scripts/update-nextcloud-hub.sh
What the script does:
- pulls latest
db,app, andwebimages - recreates services and restarts
webto refresh upstream resolution - ensures web updater is enabled and release channel is configured
- ensures maintenance mode is off before
occ upgrade - runs
occ upgrade - runs
occ app:update --all(unless disabled) - runs schema and repair commands (
db:add-missing-*,maintenance:repair) - optionally runs
maintenance:repair --include-expensive - runs
occ status,occ setupchecks, andscripts/test.sh
Important: major upgrades are one-at-a-time
Nextcloud only supports upgrading one major version at a time.
If the floating nextcloud:apache tag is more than one major ahead of your installed version, do staged upgrades first, for example:
nextcloud:31-apache→ run updater scriptnextcloud:32-apache→ run updater scriptnextcloud:33-apache→ run updater script- switch back to
nextcloud:apache
Automate Hub updates (cron)
Install/update a weekly cron job (default: Sunday 02:30):
./scripts/setup-hub-update-cron.sh
Optional custom schedule:
HUB_UPDATE_CRON_SCHEDULE="15 2 * * 6" ./scripts/setup-hub-update-cron.sh
This setup script will:
- create/update
.hub-update.env(local only, not committed) - install/refresh cron entry for
scripts/update-nextcloud-hub.sh - write logs to
logs/hub-update.log
Defaults tracked in .hub-update.env.example:
RUN_APP_UPDATES=1RUN_EXPENSIVE_REPAIR=1STRICT_TLS=0ENABLE_WEB_UPDATER=1UPDATER_RELEASE_CHANNEL=stable
Setup warning remediation notes
The following warning-focused fixes are now part of the deployed configuration:
- Transactional File Locking: Redis-backed locking enabled (
memcache.locking=Redis) - Mimetype migrations: addressed via
maintenance:repair --include-expensive - Missing optional indices: addressed via
occ db:add-missing-indices - AppAPI deploy daemon errors:
app_apidisabled (not used in this deployment) - Internet connectivity check log spam:
has_internet_connection=falseset intentionally for this environment
If you want AppAPI external apps later:
- re-enable app:
docker exec --user www-data nextcloud-app php occ app:enable app_api - configure a reachable deploy daemon from Settings > AppAPI
Deploy Talk HPB and client push
This deployment includes Talk HPB and desktop client push support in Docker Compose.
Required secrets in .env (already templated in .env.example):
TALK_TURN_SECRETTALK_SIGNALING_SECRETTALK_INTERNAL_SECRET
- Start/update services:
docker compose up -d app talk-hpb notify-push web
- Configure Talk signaling/STUN/TURN in Nextcloud:
set -a; source .env; set +a
docker exec --user www-data nextcloud-app php occ talk:signaling:add --verify https://nxt.bhatfamily.in:8446/standalone-signaling "$TALK_SIGNALING_SECRET"
docker exec --user www-data nextcloud-app php occ talk:stun:add nxt.bhatfamily.in:3478
docker exec --user www-data nextcloud-app php occ talk:turn:add --secret="$TALK_TURN_SECRET" turn nxt.bhatfamily.in:3478 udp,tcp
- Configure Client Push (
notify_push):
docker exec --user www-data nextcloud-app php occ app:install notify_push
docker exec --user www-data nextcloud-app php occ notify_push:setup https://nxt.bhatfamily.in:8446/push
docker exec --user www-data nextcloud-app php occ notify_push:self-test
If notify_push is already installed, skip app:install and run notify_push:setup + self-test.
- Verify endpoints and setup checks:
curl -k https://nxt.bhatfamily.in:8446/standalone-signaling/api/v1/welcome
docker exec --user www-data nextcloud-app php occ setupchecks
One-time setup/security hardening commands
These commands were used to clear remaining setup/security notices in this deployment:
docker exec --user www-data nextcloud-app php occ twofactorauth:enforce --on
docker exec --user www-data nextcloud-app php occ config:system:set default_phone_region --value=IN
docker exec --user www-data nextcloud-app php occ config:system:set serverid --type=integer --value=1
docker exec --user www-data nextcloud-app php occ config:system:set mail_smtpmode --value=null
Adjust default_phone_region to your country code as needed.
Move Nextcloud data directory to external storage
Use the migration helper to move existing data to a host path and switch the app to a bind mount.
Default target:
/media/rbhat/DATA/nextcloud/NextCloudData
Run migration:
./scripts/migrate-data-directory.sh /media/rbhat/DATA/nextcloud/NextCloudData
What the script does:
- enables maintenance mode
- copies current
/var/www/html/datacontent to target directory - applies owner/group and permissions for Nextcloud (
www-data) - updates
docker-compose.ymlapp volume with...:/var/www/html/data - recreates
appandwebservices - disables maintenance mode and verifies mount
Rollback (if needed):
- Remove the
:/var/www/html/databind mount line fromappvolumes indocker-compose.yml. docker compose up -d app web- Confirm status:
docker exec --user www-data nextcloud-app php occ status
Production TLS (Let's Encrypt + Cloudflare DNS-01)
- Export credentials in shell:
export CF_DNS_API_TOKEN={{CF_DNS_API_TOKEN}}
export LETSENCRYPT_EMAIL={{LETSENCRYPT_EMAIL}}
- Issue/renew and install production cert:
./scripts/provision-production-tls.sh
- Reload Nginx container:
docker compose restart web
- Verify cert:
echo | openssl s_client -connect nxt.bhatfamily.in:8446 -servername nxt.bhatfamily.in 2>/dev/null | openssl x509 -noout -subject -issuer -dates
Automated renewal job (cron)
- Ensure your Cloudflare token export script exists (default path used by renewal wrapper):
~/bin/cloudflare-api-usertoken.sh
- Install/update renewal cron entry:
./scripts/setup-renewal-cron.sh
This script will:
- create/update
.tls-renewal.env(local only, not committed) - install a daily cron job (
03:17by default) - write logs to
logs/tls-renew.log
- Manual renewal run (same path cron uses):
./scripts/renew-production-tls.sh
Admin password reset
List existing users:
docker exec --user www-data nextcloud-app php occ user:list
Reset password using helper script (interactive prompt):
./scripts/reset-admin-password.sh admin
Reset password non-interactively (for automation):
NEW_NEXTCLOUD_PASSWORD={{NEW_NEXTCLOUD_PASSWORD}} ./scripts/reset-admin-password.sh admin
You can target a different username by passing it as the first argument.
Useful commands
Start/update containers:
docker compose up -d
Restart all services:
docker compose restart
Restart web only:
docker compose restart web
Stop and remove containers/volumes:
./scripts/uninstall.sh
Security notes
.env,.tls-renewal.env,.hub-update.env, and runtime cert material undernginx/sslare intentionally ignored by Git.backups/is ignored and used for local database/log snapshots before risky changes.- Keep
.envmode restricted (chmod 600 .env). - If secrets were ever committed earlier, rotate them.