diff --git a/php/public/index.php b/php/public/index.php index 4d409952..f975263b 100644 --- a/php/public/index.php +++ b/php/public/index.php @@ -97,6 +97,7 @@ $app->get('/containers', function ($request, $response, $args) use ($container) 'daily_backup_time' => $configurationManager->GetDailyBackupTime(), 'is_daily_backup_running' => $configurationManager->isDailyBackupRunning(), 'timezone' => $configurationManager->GetTimezone(), + 'skip_domain_validation' => $configurationManager->shouldDomainValidationBeSkipped(), ]); })->setName('profile'); $app->get('/login', function ($request, $response, $args) use ($container) { diff --git a/php/src/Data/ConfigurationManager.php b/php/src/Data/ConfigurationManager.php index a7423075..584f9e46 100644 --- a/php/src/Data/ConfigurationManager.php +++ b/php/src/Data/ConfigurationManager.php @@ -198,67 +198,71 @@ class ConfigurationManager throw new InvalidSettingConfigurationException("Please enter a domain and not an IP-address!"); } - $dnsRecordIP = gethostbyname($domain); - if ($dnsRecordIP === $domain) { - $dnsRecordIP = ''; - } + // Skip domain validation if opted in to do so + if ($this->shouldDomainValidationBeSkipped()) { - if (empty($dnsRecordIP)) { - $record = dns_get_record($domain, DNS_AAAA); - if (!empty($record)) { - $dnsRecordIP = $record[0]['ipv6']; + $dnsRecordIP = gethostbyname($domain); + if ($dnsRecordIP === $domain) { + $dnsRecordIP = ''; } - } - // Validate IP - if(!filter_var($dnsRecordIP, FILTER_VALIDATE_IP)) { - throw new InvalidSettingConfigurationException("DNS config is not set for this domain or the domain is not a valid domain! (It was found to be set to '" . $dnsRecordIP . "')"); - } + if (empty($dnsRecordIP)) { + $record = dns_get_record($domain, DNS_AAAA); + if (!empty($record)) { + $dnsRecordIP = $record[0]['ipv6']; + } + } - // Get the apache port - $port = $this->GetApachePort(); + // Validate IP + if (!filter_var($dnsRecordIP, FILTER_VALIDATE_IP)) { + throw new InvalidSettingConfigurationException("DNS config is not set for this domain or the domain is not a valid domain! (It was found to be set to '" . $dnsRecordIP . "')"); + } - if (!filter_var($dnsRecordIP, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { - $errorMessage = "It seems like the ip-address is set to an internal or reserved ip-address. This is not supported. (It was found to be set to '" . $dnsRecordIP . "')"; - if ($port === '443') { - throw new InvalidSettingConfigurationException($errorMessage); + // Get the apache port + $port = $this->GetApachePort(); + + if (!filter_var($dnsRecordIP, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { + $errorMessage = "It seems like the ip-address is set to an internal or reserved ip-address. This is not supported. (It was found to be set to '" . $dnsRecordIP . "')"; + if ($port === '443') { + throw new InvalidSettingConfigurationException($errorMessage); + } else { + error_log($errorMessage); + } + } + + // Check if port 443 is open + $connection = @fsockopen($domain, 443, $errno, $errstr, 10); + if ($connection) { + fclose($connection); } else { - error_log($errorMessage); + throw new InvalidSettingConfigurationException("The server is not reachable on Port 443. You can verify this e.g. with 'https://portchecker.co/' by entering your domain there as ip-address and port 443 as port."); } - } - // Check if port 443 is open - $connection = @fsockopen($domain, 443, $errno, $errstr, 10); - if ($connection) { - fclose($connection); - } else { - throw new InvalidSettingConfigurationException("The server is not reachable on Port 443. You can verify this e.g. with 'https://portchecker.co/' by entering your domain there as ip-address and port 443 as port."); - } + // Get Instance ID + $instanceID = $this->GetSecret('INSTANCE_ID'); - // Get Instance ID - $instanceID = $this->GetSecret('INSTANCE_ID'); + // set protocol + if ($port !== '443') { + $protocol = 'https://'; + } else { + $protocol = 'http://'; + } - // set protocol - if ($port !== '443') { - $protocol = 'https://'; - } else { - $protocol = 'http://'; - } + // Check if response is correct + $ch = curl_init(); + $testUrl = $protocol . $domain . ':443'; + curl_setopt($ch, CURLOPT_URL, $testUrl); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $response = (string)curl_exec($ch); + # Get rid of trailing \n + $response = str_replace("\n", "", $response); - // Check if response is correct - $ch = curl_init(); - $testUrl = $protocol . $domain . ':443'; - curl_setopt($ch, CURLOPT_URL, $testUrl); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - $response = (string)curl_exec($ch); - # Get rid of trailing \n - $response = str_replace("\n", "", $response); - - if ($response !== $instanceID) { - error_log('The response of the connection attempt to "' . $testUrl . '" was: ' . $response); - error_log('Expected was: ' . $instanceID); - error_log('The error message was: ' . curl_error($ch)); - throw new InvalidSettingConfigurationException("Domain does not point to this server or the reverse proxy is not configured correctly. See the mastercontainer logs for more details. ('sudo docker logs -f nextcloud-aio-mastercontainer')"); + if ($response !== $instanceID) { + error_log('The response of the connection attempt to "' . $testUrl . '" was: ' . $response); + error_log('Expected was: ' . $instanceID); + error_log('The error message was: ' . curl_error($ch)); + throw new InvalidSettingConfigurationException("Domain does not point to this server or the reverse proxy is not configured correctly. See the mastercontainer logs for more details. ('sudo docker logs -f nextcloud-aio-mastercontainer')"); + } } // Write domain @@ -549,4 +553,12 @@ class ConfigurationManager $config['timezone'] = ''; $this->WriteConfig($config); } + + public function shouldDomainValidationBeSkipped() : bool { + $envVariableOutput = getenv('SKIP_DOMAIN_VALIDATION'); + if ($envVariableOutput !== false) { + return true; + } + return false; + } } diff --git a/php/templates/containers.twig b/php/templates/containers.twig index 662f003f..30700de3 100644 --- a/php/templates/containers.twig +++ b/php/templates/containers.twig @@ -79,14 +79,19 @@ Nextcloud AIO stands for Nextcloud All In One and provides easy deployment and maintenance with most features included in this one Nextcloud instance.

New AIO instance

Please type in the domain that will be used for Nextcloud if you want to create a new instance:

+ {% if skip_domain_validation == true %} + Please Note: The domain validation is disabled so any domain will be accepted here! So make sure that you do not make a typo here as you will not be able to change it afterwards!

+ {% endif %}
- Make sure that this server is reachable on Port 443 and you've correctly set up the DNS config for the domain that you enter.

- If you have a dynamic IP-address, you can use e.g. DDclient with a compatible domain provider for DNS updates.

+ {% if skip_domain_validation == false %} + Make sure that this server is reachable on Port 443 and you've correctly set up the DNS config for the domain that you enter.

+ If you have a dynamic IP-address, you can use e.g. DDclient with a compatible domain provider for DNS updates.

+ {% endif %}

Restore former AIO instance from backup

You can alternatively restore a former AIO instance from backup.

diff --git a/readme.md b/readme.md index c76a1a16..aa1ee54f 100644 --- a/readme.md +++ b/readme.md @@ -103,6 +103,9 @@ docker volume create ^ ``` (The value `/host_mnt/c/your/backup/path` in this example would be equivalent to `C:\your\backup\path` on the Windows host. So you need to translate the path that you want to use into the correct format.) ⚠️️ **Attention**: Make sure that the path exists on the host before you create the volume! Otherwise everything will bug out! +### How to run it behind a Cloudflare Argo Tunnel? +Although it does not seems like it is the case but from AIO perspective a Cloudflare Argo Tunnel works like a reverse proxy. So please follow the [reverse proxy documentation](./reverse-proxy.md) where is documented how to make it run behind a Cloudflare Argo Tunnel. + ### How to resolve firewall problems with Fedora Linux, RHEL OS, CentOS, SUSE Linux and others? It is known that Linux distros that use [firewalld](https://firewalld.org) as their firewall daemon have problems with docker networks. In case the containers are not able to communicate with each other, you may change your firewalld to use the iptables backend by running: ``` diff --git a/reverse-proxy.md b/reverse-proxy.md index 1386c06a..d7dcc81b 100644 --- a/reverse-proxy.md +++ b/reverse-proxy.md @@ -91,6 +91,19 @@ Of course you need to modify `` to the domain on which you want +### Cloudflare Argo Tunnel + +
+ +click here to expand + +Although it does not seems like it is the case but from AIO perspective a Cloudflare Argo Tunnel works like a reverse proxy. Here is how to make it work: + +1. Install the Cloudflare Argo Tunnel on the same machine where AIO will be running on and point the Argo Tunnel with the domain that you want to use for AIO to `localhost:11000`. If the Argo Tunnel is running on a different machine, you can alternatively instead of `localhost` use the ip-address that is displayed after running the following command on the host OS: `ip a | grep "scope global" | head -1 | awk '{print $2}' | sed 's|/.*||'` (the command only works on Linux) +2. Now continue with [point 2](#2-use-this-startup-command) but additionally, add `-e SKIP_DOMAIN_VALIDATION=true` to the docker run command which will disable the dommain validation (because it is known that the domain validation will not work behind a Cloudflare Argo Tunnel). So you need to ensure yourself that you've configured everything correctly. + +
+ ### Nginx
@@ -307,3 +320,5 @@ If something does not work, follow the steps below: 1. Make sure that the mastercontainer is able to spawn other containers. You can do so by checking that the mastercontainer indeed has access to the Docker socket which might not be positioned in one of the suggested directories like `/var/run/docker.sock` but in a different directory, based on your OS and the way how you installed Docker. The mastercontainer logs should help figuring this out. You can have a look at them by running `sudo docker logs nextcloud-aio-mastercontainer` after the container is started the first time. 1. Check if after the mastercontainer was started, the reverse proxy if running inside a container, can reach the provided apache port. You can test this by running `nc -z localhost 11000; echo $?` from inside the reverse proxy container. If the output is `0`, everything works. Alternatively you can of course use instead of `localhost` the ip-address of the host here for the test. 1. Try to configure everything from scratch if it still does not work! +1. As last resort, you may disable the domain validation by adding `-e SKIP_DOMAIN_VALIDATION=true` to the docker run command. But only use this if you are completely sure that you've correctly configured everything! + diff --git a/tests/QA/060-environmental-variables.md b/tests/QA/060-environmental-variables.md index d6e3d6bf..08ddd6cd 100644 --- a/tests/QA/060-environmental-variables.md +++ b/tests/QA/060-environmental-variables.md @@ -2,6 +2,7 @@ - [ ] When starting the mastercontainer with `-e APACHE_PORT=11000` on a clean instance, the domaincheck container should be started with that same port published. That makes sure that also the Apache container will use that port later on. Using a value here that is not a port will not allow the mastercontainer to start correctly. - [ ] Make also sure that reverse proxies work by following https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md#reverse-proxy-documentation and following [001-initial-setup.md](./001-initial-setup.md) and [002-new-instance.md](./002-new-instance.md) +- [ ] When starting the mastercontainer with `-e SKIP_DOMAIN_VALIDATION=true` on a clean instance, it should skip the domain verification. So it should accept any domain that you type in then. - [ ] When starting the mastercontainer with `-e NEXTCLOUD_DATADIR="/mnt/testdata"` it should map that location from `/mnt/testdata` to `/mnt/ncdata` inside the Nextcloud container. Not having adjusted the permissions correctly before starting the Nextcloud container the first time will not allow the Nextcloud container to start correctly. See https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir for allowed values. - [ ] When starting the mastercontainer with `-e NEXTCLOUD_MOUNT="/mnt/"` it should map `/mnt/` to `/mnt/` inside the Nextcloud container. See https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host for allowed values. - [ ] When starting the mastercontainer with `-e DOCKER_SOCKET_PATH="/var/run/docker.sock.raw"` it should map `/var/run/docker.sock.raw` to `/var/run/docker.sock` inside the watchtower container which allow to update the mastercontainer on macos and with docker rootless.