Deploy Nextcloud on TrueNAS SCALEBehind a NPMplus SSL Proxy
Nextcloud is consistently one of the most-installed apps on TrueNAS SCALE, but the official app catalog ships with a few defaults and quirks that can send a fresh install sideways; especially if you're putting it behind a reverse proxy like NPMplus. The good news is that once you know which boxes to tick (and which to leave alone), the whole stack comes up clean and stays up.
This guide walks through the exact sequence I used to deploy Nextcloud on TrueNAS SCALE Community Edition with NPMplus handling SSL and reverse proxying, with all the working settings with no detours, no "try this and see if it works" steps, and no recovery sections you'll only need if something breaks.
What You'll Need Before Starting
- TrueNAS SCALE Community Edition (24.10 or newer) up and running
- An NPMplus instance already deployed and reachable on your LAN (this guide assumes NPMplus is running as another TrueNAS app)
- A domain or DDNS hostname pointing at your WAN IP; e.g. nextcloud.yourdomain.com
- Ports 80 and 443 forwarded from your router/firewall to your TrueNAS IP (Let's Encrypt needs port 80; HTTPS uses 443)
- Shell access to TrueNAS (System → Shell, or SSH)
Throughout the article I'll use these placeholders and you will just need to substitute your own values:
- POOL: Your TrueNAS pool name
- 10.0.1.X: Your TrueNAS LAN IP
- nextcloud.yourdomain.com: The public hostname you'll access Nextcloud through
Step 1 - Pre-Create The Needed Datasets In TrueNAS
This is the single most important step for a smooth install. Pre-creating your datasets and pointing Nextcloud at them as Host Paths (not auto-generated ixVolumes) means your data is in a known location that's easy to back up, easy to recover, and easy to edit when you need to tweak config.php later.
In the TrueNAS web console, go to Datasets, select your pool, and create the following structure:
POOL/
└── Apps/
└── nextcloud/
├── data ← user files (the bulk of your storage)
├── config ← Nextcloud config.php, themes, custom apps
└── postgres ← database files
For each of the three child datasets, use these settings:
- Dataset Preset: Generic
- ACL Type: POSIX (do not use NFSv4 as the Nextcloud container runs as a non-root UID and POSIX is what it expects)
- Case Sensitivity: Sensitive
You don't need to manually configure ACLs or permissions for the data and config datasets; the app will set those during install. But there's one permission tweak you should do up front…
Step 2 - Pre-Set Postgres Ownership (The Install-Saver)
The Nextcloud app's PostgreSQL container runs as UID/GID 999 internally. If your postgres dataset isn't already owned by 999:999 when the app first comes up, the postgres_upgrade init container can fail and the whole install bails out; usually with a generic Python traceback that doesn't tell you what's wrong.
Setting it correctly before first install bypasses the issue entirely. Open System → Shell and run:
sudo chown -R 999:999 /mnt/POOL/Apps/nextcloud/postgres
That's it. One command. The other two datasets (data and config) can stay at their default ownership, as the Nextcloud container will fix those itself.
Step 3 - Install The Nextcloud App In TrueNAS
In the TrueNAS web console go to Apps → Available Applications, search for Nextcloud, and click Install.
Application Name
Use nextcloud (or whatever you want).
Nextcloud Configuration
- Admin Username: your choice
- Admin Password: a strong password and save it
- Host: nextcloud.yourdomain.com (the exact public hostname you'll access it at)
- Data Directory: leave default
The Host field matters. Whatever you type here gets written into config.php as a trusted domain. Type the public FQDN exactly as you'll use it without a https:// prefix, no trailing slash, no markdown formatting (paste it as plain text only).
Database Configuration
- Database Type: PostgreSQL (preferred over SQLite for any real-world use)
- Database Password: a strong password
Storage Configuration
For each of the three storage sections, change the Type to Host Path (Path that already exists on the system) and point at the dataset you pre-created. Leave the Enable ACL checkbox unchecked for all three as the container manages its own internal permissions, and ACL enforcement at the dataset level can cause permission-denied errors on first boot.
- Nextcloud AppData (config) → /mnt/POOL/Apps/nextcloud/config
- Nextcloud User Data → /mnt/POOL/Apps/nextcloud/data
- Postgres Data → /mnt/POOL/Apps/nextcloud/postgres
Networking
Leave the default NodePort as-is unless you have a reason to change it. Note the port number assigned (typically something in the 30000-range like 30027) as you'll need it in the next step.
Resources Configuration
- CPUs: 2
- Memory: 4096 MB
- GPU: leave unchecked
Click Install and wait. First boot takes 2–5 minutes while the container image pulls and Postgres initializes; the app status will go from Deploying to Running when it's ready.
Step 4 - Verify Local Access
Once the app shows Running, browse to http://10.0.1.X:30027 from any machine on your LAN (substitute your TrueNAS IP and the NodePort from the install step). You should hit the Nextcloud login page. Log in with the admin credentials you set during install to confirm everything's working before you put a proxy in front of it.
If the login page loads and you can sign in, the app side is done. Now let's get it on a real domain with a real SSL cert.
Step 5 - Add A Proxy Host In NPMplus
Open NPMplus (typically at https://10.0.1.X:81), go to Hosts → Proxy Hosts, and click Add Proxy Host.
Details tab
- Domain Names: nextcloud.yourdomain.com
- Scheme: http
- Forward Hostname / IP: 10.0.1.X (your TrueNAS IP)
- Forward Port: the NodePort from Step 3 (e.g. 30027)
- Cache Assets: Off
- Block Common Exploits: On
- Disable Request Buffering: On
- Disable Response Buffering: On
The two buffering toggles handle the equivalent of proxy_buffering off and proxy_request_buffering off in nginx config and are required for Nextcloud to handle large file uploads/downloads cleanly without it stalling out behind the proxy.
TLS tab
- SSL Certificate: Request a new SSL Certificate
- Force HTTPS: On
- HSTS Enabled: On
- HTTP/2 Support: On
- HTTP/3 Support: On
- Email address: your email (for Let's Encrypt notifications)
If you're using DuckDNS or another DNS-API-capable provider, enable Use DNS Challenge instead of letting it default to HTTP-01. DNS challenge is more reliable, doesn't require port 80 to be open from the public internet, and lets you issue wildcard certs that cover every subdomain on your domain. Select your provider, paste in the API token, and the credentials file content will auto-populate.
Advanced tab (custom nginx config)
Click into the custom nginx config field (the gear icon at the top right of the edit dialog in some NPMplus versions, or the dedicated Advanced tab in others) and paste this exactly:
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 $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
client_max_body_size 10G;
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
What this is doing, briefly:
- The first four
proxy_set_headerlines tell Nextcloud the original client's hostname, IP, and protocol (so it generates correct URLs and logs the right IPs) - The Upgrade and Connection headers enable WebSocket support for Nextcloud Talk and live notifications
client_max_body_size 10Glets you upload large files through the proxy so just tune up or down to taste- The HSTS header reinforces HTTPS enforcement at the browser level
Save the proxy host. NPMplus will issue the Let's Encrypt cert (takes 10–30 seconds) and reload nginx automatically.
Step 6 - Patch config.php For The Reverse Proxy
If you load https://nextcloud.yourdomain.com right now, you'll likely either get an "Access through untrusted domain" error or hit a redirect loop. That's because Nextcloud doesn't know it's behind a reverse proxy yet. Two minutes in config.php fixes everything.
Because you used Host Path storage, the file is directly editable on the host filesystem. Open it in your editor of choice:
sudo nano /mnt/POOL/Apps/nextcloud/config/config/config.php
Note the doubled config/config , that's actually correct. The container mounts your config dataset at /var/www/html/config, and Nextcloud's actual config file lives one level deeper at config/config.php inside that.
Find the 'trusted_domains' array (it'll have just your FQDN in it) and replace it with the block below, adding all the overwrite/proxy lines just after it. Place this block just before the final closing );:
'trusted_domains' =>
array (
0 => '127.0.0.1',
1 => 'localhost',
2 => 'nextcloud',
3 => 'nextcloud.yourdomain.com',
4 => '10.0.1.X:30027',
),
'overwrite.cli.url' => 'https://nextcloud.yourdomain.com',
'overwriteprotocol' => 'https',
'overwritehost' => 'nextcloud.yourdomain.com',
'trusted_proxies' => array('10.0.1.0/24'),
'forwarded_for_headers' => array('HTTP_X_FORWARDED_FOR'),
What each line does:
- trusted_domains: every hostname/IP you want to allow Nextcloud to be accessed from. Including 10.0.1.X:30027 means you can still hit it locally for troubleshooting if your domain or proxy ever has issues.
- overwrite.cli.url, overwriteprotocol, overwritehost: tell Nextcloud how to construct its own URLs. Without these you'll get redirect loops, broken share links, and mixed-content warnings.
- trusted_proxies: tells Nextcloud which IPs are allowed to set X-Forwarded-* headers on its behalf. Setting your LAN subnet covers any container IP NPMplus might use.
- forwarded_for_headers: which header Nextcloud should read for the real client IP.
Critical: paste the domain values as plain text. If you copy from a chat client or markdown editor and end up with something like [nextcloud.yourdomain.com](http://nextcloud.yourdomain.com) in the file, the trusted-domain match will fail and you'll keep getting the untrusted-domain error.
Save (Ctrl+O, Enter) and exit (Ctrl+X). Nextcloud reads config.php on every request, so no container restart needed.
Step 7 - Test It All!
Refresh https://nextcloud.yourdomain.com in your browser. You should land on the login page, served over HTTPS, with a valid Let's Encrypt cert. Sign in with the admin credentials you set during install.
Once you're logged in, head to Administration Settings → Overview and check the Security & setup warnings panel. If you've followed every step above, this should be clean with no proxy warnings, no missing-headers warnings, no "reverse proxy not configured" complaints.
What To Do Next:
You now have a fully working, SSL-secured, reverse-proxied Nextcloud instance. Some natural next steps:
- Install the desktop and mobile sync clients and point them at https://nextcloud.yourdomain.com and sign in with your admin (or a regular user) account
- Set up a periodic snapshot task on your POOL/Apps/nextcloud dataset (Datasets → Periodic Snapshot Tasks) for cheap point-in-time backups
- Add additional users from the Users panel rather than letting everyone share the admin account
- Install Nextcloud apps like Calendar, Contacts, Notes, and Talk from the built-in app catalog
- Run the background job (cron) on a schedule rather than letting it use AJAX for better performance and reliability
The biggest win of pre-creating datasets and using Host Paths is that everything important to the app lives in three predictable folders on your pool. Backups, restores, migrations to another server, and config edits all become trivial. If you ever need to rebuild the app from scratch, you can delete the app, point a new install at the same datasets, and pick up exactly where you left off.
If you found this useful, please leave a comment with what you're using your Nextcloud instance for and include any tweaks you made along the way that worked better for your environment!!
Created & Maintained by Pacific Northwest Computers
📞 Pacific Northwest Computers offers Remote & Onsite Support Across:
SW Washington including Vancouver WA, Battle Ground WA, Camas WA, Washougal WA, Longview WA, Kelso WA, and Portland OR


No comments:
Post a Comment