AIO fails to install (iptables, domain not reachable)

Support intro

Sorry to hear you’re facing problems. :slightly_frowning_face:

The community help forum (help.nextcloud.com) is for home and non-enterprise users. Support is provided by other community members on a best effort / “as available” basis. All of those responding are volunteering their time to help you.

If you’re using Nextcloud in a business/critical setting, paid and SLA-based support services can be accessed via portal.nextcloud.com where Nextcloud engineers can help ensure your business keeps running smoothly.

Getting help

In order to help you as efficiently (and quickly!) as possible, please fill in as much of the below requested information as you can.

Before clicking submit: Please check if your query is already addressed via the following resources:

(Utilizing these existing resources is typically faster. It also helps reduce the load on our generous volunteers while elevating the signal to noise ratio of the forums otherwise arising from the same queries being posted repeatedly).

Some or all of the below information will be requested if it isn’t supplied; for fastest response please provide as much as you can. :heart:

The Basics

  • Nextcloud Server version (e.g., 29.x.x):
    • Nextcloud AIO v12.8.0
  • Operating system and version (e.g., Ubuntu 24.04):
    • Alpine Linux v3.23 x86_64
  • Web server and version (e.g, Apache 2.4.25):
    • N/A
  • Reverse proxy and version _(e.g. nginx 1.27.2)
    • none
  • PHP version (e.g, 8.3):
    • N/A
  • Is this the first time you’ve seen this error? (Yes / No):
    • yes
  • When did this problem seem to first start?
    • installation
  • Installation method (e.g. AlO, NCP, Bare Metal/Archive, etc.)
    • AIO
  • Are you using CloudfIare, mod_security, or similar? (Yes / No)
    • no

Summary of the issue you are facing:

I am trying to install Nextcloud using AIO, however when I enter the domain name, I get the error message.

The domain is not reachable on Port 443 from within this container. Have you opened port 443/tcp in your router/firewall? If yes is the problem most likely that the router or firewall forbids local access to your domain. Or in other words: NAT loopback (Hairpinning) does not seem to work in your network. You can work around that by setting up a local DNS server and utilizing Split-Brain-DNS and configuring the daemon.json file of your docker daemon to use the local DNS server.

I am using iptables to whitelist ports on the server for security reasons. Here is my configuration. I’m, sorry for the mess, I only exported these out of iptables and I’m not using any abstraction on top of it, so docker has created most of these rules. My intention is to only allow ports 22,80,443,8443 and to have a NAT for my Wireguard VPN network (wg0, UDP/51820, 192.168.61.0/24). Note that I am already opening the setup using my domain name on port 8443.

# Generated by iptables-save v1.8.11 (nf_tables) on Sun Apr  5 20:25:05 2026
*raw
:PREROUTING ACCEPT [3149:826003]
:OUTPUT ACCEPT [0:0]
[0:0] -A PREROUTING -d 172.19.0.2/32 ! -i br-3530f247a230 -j DROP
[0:0] -A PREROUTING -d 172.19.0.3/32 ! -i br-3530f247a230 -j DROP
COMMIT
# Completed on Sun Apr  5 20:25:05 2026
# Generated by iptables-save v1.8.11 (nf_tables) on Sun Apr  5 20:25:05 2026
*filter
:INPUT DROP [576:59436]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [251:44783]
:DOCKER - [0:0]
:DOCKER-BRIDGE - [0:0]
:DOCKER-CT - [0:0]
:DOCKER-FORWARD - [0:0]
:DOCKER-INTERNAL - [0:0]
:DOCKER-USER - [0:0]
[154:13274] -A INPUT -i lo -j ACCEPT
[4246:668181] -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
[419:24304] -A INPUT -i eth0 -p tcp -m multiport --dports 22,80,443,8443 -j ACCEPT
[0:0] -A INPUT -i eth0 -p udp -m udp --dport 51820 -j ACCEPT
[4:200] -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
[192:40708] -A FORWARD -j DOCKER-USER
[192:40708] -A FORWARD -j DOCKER-FORWARD
[0:0] -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
[0:0] -A FORWARD -i wg0 -o eth0 -j ACCEPT
[0:0] -A FORWARD -i eth0 -o wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
[1:60] -A DOCKER -d 172.19.0.3/32 ! -i br-3530f247a230 -o br-3530f247a230 -p tcp -m tcp --dport 443 -j ACCEPT
[0:0] -A DOCKER -d 172.19.0.2/32 ! -i br-3530f247a230 -o br-3530f247a230 -p tcp -m tcp --dport 8443 -j ACCEPT
[6:312] -A DOCKER -d 172.19.0.2/32 ! -i br-3530f247a230 -o br-3530f247a230 -p tcp -m tcp --dport 8080 -j ACCEPT
[7:348] -A DOCKER -d 172.19.0.2/32 ! -i br-3530f247a230 -o br-3530f247a230 -p tcp -m tcp --dport 80 -j ACCEPT
[0:0] -A DOCKER ! -i br-25f773566921 -o br-25f773566921 -j DROP
[0:0] -A DOCKER ! -i docker0 -o docker0 -j DROP
[0:0] -A DOCKER ! -i br-3530f247a230 -o br-3530f247a230 -j DROP
[0:0] -A DOCKER-BRIDGE -o br-25f773566921 -j DOCKER
[0:0] -A DOCKER-BRIDGE -o docker0 -j DOCKER
[14:720] -A DOCKER-BRIDGE -o br-3530f247a230 -j DOCKER
[14:7017] -A DOCKER-CT -o br-25f773566921 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
[0:0] -A DOCKER-CT -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
[69:18996] -A DOCKER-CT -o br-3530f247a230 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
[192:40708] -A DOCKER-FORWARD -j DOCKER-CT
[109:14695] -A DOCKER-FORWARD -j DOCKER-INTERNAL
[109:14695] -A DOCKER-FORWARD -j DOCKER-BRIDGE
[16:2653] -A DOCKER-FORWARD -i br-25f773566921 -j ACCEPT
[0:0] -A DOCKER-FORWARD -i docker0 -j ACCEPT
[79:11322] -A DOCKER-FORWARD -i br-3530f247a230 -j ACCEPT
COMMIT
# Completed on Sun Apr  5 20:25:05 2026
# Generated by iptables-save v1.8.11 (nf_tables) on Sun Apr  5 20:25:05 2026
*nat
:PREROUTING ACCEPT [8266:2250104]
:INPUT ACCEPT [17:1004]
:OUTPUT ACCEPT [24:1566]
:POSTROUTING ACCEPT [38:2286]
:DOCKER - [0:0]
[535:41542] -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
[0:0] -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
[2:120] -A POSTROUTING -s 172.19.0.0/16 ! -o br-3530f247a230 -j MASQUERADE
[0:0] -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
[1:60] -A POSTROUTING -s 172.18.0.0/16 ! -o br-25f773566921 -j MASQUERADE
[0:0] -A POSTROUTING -s 192.168.61.0/24 -o eth0 -j MASQUERADE
[7:348] -A DOCKER ! -i br-3530f247a230 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.19.0.2:80
[6:312] -A DOCKER ! -i br-3530f247a230 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.19.0.2:8080
[0:0] -A DOCKER ! -i br-3530f247a230 -p tcp -m tcp --dport 8443 -j DNAT --to-destination 172.19.0.2:8443
[1:60] -A DOCKER ! -i br-3530f247a230 -p tcp -m tcp --dport 443 -j DNAT --to-destination 172.19.0.3:443
COMMIT
# Completed on Sun Apr  5 20:25:05 2026

Steps to replicate it (hint: details matter!):

  1. Setup Alpine Virtual

  2. Configure IP-Tables

  3. Start the default docker-compose from the git repository

Log entries

The installation did not start yet, thus there are no logs.

Configuration

The AIO setup fails before any configuration could be done.

Tips for increasing the likelihood of a response

  • Use the preformatted text formatting option in the editor for all log entries and configuration output.
  • If screenshots are useful, feel free to include them.
    • If possible, also include key error output in text form so it can be searched for.
  • Try to edit log output only minimally (if at all) so that it can be ran through analyzers / formatters by those trying to help you.

This looks more like an AIO-specific install validation issue than a raw Nextcloud issue.

The error message is the usual AIO check that your domain must be reachable on port 443 from inside the container, and that often runs into NAT loopback / hairpin NAT / split-DNS problems depending on the network and firewall setup. In your case, the custom iptables policy may be contributing, but the main blocker appears to be that AIO cannot validate the domain path it expects during setup. The AIO docs and related community guidance mention exactly this kind of behavior for domain validation, especially around NAT loopback and split-brain DNS scenarios. (help.nextcloud.com, help.nextcloud.com, github.com)

So I’d probably test in this order:

  1. verify the domain resolves correctly from the host and from inside the AIO-related container
  2. confirm that port 443 is actually reachable from inside the container to the public hostname
  3. check whether your network/router supports hairpin NAT, or use split-brain DNS if that is your intended design
  4. if you are using AIO behind another proxy or custom network path, follow the reverse-proxy mode documentation rather than the default install flow

If you decide that AIO’s validation flow is more trouble than it is worth for your setup, I put together a community Docker-based stack here:

https://github.com/iamjavadali/nextcloudpi

It is not AIO and not an official Nextcloud / NextcloudPi release, but it may be useful if you want a more manual, modular Docker deployment without the AIO installer/domain-validation path. So I would treat it more as an alternative deployment option than a direct fix for this specific AIO error.

If you want, I can also share the exact checks I would run first for DNS, hairpin NAT, and container-side connectivity.

  1. On Host: wget -qO- https://nextcloud.colintimbarndt.de succeeds and gives me a hex string
    In Container: docker exec -it nextcloud-aio-domaincheck /usr/bin/wget -qO- https://nextcloud.colintimbarndt.de times out, request is likely dropped. I also tried another domain to an external server, which works.
  2. The container cannot reach port 443 while the host can
  3. How can I do this? I am using plain Docker inside an Alpine Linux VM. No dedicated router is used.
  4. I am now using my own Caddy container (in a separate compose file) and successfully hosting Immich using it. I’ve configured the docker-compose accordingly, which is reflected in the web-UI, but the problem remains.

I think that it has something to do with my iptables firewall rules (it’s dropping by default), but I don’t know which rule I’d need to add to solve the problem.

Thank you for you help

I’m experimenting with different rules. I can get the request to work by using this rule:

iptables -A INPUT -i br-3530f247a230 -j ACCEPT

However, I don’t want to use this rule permanently as it is hard-coding a docker interface and is just a blanket allow.

I’ve read more into what Hairpin NAT actually is here: https://serverfault.com/questions/55611/loopback-to-forwarded-public-ip-address-from-local-network-hairpin-nat/557776#557776

TLDR: The container can talk to the host using the public IP address. DNAT is rewriting the destination IP to that of the Caddy container, but it keeps the source address intact. Caddy then sends a reply directly to the container without going back through the NAT, thus the answer is lost.

The client thus sends a packet to an external IP address, but gets a reply from an internal IP address. It has no idea that the two packets are part of the same conversation, so no conversation happens.

Hairpin NAT therefore is a combination of SNAT and DNAT where the source address is rewritten to be the gateway address such that the reply can be translated appropriately.

Why you may need "Hairpin NAT" (NAT Reflection, NAT Loopback) for AIO/NC - #10 by Iv_Dark mentions that I would need Hairpin NAT, but I can’t figure out which iptables rules I need to create to make it work.

You have identified the core issue correctly: hairpin NAT. The AIO container tries to reach your domain via the public IP, the router DNATs it back to the host, but the return traffic gets confused because the source and destination are on the same network.

Two practical fixes:

Option 1 - Split DNS (cleanest): Set up a DNS override on your local network so that your domain resolves to the host’s local IP (e.g. 192.168.x.x) instead of the public IP. If you run Pi-hole, AdGuard Home, or any local DNS, add a custom DNS record for your Nextcloud domain pointing to the LAN IP. This way the AIO container never tries to go through the public IP at all.

If you use the host’s /etc/hosts, that won’t help because Docker containers have their own DNS resolution. Instead, pass it to the AIO container with Docker’s --add-host flag:

--add-host yourdomain.com:192.168.x.x

Or in docker-compose:

extra_hosts:
  - "yourdomain.com:192.168.x.x"

Option 2 - Enable hairpin NAT on your router: Some routers call this “NAT loopback” or “NAT reflection”. If your router supports it, enabling it fixes the problem at the network level without needing DNS overrides. Check your router’s NAT settings.

The iptables errors you saw during AIO installation are a separate issue. AIO needs iptables to set up its own container networking rules. Make sure iptables is installed on the host and that Docker has permission to manage iptables rules (the default unless you set "iptables": false in Docker’s daemon.json).

My Nextcloud container is running on a server that is directly connected to the internet with a public IPv4 address (and IPv6). There is no local IP address except for 127.0.0.1. Which address do I use in that case? 127.0.0.1 would just point to the container itself and not the host.

I don’t know why, but I’ve now fixed the nextcloud network to be interface “br_nextcloud” and added this rule:

iptables -A INPUT -i br_nextcloud -m addrtype --dst-type LOCAL -j ACCEPT

Which magically fixes the problem. I don’t know why this works and I would like to know if this is a hack or an actual solution. I did not add any Hairpin NAT here.