---
title: "How to Install and Configure Nextcloud AIO on Ubuntu 24.04 LTS"
description: "Install Nextcloud All-in-One with Docker on an Ubuntu LTS server, with a software RAID data array, working container DNS and routed IPv6."
url: "https://docs.noiz.ie/nextcloud/how-to-install-and-configure-nextcloud-aio-on-ubuntu-2404-lts/"
section: "Nextcloud"
categories:
  - "Applications > Nextcloud"
last_reviewed: "27 July 2026, against the current Nextcloud All-in-One release on Ubuntu 24"
---

# How to Install and Configure Nextcloud AIO on Ubuntu 24.04 LTS

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 the current Nextcloud All-in-One release 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](https://github.com/nextcloud/all-in-one)
- Docker Engine install on Ubuntu: [docs.docker.com/engine/install/ubuntu](https://docs.docker.com/engine/install/ubuntu/)
- Docker IPv6 networking: [docs.docker.com/engine/daemon/ipv6](https://docs.docker.com/engine/daemon/ipv6/)
- Nextcloud admin manual: [docs.nextcloud.com/server/latest/admin\_manual](https://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 `/64` from 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 the stub resolver `127.0.0.53` in the host's `/etc/resolv.conf`. Docker does not hand that loopback address to containers: it drops loopback nameservers and uses the host's upstream DNS servers instead. Docker's [networking documentation](https://docs.docker.com/engine/network/#dns-services) explains how containers inherit the host's DNS settings. Container DNS therefore depends on how the host's resolver is configured. The AIO master container needs to reach `ghcr.io` when it starts, so if containers cannot resolve names, the master restarts repeatedly.

Setting DNS servers explicitly in `daemon.json` removes that dependency, so every container gets the same known resolvers whatever the host's resolver configuration.

### 3.2 Why the Default IPv6 Example Is Wrong

Many guides publish `2001:db8:1::/64` as a working `fixed-cidr-v6` value. Every address under `2001:db8::/32` belongs to the **RFC 3849 documentation prefix**, which is reserved for examples and must never appear on a production network. Containers given 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.

This guide uses the documentation prefix, such as `2001:db8:13b:3004:1::/80`, only as a placeholder. Copying it into a live `daemon.json` breaks container IPv6 in exactly this way.

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 `2001:db8:13b:3004::2/64`, meaning your provider has routed `2001:db8: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:

```
2001:db8:13b:3004:1::/80
```

Replace `2001:db8:13b:3004` with your own prefix.

### 3.4 Write the daemon.json

Before you run this, replace `2001:db8:13b:3004` in the `fixed-cidr-v6` line with your own routed prefix from Step 3.3. The value shown is a documentation placeholder and does not route.

```
cat > /etc/docker/daemon.json <<'EOF'
{
    "ipv6": true,
    "fixed-cidr-v6": "2001:db8: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 `2001:db8: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 repeated restarts described in Step 3.1.

### 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`.

**Note:** ports published by Docker containers bypass UFW, because Docker routes container traffic before UFW's rules are applied. The AIO ports stay reachable whatever `ufw status` shows, so UFW only protects services running directly on the host. To restrict a published port, use your provider's network firewall or follow Docker's [packet filtering and firewalls](https://docs.docker.com/engine/network/packet-filtering-firewalls/) guidance.

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:

- UFW does not decide whether 8080 is reachable: the port is published by Docker, which bypasses UFW (see the note in Step 5). Check the provider-level firewall instead.
- 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 below is a documentation placeholder (RFC 3849, 2001:db8::/32).
# Replace 2001:db8:13b:3004 with your own routed prefix, or container IPv6 will not route.
IPV6_PREFIX="2001:db8: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
```

## Related Guides

- [How to Update Nextcloud All-in-One and Its Apps](/nextcloud/how-to-update-nextcloud-all-in-one-and-its-apps/)
- [How to Back Up and Restore Nextcloud All-in-One (AIO)](/nextcloud/how-to-back-up-and-restore-nextcloud-all-in-one/)
- [How to Migrate from Dropbox to Nextcloud All-in-One with rclone](/nextcloud/how-to-migrate-from-dropbox-to-nextcloud-all-in-one-with-rclone/)

## Support

For Noiz hosting customers, open a support ticket via the client area at [www.noiz.co.za](https://www.noiz.co.za) with the output of `docker ps -a`, `docker logs nextcloud-aio-mastercontainer`, and a description of the symptoms.

---
Source: https://docs.noiz.ie/nextcloud/how-to-install-and-configure-nextcloud-aio-on-ubuntu-2404-lts/
