diff --git a/actions/admin/settings/130.webserver.php b/actions/admin/settings/130.webserver.php
index 84861fd9b1..7a570bb50f 100644
--- a/actions/admin/settings/130.webserver.php
+++ b/actions/admin/settings/130.webserver.php
@@ -86,6 +86,18 @@
],
'visible' => Settings::Get('system.use_ssl')
],
+ 'system_http3_support' => [
+ 'label' => lng('serversettings.http3_support'),
+ 'settinggroup' => 'system',
+ 'varname' => 'http3_support',
+ 'type' => 'checkbox',
+ 'default' => false,
+ 'save_method' => 'storeSettingField',
+ 'websrv_avail' => [
+ 'nginx'
+ ],
+ 'visible' => Settings::Get('system.use_ssl')
+ ],
'system_dhparams_file' => [
'label' => lng('serversettings.dhparams_file'),
'settinggroup' => 'system',
diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php
index e0df433a3b..18bb82483b 100644
--- a/install/froxlor.sql.php
+++ b/install/froxlor.sql.php
@@ -291,6 +291,7 @@
`hsts_preload` tinyint(1) NOT NULL default '0',
`ocsp_stapling` tinyint(1) DEFAULT '0',
`http2` tinyint(1) DEFAULT '0',
+ `http3` tinyint(1) DEFAULT '0',
`notryfiles` tinyint(1) DEFAULT '0',
`writeaccesslog` tinyint(1) DEFAULT '1',
`writeerrorlog` tinyint(1) DEFAULT '1',
@@ -599,6 +600,7 @@
('system', 'ssl_cipher_list', 'ECDH+AESGCM:ECDH+AES256:!aNULL:!MD5:!DSS:!DH:!AES128'),
('system', 'nginx_php_backend', '127.0.0.1:8888'),
('system', 'http2_support', '0'),
+ ('system', 'http3_support', '0'),
('system', 'perl_server', 'unix:/var/run/nginx/cgiwrap-dispatch.sock'),
('system', 'phpreload_command', ''),
('system', 'apache24', '1'),
@@ -731,7 +733,7 @@
('panel', 'settings_mode', '0'),
('panel', 'menu_collapsed', '1'),
('panel', 'version', '2.2.4'),
- ('panel', 'db_version', '202409280');
+ ('panel', 'db_version', '202410100');
DROP TABLE IF EXISTS `panel_tasks`;
diff --git a/install/updates/froxlor/update_2.2.inc.php b/install/updates/froxlor/update_2.2.inc.php
index 929c94ac2b..bd2c75db90 100644
--- a/install/updates/froxlor/update_2.2.inc.php
+++ b/install/updates/froxlor/update_2.2.inc.php
@@ -193,3 +193,16 @@
Update::showUpdateStep("Updating from 2.2.3 to 2.2.4", false);
Froxlor::updateToVersion('2.2.4');
}
+
+if (Froxlor::isDatabaseVersion('202409280')) {
+
+ Update::showUpdateStep("Adding new settings");
+ Settings::AddNew("system.http3_support", "0");
+ Update::lastStepStatus(0);
+
+ Update::showUpdateStep("Adding http3 field to domain table");
+ Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `http3` tinyint(1) NOT NULL default '0' AFTER `http2`;");
+ Update::lastStepStatus(0);
+
+ Froxlor::updateToDbVersion('202410100');
+}
\ No newline at end of file
diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php
index 0ed0fbc9f3..0712e7620e 100644
--- a/lib/Froxlor/Api/Commands/Domains.php
+++ b/lib/Froxlor/Api/Commands/Domains.php
@@ -246,6 +246,9 @@ public function listingCount()
* @param bool $http2
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
* 0 (false)
+ * @param bool $http3
+ * optional, whether to enable http/3 for this domain (requires to be enabled in the settings), default
+ * 0 (false)
* @param int $hsts_maxage
* optional max-age value for HSTS header
* @param bool $hsts_sub
@@ -322,6 +325,7 @@ public function add()
$dont_use_default_ssl_ipandport_if_empty = $this->getBoolParam('dont_use_default_ssl_ipandport_if_empty', true, 0);
$p_ssl_ipandports = $this->getParam('ssl_ipandport', true, $dont_use_default_ssl_ipandport_if_empty ? [] : explode(',', Settings::Get('system.defaultsslip')));
$http2 = $this->getBoolParam('http2', true, 0);
+ $http3 = $this->getBoolParam('http3', true, 0);
$hsts_maxage = $this->getParam('hsts_maxage', true, 0);
$hsts_sub = $this->getBoolParam('hsts_sub', true, 0);
$hsts_preload = $this->getBoolParam('hsts_preload', true, 0);
@@ -557,6 +561,7 @@ public function add()
$ssl_redirect = 0;
$letsencrypt = 0;
$http2 = 0;
+ $http3 = 0;
// we need this for the json_encode
// if ssl is disabled or no ssl-ip/port exists
$ssl_ipandports[] = -1;
@@ -726,6 +731,7 @@ public function add()
'mod_fcgid_maxrequests' => $mod_fcgid_maxrequests,
'letsencrypt' => $letsencrypt,
'http2' => $http2,
+ 'http3' => $http3,
'hsts' => $hsts_maxage,
'hsts_sub' => $hsts_sub,
'hsts_preload' => $hsts_preload,
@@ -779,6 +785,7 @@ public function add()
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
`letsencrypt` = :letsencrypt,
`http2` = :http2,
+ `http3` = :http3,
`hsts` = :hsts,
`hsts_sub` = :hsts_sub,
`hsts_preload` = :hsts_preload,
@@ -1137,6 +1144,9 @@ private function getIpsFromIdArray(array $ids)
* @param bool $http2
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
* 0 (false)
+ * @param bool $http3
+ * optional, whether to enable http/3 for this domain (requires to be enabled in the settings), default
+ * 0 (false)
* @param int $hsts_maxage
* optional max-age value for HSTS header
* @param bool $hsts_sub
@@ -1224,6 +1234,7 @@ public function update()
] : null);
$sslenabled = $remove_ssl_ipandport ? false : $this->getBoolParam('sslenabled', true, $result['ssl_enabled']);
$http2 = $this->getBoolParam('http2', true, $result['http2']);
+ $http3 = $this->getBoolParam('http3', true, $result['http3']);
$hsts_maxage = $this->getParam('hsts_maxage', true, $result['hsts']);
$hsts_sub = $this->getBoolParam('hsts_sub', true, $result['hsts_sub']);
$hsts_preload = $this->getBoolParam('hsts_preload', true, $result['hsts_preload']);
@@ -1540,6 +1551,7 @@ public function update()
$ssl_redirect = 0;
$letsencrypt = 0;
$http2 = 0;
+ $http3 = 0;
// act like $remove_ssl_ipandport
$ssl_ipandports = [];
@@ -1674,6 +1686,7 @@ public function update()
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|| $letsencrypt != $result['letsencrypt']
|| $http2 != $result['http2']
+ || $http3 != $result['http3']
|| $hsts_maxage != $result['hsts']
|| $hsts_sub != $result['hsts_sub']
|| $hsts_preload != $result['hsts_preload']
@@ -1847,6 +1860,7 @@ public function update()
$update_data['termination_date'] = $termination_date;
$update_data['letsencrypt'] = $letsencrypt;
$update_data['http2'] = $http2;
+ $update_data['http3'] = $http3;
$update_data['hsts'] = $hsts_maxage;
$update_data['hsts_sub'] = $hsts_sub;
$update_data['hsts_preload'] = $hsts_preload;
@@ -1895,6 +1909,7 @@ public function update()
`termination_date` = :termination_date,
`letsencrypt` = :letsencrypt,
`http2` = :http2,
+ `http3` = :http3,
`hsts` = :hsts,
`hsts_sub` = :hsts_sub,
`hsts_preload` = :hsts_preload,
diff --git a/lib/Froxlor/Api/Commands/SubDomains.php b/lib/Froxlor/Api/Commands/SubDomains.php
index 1c4870c202..b86dbaafb1 100644
--- a/lib/Froxlor/Api/Commands/SubDomains.php
+++ b/lib/Froxlor/Api/Commands/SubDomains.php
@@ -80,6 +80,9 @@ class SubDomains extends ApiCommand implements ResourceEntity
* @param bool $http2
* optional, whether to enable http/2 for this subdomain (requires to be enabled in the settings),
* default 0 (false)
+ * @param bool $http3
+ * optional, whether to enable http/3 for this subdomain (requires to be enabled in the settings),
+ * default 0 (false)
* @param int $hsts_maxage
* optional max-age value for HSTS header, default 0
* @param bool $hsts_sub
@@ -116,6 +119,7 @@ public function add()
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, 0);
$letsencrypt = $this->getBoolParam('letsencrypt', true, 0);
$http2 = $this->getBoolParam('http2', true, 0);
+ $http3 = $this->getBoolParam('http3', true, 0);
$hsts_maxage = $this->getParam('hsts_maxage', true, 0);
$hsts_sub = $this->getBoolParam('hsts_sub', true, 0);
$hsts_preload = $this->getBoolParam('hsts_preload', true, 0);
@@ -124,6 +128,7 @@ public function add()
$ssl_redirect = 0;
$letsencrypt = 0;
$http2 = 0;
+ $http3 = 0;
$hsts_maxage = 0;
$hsts_sub = 0;
$hsts_preload = 0;
@@ -341,6 +346,7 @@ public function add()
`phpsettingid` = :phpsettingid,
`letsencrypt` = :letsencrypt,
`http2` = :http2,
+ `http3` = :http3,
`hsts` = :hsts,
`hsts_sub` = :hsts_sub,
`hsts_preload` = :hsts_preload,
@@ -373,6 +379,7 @@ public function add()
"phpsettingid" => $phpsid_result['phpsettingid'],
"letsencrypt" => $letsencrypt,
"http2" => $http2,
+ "http3" => $http3,
"hsts" => $hsts_maxage,
"hsts_sub" => $hsts_sub,
"hsts_preload" => $hsts_preload,
@@ -618,6 +625,9 @@ private function validateDomainDocumentRoot($path = null, $url = null, $customer
* @param bool $http2
* optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default
* 0 (false)
+ * @param bool $http3
+ * optional, whether to enable http/3 for this domain (requires to be enabled in the settings), default
+ * 0 (false)
* @param int $hsts_maxage
* optional max-age value for HSTS header
* @param bool $hsts_sub
@@ -671,6 +681,7 @@ public function update()
$ssl_redirect = $this->getBoolParam('ssl_redirect', true, $result['ssl_redirect']);
$letsencrypt = $this->getBoolParam('letsencrypt', true, $result['letsencrypt']);
$http2 = $this->getBoolParam('http2', true, $result['http2']);
+ $http3 = $this->getBoolParam('http3', true, $result['http3']);
$hsts_maxage = $this->getParam('hsts_maxage', true, $result['hsts']);
$hsts_sub = $this->getBoolParam('hsts_sub', true, $result['hsts_sub']);
$hsts_preload = $this->getBoolParam('hsts_preload', true, $result['hsts_preload']);
@@ -679,6 +690,7 @@ public function update()
$ssl_redirect = 0;
$letsencrypt = 0;
$http2 = 0;
+ $http3 = 0;
$hsts_maxage = 0;
$hsts_sub = 0;
$hsts_preload = 0;
@@ -824,6 +836,7 @@ public function update()
|| $hsts_preload != $result['hsts_preload']
|| $phpsettingid != $result['phpsettingid']
|| $http2 != $result['http2']
+ || $http3 != $result['http3']
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
) {
$stmt = Database::prepare("
@@ -838,6 +851,7 @@ public function update()
`ssl_redirect` = :ssl_redirect,
`letsencrypt` = :letsencrypt,
`http2` = :http2,
+ `http3` = :http3,
`hsts` = :hsts,
`hsts_sub` = :hsts_sub,
`hsts_preload` = :hsts_preload,
@@ -856,6 +870,7 @@ public function update()
"ssl_redirect" => $ssl_redirect,
"letsencrypt" => $letsencrypt,
"http2" => $http2,
+ "http3" => $http3,
"hsts" => $hsts_maxage,
"hsts_sub" => $hsts_sub,
"hsts_preload" => $hsts_preload,
diff --git a/lib/Froxlor/Cron/Http/Nginx.php b/lib/Froxlor/Cron/Http/Nginx.php
index ffe153ee6b..18831b320a 100644
--- a/lib/Froxlor/Cron/Http/Nginx.php
+++ b/lib/Froxlor/Cron/Http/Nginx.php
@@ -169,6 +169,7 @@ public function createIpPort()
}
$http2 = $ssl_vhost == true && Settings::Get('system.http2_support') == '1';
+ $http3 = $ssl_vhost == true && Settings::Get('system.http3_support') == '1';
/**
* this HAS to be set for the default host in nginx or else no vhost will work
@@ -177,6 +178,14 @@ public function createIpPort()
if ($http2 && $this->http2_on_directive) {
$this->nginx_data[$vhost_filename] .= "\t" . 'http2 on;' . "\n";
}
+ if ($http3) {
+ $this->nginx_data[$vhost_filename] .= "\t" . 'listen ' . $ip . ':' . $port . ' default_server quic reuseport;' . "\n";
+ $this->nginx_data[$vhost_filename] .= "\t" . 'http3 on;' . "\n";
+ $this->nginx_data[$vhost_filename] .= "\t" . 'http3_hq on;' . "\n";
+ $this->nginx_data[$vhost_filename] .= "\t" . 'quic_gso on;' . "\n";
+ $this->nginx_data[$vhost_filename] .= "\t" . 'quic_retry on;' . "\n";
+ $this->nginx_data[$vhost_filename] .= "\t" . 'add_header Alt-Svc \'h3=":' . $port . '"; ma=86400\';' . "\n";
+ }
$this->nginx_data[$vhost_filename] .= "\t" . '# Froxlor default vhost' . "\n";
$aliases = "";
@@ -515,6 +524,7 @@ protected function getVhostContent($domain, $ssl_vhost = false)
'domainid' => $domain['id']
]);
+ $http3 = $ssl_vhost == true && (isset($domain['http3']) && $domain['http3'] == '1' && Settings::Get('system.http3_support') == '1');
while ($ipandport = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$domain['ip'] = $ipandport['ip'];
$domain['port'] = $ipandport['port'];
@@ -550,6 +560,17 @@ protected function getVhostContent($domain, $ssl_vhost = false)
$vhost_content .= "\t" . 'http2 on;' . "\n";
$has_http2_on = true;
}
+ if ($http3) {
+ $vhost_content .= "\t" . 'listen ' . $ipport . ' quic;' . "\n";
+ }
+ }
+
+ if ($http3) {
+ $vhost_content .= "\t" . 'add_header Alt-Svc \'h3=":' . $domain['port'] . '"; ma=86400\';' . "\n";
+ $vhost_content .= "\t" . 'http3 on;' . "\n";
+ $vhost_content .= "\t" . 'http3_hq on;' . "\n";
+ $vhost_content .= "\t" . 'quic_gso on;' . "\n";
+ $vhost_content .= "\t" . 'quic_retry on;' . "\n";
}
// get all server-names
diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php
index acb7f6c188..e28bb9b001 100644
--- a/lib/Froxlor/Froxlor.php
+++ b/lib/Froxlor/Froxlor.php
@@ -34,7 +34,7 @@ final class Froxlor
const VERSION = '2.2.4';
// Database version (YYYYMMDDC where C is a daily counter)
- const DBVERSION = '202409280';
+ const DBVERSION = '202410100';
// Distribution branding-tag (used for Debian etc.)
const BRANDING = '';
diff --git a/lib/formfields/admin/domains/formfield.domains_add.php b/lib/formfields/admin/domains/formfield.domains_add.php
index b5e994446f..5a81baa7da 100644
--- a/lib/formfields/admin/domains/formfield.domains_add.php
+++ b/lib/formfields/admin/domains/formfield.domains_add.php
@@ -234,6 +234,14 @@
'value' => '1',
'checked' => false
],
+ 'http3' => [
+ 'visible' => !empty($ssl_ipsandports) && Settings::Get('system.webserver') == 'nginx' && Settings::Get('system.http3_support') == '1',
+ 'label' => lng('admin.domain_http3.title'),
+ 'desc' => lng('admin.domain_http3.description'),
+ 'type' => 'checkbox',
+ 'value' => '1',
+ 'checked' => false
+ ],
'override_tls' => [
'visible' => !empty($ssl_ipsandports) && $userinfo['change_serversettings'] == '1',
'label' => lng('admin.domain_override_tls'),
diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php
index 45585ca318..efe7995160 100644
--- a/lib/formfields/admin/domains/formfield.domains_edit.php
+++ b/lib/formfields/admin/domains/formfield.domains_edit.php
@@ -266,6 +266,14 @@
'value' => '1',
'checked' => $result['http2']
],
+ 'http3' => [
+ 'visible' => !empty($ssl_ipsandports) && Settings::Get('system.webserver') == 'nginx' && Settings::Get('system.http3_support') == '1',
+ 'label' => lng('admin.domain_http3.title'),
+ 'desc' => lng('admin.domain_http3.description'),
+ 'type' => 'checkbox',
+ 'value' => '1',
+ 'checked' => $result['http3']
+ ],
'override_tls' => [
'visible' => !empty($ssl_ipsandports) && $userinfo['change_serversettings'] == '1',
'label' => lng('admin.domain_override_tls'),
diff --git a/lib/formfields/customer/domains/formfield.domains_add.php b/lib/formfields/customer/domains/formfield.domains_add.php
index fcd0c17232..c77c791234 100644
--- a/lib/formfields/customer/domains/formfield.domains_add.php
+++ b/lib/formfields/customer/domains/formfield.domains_add.php
@@ -137,6 +137,14 @@
'value' => '1',
'checked' => false
],
+ 'http3' => [
+ 'visible' => $ssl_ipsandports && Settings::Get('system.webserver') == 'nginx' && Settings::Get('system.http3_support') == '1',
+ 'label' => lng('admin.domain_http3.title'),
+ 'desc' => lng('admin.domain_http3.description'),
+ 'type' => 'checkbox',
+ 'value' => '1',
+ 'checked' => false
+ ],
'hsts_maxage' => [
'label' => lng('admin.domain_hsts_maxage.title'),
'desc' => lng('admin.domain_hsts_maxage.description'),
diff --git a/lib/formfields/customer/domains/formfield.domains_edit.php b/lib/formfields/customer/domains/formfield.domains_edit.php
index 6e0ab1cc12..8bba955cdc 100644
--- a/lib/formfields/customer/domains/formfield.domains_edit.php
+++ b/lib/formfields/customer/domains/formfield.domains_edit.php
@@ -172,6 +172,14 @@
'value' => '1',
'checked' => $result['http2']
],
+ 'http3' => [
+ 'visible' => $ssl_ipsandports && Settings::Get('system.webserver') == 'nginx' && Settings::Get('system.http3_support') == '1',
+ 'label' => lng('admin.domain_http3.title'),
+ 'desc' => lng('admin.domain_http3.description'),
+ 'type' => 'checkbox',
+ 'value' => '1',
+ 'checked' => $result['http3']
+ ],
'hsts_maxage' => [
'label' => lng('admin.domain_hsts_maxage.title'),
'desc' => lng('admin.domain_hsts_maxage.description'),
diff --git a/lib/tablelisting/admin/tablelisting.domains.php b/lib/tablelisting/admin/tablelisting.domains.php
index b378482832..9bd3d89cfc 100644
--- a/lib/tablelisting/admin/tablelisting.domains.php
+++ b/lib/tablelisting/admin/tablelisting.domains.php
@@ -143,6 +143,11 @@
'field' => 'http2',
'callback' => [Text::class, 'boolean'],
],
+ 'd.http3' => [
+ 'label' => lng('admin.domain_http3.title'),
+ 'field' => 'http3',
+ 'callback' => [Text::class, 'boolean'],
+ ],
'd.letsencrypt' => [
'label' => lng('panel.letsencrypt'),
'field' => 'letsencrypt',
diff --git a/lng/de.lng.php b/lng/de.lng.php
index 7199ee878b..4a2593f41c 100644
--- a/lng/de.lng.php
+++ b/lng/de.lng.php
@@ -448,6 +448,10 @@
'title' => 'HTTP2 Unterstützung',
'description' => 'Siehe Wikipedia für eine ausführliche Beschreibung von HTTP2',
],
+ 'domain_http3' => [
+ 'title' => 'HTTP3 Unterstützung',
+ 'description' => 'Siehe Wikipedia für eine ausführliche Beschreibung von HTTP3',
+ ],
'testmail' => 'SMTP Test',
'phpsettingsforsubdomains' => 'PHP-Config für alle Subdomains übernehmen:',
'plans' => [
@@ -2005,6 +2009,10 @@
'title' => 'HTTP2 Unterstützung',
'description' => 'Aktiviere HTTP2 Unterstützung für SSL.
NUR AKTIVIEREN, WENN DER WEBSERVER DIESE FUNKTION UNTERSTÜTZT (nginx version 1.9.5+, apache2 version 2.4.17+)',
],
+ 'http3_support' => [
+ 'title' => 'HTTP3 Unterstützung',
+ 'description' => 'Aktiviere HTTP3 Unterstützung für SSL.
NUR AKTIVIEREN, WENN DER WEBSERVER DIESE FUNKTION UNTERSTÜTZT (nginx version 1.25.0+)',
+ ],
'nssextrausers' => [
'title' => 'Verwende libnss-extrausers anstatt libnss-mysql',
'description' => 'Lese Benutzer nicht direkt aus der Datenbank sondern über Dateien. Bitte nur aktivieren, wenn die entsprechende Konfiguration vorgenommen wurde (System -> libnss-extrausers).
Nur für Debian/Ubuntu (oder wenn libnss-extrausers manuell kompiliert wurde!)',
diff --git a/lng/en.lng.php b/lng/en.lng.php
index 6c0af9c122..609eb9168f 100644
--- a/lng/en.lng.php
+++ b/lng/en.lng.php
@@ -456,6 +456,10 @@
'title' => 'HTTP2 support',
'description' => 'See Wikipedia for a detailed explanation of HTTP2',
],
+ 'domain_http3' => [
+ 'title' => 'HTTP3 support',
+ 'description' => 'See Wikipedia for a detailed explanation of HTTP3',
+ ],
'testmail' => 'SMTP test',
'phpsettingsforsubdomains' => 'Apply php-config to all subdomains:',
'plans' => [
@@ -2127,6 +2131,10 @@
'title' => 'HTTP2 Support',
'description' => 'enable HTTP2 support for ssl.
ENABLE ONLY IF YOUR WEBSERVER SUPPORTS THIS FEATURE (nginx version 1.9.5+, apache2 version 2.4.17+)',
],
+ 'http3_support' => [
+ 'title' => 'HTTP3 Support',
+ 'description' => 'enable HTTP3 support for ssl.
ENABLE ONLY IF YOUR WEBSERVER SUPPORTS THIS FEATURE (nginx version 1.25.0+)',
+ ],
'nssextrausers' => [
'title' => 'Use libnss-extrausers instead of libnss-mysql',
'description' => 'Do not read users from the database but from files. Please only activate if you have already gone through the required configuration steps (system -> libnss-extrausers).
For Debian/Ubuntu only (or if you have compiled libnss-extrausers yourself!)',