A step-by-step guide for deploying Nextcloud All-in-One (AIO) on a private Tailscale network, using host Nginx for SSL termination via Cloudflare DNS-01 verification and Collabora Online for document editing.
This deployment model was intentionally selected to achieve three core operational goals:
- Domain Name & SSL Control: Using Cloudflare DNS-01 validation allows for trusted Let's Encrypt Wildcard/SAN SSL certificates under a custom domain without opening inbound router ports or exposing web services directly to public scanners.
- Enhanced Security (No WAN Exposure): By pairing Tailscale with Cloudflare DNS-only records pointing to private mesh IPs (
100.x.y.z), the Nextcloud instance is entirely isolated from public WAN threats while remaining seamlessly accessible across authorized personal devices. - Optimized Network Performance: Tailscale's WireGuard-based mesh network establishes direct peer-to-peer (P2P) connections between clients and the host server, ensuring high-speed local transfer rates for heavy file synchronization and Collabora sessions.
The example default compose.yaml can be found here.
This is a summary of the file's active lines:
services:
nextcloud-aio-mastercontainer:
image: nextcloud/all-in-one:latest
init: true
sig-proxy: false
container_name: nextcloud-aio-mastercontainer
restart: always
ports:
- "8080:8080"
environment:
APACHE_PORT: 11000
APACHE_IP_BINDING: 127.0.0.1
NEXTCLOUD_DATADIR: ${PWD}/ncdata
SKIP_DOMAIN_VALIDATION: true
volumes:
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config
- /var/run/docker.sock:/var/run/docker.sock:ro
volumes:
nextcloud_aio_mastercontainer:
name: nextcloud_aio_mastercontainerBelow is a breakdown of the modifications made to the default Nextcloud AIO configuration and the specific reasons for each change:
environment:
APACHE_PORT: 11000
APACHE_IP_BINDING: 127.0.0.1
NEXTCLOUD_DATADIR: ${PWD}/ncdata
SKIP_DOMAIN_VALIDATION: true-
Commented out Ports 80 & 8443
- Modification: Removed port mappings for
80and8443from theportsblock incompose.yaml. - Why: Disables AIO's built-in web server binding on standard web ports so host Nginx can freely manage HTTP/HTTPS traffic.
- Modification: Removed port mappings for
-
APACHE_PORT: 11000
- Modification: Changed Nextcloud's internal Apache container port to
11000. - Why: Tells the mastercontainer to serve Nextcloud internally on port 11000 for host Nginx to proxy back to (
proxy_pass http://127.0.0.1:11000).
- Modification: Changed Nextcloud's internal Apache container port to
-
APACHE_IP_BINDING: 127.0.0.1
- Modification: Binds internal Apache strictly to localhost.
- Why: Prevents exposing the unencrypted HTTP interface directly to the external network, ensuring all requests must pass through Nginx.
-
NEXTCLOUD_DATADIR: ${PWD}/ncdata
- Modification: Mapped the data directory to
./ncdatain the local working folder. - Why: Prevents Nextcloud from generating unmanaged anonymous Docker volumes for user files, storing all user data cleanly in a predictable host folder.
- Modification: Mapped the data directory to
-
SKIP_DOMAIN_VALIDATION: "true"
- Modification: Added the skip domain validation environment variable.
- Why: Necessary because your AIO instance sits behind Tailscale and Nginx, preventing Nextcloud's external validation container from pinging port 443 over public WAN.
- Log in to the Cloudflare Dashboard: https://dash.cloudflare.com/
- Click your User Profile icon (top-right) -> My Profile -> API Tokens.
- Click Create Token and select the Edit zone DNS template.
- Configure permissions carefully:
- Permissions:
- Zone -> DNS -> Edit
- Zone -> Zone -> Read (helps Certbot locate the Zone ID automatically)
- Zone Resources:
- Include -> Specific zone -> Select
yourdomain.com
- Include -> Specific zone -> Select
- Permissions:
- Click Continue to summary -> Create Token.
- Copy and save the 40-character token immediately.
- Navigate to
yourdomain.com-> DNS Records. - Add an A Record:
- Name:
nextcloud - IPv4 address:
YOUR_TAILSCALE_IP(e.g.,100.x.y.z) - Proxy status: DNS only (Gray cloud — must not be proxied through Cloudflare).
- Name:
Run the following commands on your host server:
sudo apt update
sudo apt install -y certbot python3-certbot-dns-cloudflare
sudo mkdir -p /etc/letsencrypt
sudo nano /etc/letsencrypt/cloudflare.iniAdd your Cloudflare API token to cloudflare.ini:
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKENSecure the credentials file and run Certbot:
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
--dns-cloudflare-propagation-seconds 20 \
--deploy-hook "systemctl reload nginx" \
-d nextcloud.yourdomain.comCreate the Nginx server block at /etc/nginx/sites-available/nextcloud:
server {
listen 80;
server_name nextcloud.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name nextcloud.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/nextcloud.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/nextcloud.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 10G;
client_body_timeout 3600s;
location / {
proxy_pass http://127.0.0.1:11000;
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;
# WebSocket Support (Required for Collabora Online)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_request_buffering off;
}
}Enable the configuration and reload Nginx:
sudo ln -s /etc/nginx/sites-available/nextcloud /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxStart the mastercontainer:
docker compose upFinal setup steps:
- Access the AIO setup interface at
https://YOUR_TAILSCALE_IP:8080 - Enter your domain name:
nextcloud.yourdomain.com - Select Nextcloud Office (Collabora) during the initial container setup.
If you ever need to perform a complete wipe and restart from scratch, follow the official Nextcloud AIO Reset Guide: https://github.com/nextcloud/all-in-one#how-to-properly-reset-the-instance