Nextcloud HTTPS SSL Setup with Docker Compose: A Step-by-Step Guide for Homelab
Learn how to deploy Nextcloud v34.0.3 with Docker Compose, configure HTTPS/SSL via Let's Encrypt and Nginx Proxy Manager, and secure your homelab.
Introduction
Self-hosting Nextcloud is one of the most rewarding projects for any homelab enthusiast. It gives you full control over your files, calendars, contacts, and collaborative documents—no more relying on third-party cloud services that mine your data. However, exposing Nextcloud to the internet without proper HTTPS/SSL encryption is like leaving your front door wide open. In this guide, you will learn how to set up Nextcloud v34.0.3 using Docker Compose, secure it with a reverse proxy (Nginx Proxy Manager), and obtain trusted SSL certificates via Let's Encrypt. We will cover everything from prerequisites to advanced hardening, including common pitfalls and their solutions.
By the end of this guide, you will have a fully functional Nextcloud instance accessible via HTTPS with auto-renewing certificates, automated backups, and a hardened configuration. Whether you are a seasoned sysadmin or a curious hobbyist, the step-by-step instructions and troubleshooting table will help you avoid the usual mistakes and save hours of debugging.
Let's dive in. We assume you have basic familiarity with Docker and Linux, but we'll explain every command so you can follow along even if you're not an expert.
Prerequisites / Requirements
Before you begin, ensure your homelab hardware and software meet these minimum requirements. The table below lists typical values—actual needs vary with the number of users and usage patterns.
| Component | Minimum (Typical) | Recommended | Notes |
|---|---|---|---|
| CPU | 2 cores | 4+ cores | Nextcloud performs many PHP and database operations; more cores help with concurrent requests. |
| RAM | 2 GB (estimated) | 4 GB+ | Heavily depends on the number of active users, background jobs, and caching. |
| Storage | 20 GB free | 100+ GB | Store your data files separately from the OS; consider a RAID or a NAS. |
| OS | Ubuntu 22.04 LTS (or Debian 12) | Any recent Linux | Docker Engine and Docker Compose plugin are required. |
| Software | Docker Engine 24+, Docker Compose v2 | Latest stable | Install via official Docker repository. |
| Domain | A domain name pointing to your public IP | Dynamic DNS is fine | Needed for SSL certificates. |
| Ports | 80 and 443 (inbound) | - | Must be open in your firewall/router. |
Important: This guide assumes you have a domain name (e.g., cloud.example.com) that resolves to your homelab's public IP. If you only have an IP, you can still use a self-signed certificate, but it won't be trusted by browsers without additional configuration.
Step-by-Step Installation
Step 1: Prepare Your Environment
Create a dedicated directory for Nextcloud and set up a .env file to store secrets and configuration variables. This keeps your docker-compose.yml clean and avoids hardcoding passwords.
mkdir -p ~/nextcloud && cd ~/nextcloud && touch .env
Edit the .env file with your preferred text editor (nano, vim, etc.) and add the following content. Never commit this file to Git.
# .env
NEXTCLOUD_VERSION=34.0.3
MYSQL_PASSWORD=change-me-strong-password
MYSQL_ROOT_PASSWORD=change-me-root-password
REDIS_PASSWORD=change-me-redis-password
Replace the passwords with strong random strings (e.g., openssl rand -base64 32).
Step 2: Create the Docker Compose File
Create a file named docker-compose.yml in the same directory. This configuration uses official images for Nextcloud, MariaDB, and Redis.
version: "3.8"
services:
db:
image: mariadb:10.11
container_name: nextcloud-db
restart: unless-stopped
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
volumes:
- ./db:/var/lib/mysql
environment:
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: nextcloud-redis
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- ./redis:/data
app:
image: nextcloud:${NEXTCLOUD_VERSION:-latest}
container_name: nextcloud-app
restart: unless-stopped
ports:
- "8080:80"
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- ./nextcloud:/var/www/html
environment:
- MYSQL_HOST=db
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- REDIS_HOST=redis
- REDIS_PASSWORD=${REDIS_PASSWORD}
- NEXTCLOUD_ADMIN_USER=admin
- NEXTCLOUD_ADMIN_PASSWORD=change-me-admin-password
- TRUSTED_DOMAINS=cloud.example.com
Note: The NEXTCLOUD_VERSION variable is set to 34.0.3 in the .env file. If you omit it, the tag latest will be used, which is not recommended for production. Always pin to a specific version. Check the official Nextcloud Docker Hub page for the latest stable release before upgrading.
Step 3: Start the Stack
Pull the images and start the containers in detached mode.
docker compose up -d
Wait a few minutes for the database to initialize. Check the logs to ensure everything is ready.
docker compose logs -f app
When you see a message like Nextcloud is ready, you can proceed. Open your browser to http://localhost:8080 to verify the initial setup screen appears.
Step 4: Configure Nextcloud Initial Settings
If you didn't set the admin user via environment variables, you'll see a setup wizard. We set it in the environment, so the admin user is created automatically. However, you should still visit the web interface and change the admin password to a strong one if you used the default in .env (we used change-me-admin-password).
Go to https://cloud.example.com (once SSL is set up later). For now, use http://localhost:8080 and log in with the admin credentials from your .env. Then navigate to Settings → Security and update your password.
Step 5: Set Up a Reverse Proxy with SSL
For HTTPS/SSL, we'll use Nginx Proxy Manager (NPM) as a reverse proxy. It provides a user-friendly web UI to manage SSL certificates via Let's Encrypt.
First, create a directory for NPM and its compose file.
mkdir -p ~/nginx-proxy-manager && cd ~/nginx-proxy-manager && touch docker-compose.yml
Edit docker-compose.yml with the following content:
version: "3.8"
services:
npm:
image: jc21/nginx-proxy-manager:latest
container_name: npm
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "81:81" # Admin UI
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
Start NPM:
docker compose up -d
Access the NPM admin UI at http://localhost:81. The default login is admin@example.com with password changeme. Change it immediately after first login.
Step 6: Configure Proxy Host in NPM
In the NPM admin panel:
- Go to Proxy Hosts → Add Proxy Host.
- Fill in:
- Domain Names:
cloud.example.com - Scheme:
http - Forward Hostname/IP:
nextcloud-app(if NPM and Nextcloud are on the same Docker network) orlocalhost(if using port mapping). Since we didn't connect them to a custom network, we'll use the host's IP and port8080. Usehttp://127.0.0.1:8080. - Forward Port:
8080
- Domain Names:
- Enable Websockets Support (important for collaboration features).
- Under SSL tab, select Request a new SSL Certificate, enter your email, and agree to the terms. Choose Force SSL and HTTP/2.
- Save the configuration.
NPM will automatically obtain a Let's Encrypt certificate and renew it.
Step 7: Update Nextcloud Configuration for Trusted Domains
Nextcloud needs to know which domains are allowed. Edit the config/config.php file inside the Nextcloud container or volume.
docker exec -it nextcloud-app sed -i "s/'trusted_domains' =>/[removed]/" /var/www/html/config/config.php
Better, run an interactive shell:
docker exec -it nextcloud-app bash
Edit /var/www/html/config/config.php and add your domain to the trusted_domains array.
'trusted_domains' =>
array (
0 => 'localhost',
1 => 'cloud.example.com',
),
Exit the container and restart the app container to apply changes.
docker restart nextcloud-app
Step 8: Enable HTTPS in Nextcloud (Optional)
If you want Nextcloud to know it's behind HTTPS, you can set the overwriteprotocol parameter. Edit the config file again and add:
'overwriteprotocol' => 'https',
Also, set overwrite.cli.url to your HTTPS domain.
Step 9: Set Up Background Jobs (Cron)
Nextcloud should run background tasks. Use the system cron inside the container.
Edit the config.php and add:
'backgroundjobs_mode' => 'cron',
Then add a crontab entry on the host to execute the cron script every 5 minutes:
crontab -e
Add this line:
*/5 * * * * docker exec -u www-data nextcloud-app php /var/www/html/cron.php
Save and exit.
Step 10: Verify SSL and Functionality
Open https://cloud.example.com in your browser. You should see the lock icon. Test uploads, downloads, and the mobile app. Also, check the Nextcloud admin panel under Settings → Overview for any warnings.
Advanced Setup and Optimization
Reverse Proxy and SSL Best Practices
- Use a dedicated Docker network for all containers to avoid exposing ports to the host. For example, create a network
weband attach NPM and Nextcloud to it. Then in NPM, forward tonextcloud-app:80instead oflocalhost:8080. - Enable HTTP/2 in NPM (we did).
- Set up a firewall (ufw) to only allow ports 80, 443, and 81 (admin) from your local network.
Backups
Automate backups of the Nextcloud data volume and database. Create a script that runs docker exec to dump the database and copy the data folder.
mkdir -p ~/backup-scripts && cd ~/backup-scripts && touch backup_nextcloud.sh && chmod +x backup_nextcloud.sh
Edit the script with the following content:
#!/bin/bash
# Backup Nextcloud data and database
BACKUP_DIR=~/backups/nextcloud
mkdir -p $BACKUP_DIR
DATE=$(date +%Y%m%d_%H%M%S)
# Dump database
docker exec nextcloud-db sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > $BACKUP_DIR/db_$DATE.sql
# Copy data
tar czf $BACKUP_DIR/data_$DATE.tar.gz -C ~/nextcloud nextcloud
# Clean old backups (keep last 7)
find $BACKUP_DIR -type f -mtime +7 -delete
Add a crontab entry to run this daily.
Security Hardening (Optional)
Important: The following settings are advanced and may break your container if not adapted to your specific environment. Test them thoroughly.
- Add
read_only: trueto the app service in Docker Compose, but then you must mount theconfiganddatadirectories as writable volumes. - Use
cap_drop: [ALL]and add specific capabilities likeCHOWN,SETUID, etc., as needed. This requires deep testing. - Set `security_opt:
- no-new-privileges:true`
Example snippet:
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
cap_add:
- CHOWN
- SETUID
- SETGID
But note: Nextcloud may need to write to /var/www/html for updates and apps. You'll need to mount the config and data directories as volumes.
Troubleshooting Common Issues
| Error | Cause | Solution |
|---|---|---|
502 Bad Gateway from NPM |
Nextcloud container not reachable or wrong forward host/port | Check that Nextcloud is running (docker ps), and that NPM is on the same network or can reach the host port. Use curl http://localhost:8080 from the host. |
| SSL certificate not issued | Domain not pointing to your IP, or port 80 not accessible | Verify DNS A record, ensure port 80 is open, and try again. |
| Nextcloud shows “Untrusted domain” | The domain not in trusted_domains |
Edit config.php and add the domain, then restart. |
| Database connection error | MariaDB not ready or credentials wrong | Check .env values match, and view logs with docker logs nextcloud-db. |
| Redis connection error | Redis password mismatch | Ensure the REDIS_PASSWORD is the same in both .env and the app environment. |
| Updates fail with “Could not write to config” | File permissions incorrect | Run id -u and id -g on your host and compare to the image's default user (www-data, UID 33 in the official image). Adjust the ownership of the nextcloud volume accordingly. |
Conclusion and FAQ
You now have a production-ready Nextcloud instance secured with HTTPS/SSL. This setup gives you the freedom of self-hosting while maintaining security and reliability. Remember to keep your system updated, perform regular backups, and monitor logs.
FAQ
1. Can I use a self-signed certificate instead of Let's Encrypt? Yes, but browsers will show a warning. Let's Encrypt provides trusted certificates for free and is the recommended approach. You can use a self-signed for testing only.
2. How do I update Nextcloud to a newer version?
Change the NEXTCLOUD_VERSION in your .env file to the new version (check official Docker Hub), then run docker compose pull and docker compose up -d. Always backup before upgrading.
3. What if I don't have a domain name? You can use a dynamic DNS service like DuckDNS. Point it to your public IP and use that hostname for SSL. The certificate will cover that hostname.
4. How do I access Nextcloud from outside my local network?
Ensure your router forwards ports 80 and 443 to the host running NPM. Then access https://cloud.example.com. Consider using a VPN for extra security.
5. My Nextcloud is slow. What can I do? Enable Redis caching (we did), use PHP OPcache (default), and consider using a faster database like PostgreSQL. Also check that background jobs are set to cron and not Ajax.
For more details, always refer to the official Nextcloud documentation and Docker images. Happy self-hosting!