Running Nextcloud locally inside a Proxmox LXC, with Cloudflare TLS and Reverse Proxy
- Published on
- Authors

- Name
- Jerry
This guide documents my full setup experience running Nextcloud All‑in‑One (AIO) inside a Proxmox LXC container on my home server.
The challenge:
Nextcloud AIO requires HTTPS and a valid TLS certificate, even for local-only deployments. To avoid exposing my services publicly, I needed a way to generate valid certificates for a purely local environment.
The solution stack I used:
- Pi-hole --- Local DNS server for internal domain resolution
- Caddy (Cloudflare DNS challenge) --- Automatic and trusted TLS certificates
- Cloudflare --- DNS provider
- WireGuard VPN --- Remote access to my home network without exposing services
- rclone --- Mount Google Drive and OneDrive as external storage for Nextcloud
The final result:
A fully local, HTTPS-secure, remotely accessible (via VPN) personal cloud running on Nextcloud AIO.
Why This Approach?
I already run WireGuard VPN, Home Assistant, and my 3D printer interfaces inside my home network.
I do not want to expose any of these to the public internet.
Since Nextcloud AIO forces HTTPS and domain validation, local deployments become complicated.
A post from user greylinux1 on the Nextcloud forum inspired this setup, using Pi-hole + Caddy + Cloudflare DNS challenge to generate valid certificates locally.
Prerequisites
- A domain hosted on Cloudflare
- A working Pi-hole instance (local DNS)
- A working WireGuard server (for remote access)
- Proxmox VE 9.x
- Basic familiarity with Docker and Linux
Step 1: Proxmox Host Setup
Create the LXC Container
My configuration:
- Ubuntu template
- Unprivileged container (recommended)
- Disk: 32 GB
- CPU: 4 cores
- RAM: 8 GB
- Swap: 4 GB
- Features: enable FUSE
Create storage directory on host:
mkdir -p /mnt/data/nextcloud
chmod 770 /mnt/data/nextcloud
chown 100000:100000 /mnt/data/nextcloud
Load FUSE & fix Redis overcommit warning:
modprobe fuse
sysctl vm.overcommit_memory=1
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
Add mount point to CT config:
# add this line to /etc/pve/lxc/<CTID>.conf
mp0: /mnt/data/nextcloud,mp=/data/nextcloud
Step 2: Configure the LXC Container
Install FUSE & enable allow_other
apt update && apt install -y fuse3 fuse fusermount3
Edit /etc/fuse.conf:
user_allow_other
Step 3: rclone (Optional: Cloud Storage Integration)
Install rclone:
Configure:
rclone config
Test:
rclone ls gdrive: | head
rclone ls onedrive: | head
Create systemd services for automatic mounts
mkdir -p /data/gdrive /data/onedrive
Create /etc/systemd/system/[email protected]:
[Unit]
Description=Rclone mount for %i
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
User=root
Group=root
ExecStart=/usr/bin/rclone mount %i: /data/%i \
--config=/root/.config/rclone/rclone.conf \
--cache-dir=/root/.cache/rclone \
--allow-other \
--vfs-cache-mode writes \
--vfs-cache-max-size 5G
ExecStop=/usr/bin/fusermount3 -u /data/%i
Restart=on-failure
RestartSec=10
TimeoutStartSec=120
[Install]
WantedBy=multi-user.target
Enable:
systemctl daemon-reload
systemctl enable --now rclone-mount@gdrive
systemctl enable --now rclone-mount@onedrive
Step 4: Deploy Nextcloud AIO + Caddy (Cloudflare DNS)
To create your Cloudflare token, follow this guide
docker-compose.yml:
services:
nextcloud-aio-mastercontainer:
image: ghcr.io/nextcloud-releases/all-in-one:latest
init: true
restart: always
container_name: nextcloud-aio-mastercontainer
volumes:
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- 8080:8080
environment:
- NEXTCLOUD_DATADIR=/ncdata
- NEXTCLOUD_MOUNT=/data/
- SKIP_DOMAIN_VALIDATION=true
- APACHE_PORT=11000
- APACHE_IP_BINDING=127.0.0.1
network_mode: bridge
depends_on:
- caddy
caddy:
image: ghcr.io/caddybuilds/caddy-cloudflare:latest
container_name: nextcloud-caddy
restart: unless-stopped
cap_add:
- NET_ADMIN
ports:
- '80:80'
- '443:443'
- '443:443/udp'
environment:
- CLOUDFLARE_API_TOKEN=<Your Cloudflare Token>
- NC_DOMAIN=<Your domain>
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./caddy_data:/data
- ./caddy_config:/config
- ./caddy_certs:/certs
- ./caddy_sites:/srv
network_mode: 'host'
volumes:
nextcloud_aio_mastercontainer:
name: nextcloud_aio_mastercontainer
caddy_certs:
caddy_config:
caddy_data:
caddy_sites:
Step 5: First Access & Pi-hole DNS
Access AIO setup:
In Pi-hole → Local DNS Records, add:
your domain : Nextcloud LXC IP
Once Caddy obtains certificates and AIO finishes provisioning all containers, you can access your cloud at:
Important Pitfalls
Nextcloud AIO uses environment variables instead of typical Docker volume mounts:
NEXTCLOUD_DATADIRNEXTCLOUD_MOUNT
If you ever reset your instance:
You must clear the directory mapped to NEXTCLOUD_DATADIR on the host, otherwise the nextcloud-aio-nextcloud container will fail to start.
Reference:
https://github.com/nextcloud/all-in-one?tab=readme-ov-file#how-to-properly-reset-the-instance
References
这篇文章记录我在家庭服务器上折腾 Nextcloud All-in-One (AIO) 的完整过程。
目标:
- 在 Proxmox VE 的 LXC 容器中本地运行 Nextcloud AIO,不对公网暴露,通过局域网 + VPN 使用,同时又能保持完整的 HTTPS 支持(因为 AIO 强制要求 TLS)。
为了解决本地环境下的 TLS 证书问题,我采用了以下方案:
- Pi-hole 做本地 DNS,将自定义域名解析到内网地址
- Caddy(Cloudflare DNS challenge) 获取可信证书
- Cloudflare 托管域名
- WireGuard 让外网使用手机/笔电安全访问家庭网络
- rclone 将 Google Drive 和 OneDrive 挂载为 Nextcloud 扩展存储
最终效果:
一个 无需暴露公网、通过 HTTPS 安全访问、全局可用的家庭云盘。
为什么采用这个方案?
我家里已经部署了 WireGuard VPN 和一些自托管服务(Home Assistant、3D 打印机控制界面等),为了安全我不想把这些服务暴露到公网上。
Nextcloud AIO 默认要求域名 + TLS,不支持裸IP,导致本地部署变得麻烦。我在 Nextcloud 论坛看到 greylinux1的教程,受到启发,于是我根据自己的环境做了适配,并记录成本文。
前置条件(Prerequisite)
- 你有一个托管在 Cloudflare 的域名
- Pi-hole(本地 DNS,用于域名指向内网,安装和基础设置本文不展开)
- WireGuard(用于外网访问,本文不展开)
- Proxmox VE 9.x 环境
Step 1:Proxmox 主机配置
创建 LXC(CT)
我使用的配置:
- Ubuntu 模板
- unprivileged 容器(推荐)
- 32 GB 磁盘
- CPU:4 core
- Memory:8 GB
- Swap:4 GB
- Enable:FUSE
创建存储目录:
mkdir -p /mnt/data/nextcloud
chmod 770 /mnt/data/nextcloud
chown 100000:100000 /mnt/data/nextcloud
加载 FUSE 和内存设置(避免Redis容器警告):
modprobe fuse
sysctl vm.overcommit_memory=1
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
在 CT 配置文件加入挂载:
#/etc/pve/lxc/<CTID>.conf
mp0: /mnt/data/nextcloud,mp=/data/nextcloud
Step 2:配置 LXC(容器内部)
安装 FUSE 并启用 allow_other
apt update && apt install -y fuse3 fuse fusermount3
编辑 /etc/fuse.conf:
user_allow_other (删掉注释,启用)
Step 3:安装 rclone(可选:扩展存储)
安装 rclone 方法参考官网 https://rclone.org/install/
配置:
rclone config
测试(网盘名字是自己定义,例如 gdrive 和 onedrive):
rclone ls gdrive: | head
rclone ls onedrive: | head
rclone systemd 自动挂载
mkdir -p /data/gdrive /data/onedrive
创建 /etc/systemd/system/[email protected]:
[Unit]
Description=Rclone mount for %i
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
User=root
Group=root
ExecStart=/usr/bin/rclone mount %i: /data/%i \
--config=/root/.config/rclone/rclone.conf \
--cache-dir=/root/.cache/rclone \
--allow-other \
--vfs-cache-mode writes \
--vfs-cache-max-size 5G
ExecStop=/usr/bin/fusermount3 -u /data/%i
Restart=on-failure
RestartSec=10
TimeoutStartSec=120
[Install]
WantedBy=multi-user.target
启用服务:
systemctl daemon-reload
systemctl enable --now rclone-mount@gdrive
systemctl enable --now rclone-mount@onedrive
Step 4:部署 Nextcloud AIO + Caddy + Cloudflare
参考该教程创建Cloudflare token
docker-compose.yml:
services:
nextcloud-aio-mastercontainer:
image: ghcr.io/nextcloud-releases/all-in-one:latest
init: true
restart: always
container_name: nextcloud-aio-mastercontainer
volumes:
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- 8080:8080
environment:
- NEXTCLOUD_DATADIR=/ncdata
- NEXTCLOUD_MOUNT=/data/
- SKIP_DOMAIN_VALIDATION=true
- APACHE_PORT=11000
- APACHE_IP_BINDING=127.0.0.1
network_mode: bridge
depends_on:
- caddy
caddy:
image: ghcr.io/caddybuilds/caddy-cloudflare:latest
container_name: nextcloud-caddy
restart: unless-stopped
cap_add:
- NET_ADMIN
ports:
- '80:80'
- '443:443'
- '443:443/udp'
environment:
- CLOUDFLARE_API_TOKEN=<Your Cloudflare Token>
- NC_DOMAIN=<Your domain>
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./caddy_data:/data
- ./caddy_config:/config
- ./caddy_certs:/certs
- ./caddy_sites:/srv
network_mode: 'host'
volumes:
nextcloud_aio_mastercontainer:
name: nextcloud_aio_mastercontainer
caddy_certs:
caddy_config:
caddy_data:
caddy_sites:
Step 5:首次访问 & Pi-hole 配置
访问初始化界面:
在 Pi-hole 添加 Local DNS record:
你的域名 : Nextcloud LXC IP
当 Caddy 获取到证书,AIO 完成初始化后,你就可以通过之前设定的域名地址访问你的Nextcloud云盘了:
遇到的坑(非常重要)
Nextcloud AIO 的数据持久化通过环境变量实现:
NEXTCLOUD_DATADIRNEXTCLOUD_MOUNT
如果要 重置实例,必须清空 NEXTCLOUD_DATADIR 对应宿主机目录,否则 nextcloud 容器会无法启动。
重置实例时参考官方文档,记得要做第10步。