This guide walks you through installing and configuring Nextcloud All-in-One (AIO) on an Ubuntu 24.04 LTS (Noble) server, with software RAID, a custom data directory on dedicated storage, and full IPv6 support. It is written from a real Noiz production install (noiz.cloud) running on a dedicated cloud server, and it reflects the specific configuration changes needed to make AIO work reliably on a modern Ubuntu host. The same procedure also works on Ubuntu 22.04 LTS (Jammy), which shares the same networking stack.
Last reviewed: 27 July 2026, against Nextcloud All-in-One (latest stable) on Ubuntu 24.04 LTS. This guide is written for Noiz hosting and documents a real Noiz production deployment. It complements, and does not replace, the official Nextcloud AIO and Docker documentation linked below.
Official Documentation Reference
- Nextcloud AIO repository and documentation: github.com/nextcloud/all-in-one
- Docker Engine install on Ubuntu: docs.docker.com/engine/install/ubuntu
- Docker IPv6 networking: docs.docker.com/engine/daemon/ipv6
- Nextcloud admin manual: docs.nextcloud.com/server/latest/admin_manual
Hardware Setup Assumptions
The following hardware setup is assumed. Adjust to your own where the specifics differ.
- NVMe Drives: Two NVMe SSDs in a RAID 1 array, hosting the operating system, swap, and boot partition.
- HDDs: Four hard disk drives in a RAID 5 array for bulk data storage, providing redundancy with one drive of fault tolerance.
- Network: A network interface with a routed public IPv6
/64from your provider. - Resources: At least 4 CPU cores and 8 GB RAM. A fully featured AIO install can run up to around 14 containers (a master, five core services, and several optional add-ons), so more resources help.
Prerequisites
- OS: Ubuntu 24.04 LTS (Noble), 64-bit. The same steps also work on 22.04 LTS (Jammy).
- Software: Docker Engine from the official Docker APT repository (not the Snap package),
mdadm, and basic system tools. - Network: Public IPv4 and, ideally, a routed IPv6
/64. - Access: Root or sudo on the host.
Step 1: Set Up Software RAID
NVMe RAID 1 is typically pre-configured by the hosting provider. This step covers building the RAID 5 array on the HDDs for Nextcloud data.
1.1 Verify Current Block Devices
lsblk
Confirm the NVMe drives are already part of the existing arrays (/dev/md0 for swap, /dev/md1 for /boot, /dev/md2 for /) and that the HDDs (sda, sdb, sdc, sdd) are unused.
1.2 Create the RAID 5 Array
mdadm --create --verbose /dev/md3 --level=5 --raid-devices=4 /dev/sda /dev/sdb /dev/sdc /dev/sdd
Monitor build progress:
cat /proc/mdstat
Format the array (this may take a long time on large arrays):
mkfs.ext4 /dev/md3
1.3 Mount the Array Persistently
mkdir /data
mount /dev/md3 /data
Get the array UUID:
blkid /dev/md3
Add to /etc/fstab using that UUID (replace with your own):
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /data ext4 defaults 0 0
Test the fstab entry:
mount -a
1.4 Persist the RAID Configuration
mdadm --detail --scan | grep md3 | tee -a /etc/mdadm/mdadm.conf
update-initramfs -u
This ensures the array is assembled correctly on every boot.
Step 2: Install Docker Engine
Install Docker from the official Docker APT repository. Do not use the Ubuntu Snap package. Its sandboxing causes problems with bind mounts, networks, and AIO's container management.
2.1 Add the Docker APT Repository
apt-get update
apt-get install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
2.2 Install Docker
apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
2.3 Verify the Install
docker run hello-world
Step 3: Configure Docker daemon.json (DNS + IPv6)
This is the most important step and the one most likely to be done incorrectly. There are two issues to solve at the Docker daemon level.
3.1 Why DNS Configuration Matters
Ubuntu 24.04 (and 22.04 before it) uses systemd-resolved, which puts 127.0.0.53 in the host's /etc/resolv.conf as a stub resolver. When Docker copies this resolv.conf into containers, the loopback address resolves to the container itself rather than the host's resolver, and DNS resolution silently fails inside every container. The AIO master container's first action on startup is a curl to ghcr.io to check for updates, so this DNS failure causes the master to crash-loop indefinitely.
The fix is to explicitly set DNS servers in daemon.json so every container gets working resolvers regardless of what is in the host's resolv.conf.
3.2 Why the Default IPv6 Example Is Wrong
Many guides (including older versions of this one) use 2001:db8:1::/64 as the fixed-cidr-v6 value. This is the RFC 3849 documentation prefix, which is reserved for use in examples and must never appear on a production network. Containers assigned addresses in this range cannot route to the internet, because no router on the internet will accept traffic from or send traffic to this prefix.
The correct approach is to sub-allocate a slice from your provider's routed /64.
3.3 Determine Your IPv6 Sub-Prefix
Check what IPv6 prefix your host has:
ip -6 addr show scope global
Look for the public IPv6 on your main network interface. On a typical dedicated cloud server it often looks like 2a01:4f8:13b:3004::2/64, meaning your provider has routed 2a01:4f8:13b:3004::/64 to the server. This value is an example only; substitute your provider's actual routed prefix.
Pick a /80 sub-prefix from inside this /64 that does not conflict with the host's own address. A safe pattern is to use a discriminator nibble like :1::/80, giving:
2a01:4f8:13b:3004:1::/80
Replace 2a01:4f8:13b:3004 with your own prefix.
3.4 Write the daemon.json
cat > /etc/docker/daemon.json <<'EOF'
{
"ipv6": true,
"fixed-cidr-v6": "2a01:4f8:13b:3004:1::/80",
"ip6tables": true,
"default-network-opts": {
"bridge": {
"com.docker.network.enable_ipv6": "true"
}
},
"dns": ["1.1.1.1", "8.8.8.8"]
}
EOF
3.5 Apply
systemctl restart docker
3.6 Verify IPv6 Works in a Container
docker run --rm alpine sh -c "ip -6 addr show eth0 && ping6 -c 2 ipv6.google.com"
You should see that the container has a public address in your sub-prefix (for example 2a01:4f8:13b:3004:1::3/80) and that ping6 succeeds with reasonable latency.
Step 4: Install Nextcloud AIO
Deploy the AIO master container with the data directory pointed at the RAID 5 array.
4.1 Prepare the Data Directory
AIO expects the data directory to be owned by UID 33 (which is www-data inside the AIO Nextcloud container):
mkdir -p /data/ncdata
chown 33:0 /data/ncdata
chmod 750 /data/ncdata
4.2 Run the Master Container
docker run -d \
--init \
--sig-proxy=false \
--name nextcloud-aio-mastercontainer \
--restart always \
--publish 80:80 \
--publish 8080:8080 \
--publish 8443:8443 \
--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
--volume /var/run/docker.sock:/var/run/docker.sock:ro \
--env NEXTCLOUD_DATADIR="/data/ncdata" \
ghcr.io/nextcloud-releases/all-in-one:latest
The --restart always flag ensures the master comes back up automatically on reboot or after a Docker daemon restart.
Note on DNS: Because DNS servers were set in daemon.json in Step 3, the master container inherits working DNS automatically. If you did not complete Step 3, you would need to add --dns 1.1.1.1 --dns 8.8.8.8 to this docker run command to avoid the crash-loop described earlier.
4.3 Confirm the Master Is Healthy
docker ps | grep nextcloud-aio-mastercontainer
Expected: Up X seconds (healthy). If you see Restarting, check the logs with docker logs nextcloud-aio-mastercontainer to diagnose.
Step 5: Configure the Firewall
Open the ports AIO needs, plus your chosen SSH port:
ufw allow 80,443,8080,8443,3478,2222/tcp
ufw allow 3478/udp
ufw reload
ufw enable
Adjust 2222 to whichever non-standard port your SSH service listens on. Ensure IPv6 is also enabled in UFW: check /etc/default/ufw for IPV6=yes.
Port summary:
- 80: HTTP (used by the AIO Apache container for ACME/Let's Encrypt challenges and HTTP-to-HTTPS redirects).
- 443: HTTPS (the main Nextcloud entry point, served by the AIO Apache container).
- 8080: AIO management interface (self-signed cert; see the HSTS note below).
- 8443: AIO management interface, alternate.
- 3478/tcp+udp: Nextcloud Talk STUN/TURN.
Step 6: First Access to the AIO Interface
6.1 Access Via Server IP, Not Domain
The AIO management interface uses a self-signed certificate by design. Once Nextcloud is set up and HSTS is enabled on the domain (which it will be), browsers refuse to accept the self-signed cert on port 8080 even though it is a different port. Always access the AIO interface using the server IP, not the domain name:
https://<your-server-ipv4>:8080
For example: https://203.0.113.10:8080 (the address shown here is an example; use your own). Accept the self-signed certificate warning in your browser. Use HTTPS, not HTTP.
6.2 Retrieve the AIO Passphrase
The AIO interface displays a one-time generated passphrase on first run. If you missed it or need to retrieve it later, run the following on the host:
docker exec nextcloud-aio-mastercontainer grep password /mnt/docker-aio-config/data/configuration.json
Save this passphrase in your password manager. It is required for every login to the AIO management interface.
6.3 Complete the Setup Wizard
Log in, enter your Nextcloud domain name, select the optional containers you want (Office, Talk, Whiteboard, and so on), and confirm the data directory shows /data/ncdata.
6.4 Start the Containers
This step is missed easily. After completing the wizard, you must click Start containers in the AIO interface to begin pulling and launching the child containers (Apache, Nextcloud, PostgreSQL, Redis, and any optional add-ons). The initial pull takes 10 to 20 minutes depending on bandwidth, since AIO pulls a dozen or more container images.
Monitor progress in the AIO interface (the indicators turn green as each container becomes healthy) or from the host:
docker ps
Step 7: Post-Installation
7.1 Verify Everything Is Up
docker ps
docker logs nextcloud-aio-mastercontainer
ls -l /data/ncdata
You should see the master container plus its child containers: the five core services (Apache, Nextcloud, PostgreSQL, Redis, and Notify Push) and any optional add-ons you enabled. All should be Up and, eventually, (healthy). The data directory will contain Nextcloud's data files owned by UID 33.
7.2 Enable Backups
Configure the backup target in the AIO interface (a local /mnt/backup path or a remote borg repository). Daily backups are recommended.
7.3 Updates
Future updates of Nextcloud and all child containers are performed via the Stop containers then Start and update containers sequence in the AIO interface. Do not attempt to update child containers directly from the command line, because AIO is the authoritative manager.
7.4 Reboot Persistence
To confirm the install survives a reboot, run reboot on the host and verify that after the host comes back, docker ps shows all containers Up within 1 to 2 minutes. The master comes back via --restart always and starts the children automatically.
Troubleshooting
Master Container Crash-Looping
If docker ps -a | grep mastercontainer shows Restarting:
docker logs --tail 30 nextcloud-aio-mastercontainer
Look for Could not resolve host: ghcr.io, which indicates the DNS problem described in Step 3. Verify /etc/docker/daemon.json contains the "dns" entry and that systemctl restart docker was run after the change.
AIO Interface Unreachable
If https://<server-ip>:8080 times out:
- Confirm UFW allows port 8080 (
ufw status). - Confirm any provider-level firewall (for example a cloud firewall in your provider's control panel) also allows port 8080 inbound.
- Confirm the master container is up and bound to 8080 (
docker ps).
HSTS Blocks the AIO Interface
If your browser shows SEC_ERROR_UNKNOWN_ISSUER with no "Accept Risk and Continue" option when accessing https://<your-nextcloud-domain>:8080, this is HSTS blocking. Use the server's IP address instead of the domain name. HSTS is hostname-bound, so the IP is unaffected.
IPv6 Not Working in Containers
Verify the container actually got an address in your sub-prefix:
docker run --rm alpine ip -6 addr
If the container's IPv6 is in a different range than expected, recheck daemon.json and confirm systemctl restart docker was run. If containers have addresses but cannot ping external IPv6 hosts, check that ip6tables: true is set in daemon.json and that the host itself has working outbound IPv6.
Data Directory Permissions
If AIO complains it cannot write to the data directory:
chown 33:0 /data/ncdata
chmod 750 /data/ncdata
UID 33 corresponds to the www-data user inside the AIO Nextcloud container.
Automation Script
The following script automates Steps 3 and 4 (daemon.json configuration and master container launch). It assumes Docker is already installed (Step 2) and the data partition is mounted at /data (Step 1). Edit the IPV6_PREFIX variable to match your own routed IPv6 sub-prefix before running.
#!/bin/bash
set -e
# === Edit this to match your environment ===
IPV6_PREFIX="2a01:4f8:13b:3004:1::/80"
DATA_DIR="/data/ncdata"
# ============================================
echo "Writing /etc/docker/daemon.json..."
cat > /etc/docker/daemon.json <<EOF
{
"ipv6": true,
"fixed-cidr-v6": "${IPV6_PREFIX}",
"ip6tables": true,
"default-network-opts": {
"bridge": {
"com.docker.network.enable_ipv6": "true"
}
},
"dns": ["1.1.1.1", "8.8.8.8"]
}
EOF
echo "Restarting Docker..."
systemctl restart docker
echo "Verifying IPv6 in a test container..."
docker run --rm alpine sh -c "ip -6 addr show eth0 | grep inet6"
echo "Preparing data directory at ${DATA_DIR}..."
mkdir -p "${DATA_DIR}"
chown 33:0 "${DATA_DIR}"
chmod 750 "${DATA_DIR}"
echo "Launching Nextcloud AIO master container..."
docker run -d \
--init \
--sig-proxy=false \
--name nextcloud-aio-mastercontainer \
--restart always \
--publish 80:80 \
--publish 8080:8080 \
--publish 8443:8443 \
--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
--volume /var/run/docker.sock:/var/run/docker.sock:ro \
--env NEXTCLOUD_DATADIR="${DATA_DIR}" \
ghcr.io/nextcloud-releases/all-in-one:latest
echo "Done. Access the AIO interface at https://$(hostname -I | awk '{print $1}'):8080"
echo "Retrieve the AIO passphrase with:"
echo " docker exec nextcloud-aio-mastercontainer grep password /mnt/docker-aio-config/data/configuration.json"
Save as setup_nextcloud_aio.sh, make it executable, and run:
chmod +x setup_nextcloud_aio.sh
./setup_nextcloud_aio.sh
Support
For Noiz hosting customers, open a support ticket via the client area at www.noiz.co.za with the output of docker ps -a, docker logs nextcloud-aio-mastercontainer, and a description of the symptoms.
