mirror of
https://github.com/opnsense/plugins.git
synced 2026-04-20 20:22:51 -05:00
www/caddy: sync with master
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
PLUGIN_NAME= caddy
|
||||
PLUGIN_VERSION= 2.0.4
|
||||
PLUGIN_REVISION= 3
|
||||
PLUGIN_VERSION= 2.1.0
|
||||
PLUGIN_DEPENDS= caddy-custom
|
||||
PLUGIN_COMMENT= Modern Reverse Proxy with Automatic HTTPS, Dynamic DNS and Layer4 Routing
|
||||
PLUGIN_MAINTAINER= cedrik@pischem.com
|
||||
|
||||
@@ -6,34 +6,45 @@ DOC: https://docs.opnsense.org/manual/how-tos/caddy.html
|
||||
Plugin Changelog
|
||||
================
|
||||
|
||||
2.1.0
|
||||
|
||||
* Remove: NTLM plugin support due to service control instability and protocol deprecation (opnsense/plugins/pull/5258)
|
||||
* Remove: validateAction and caddy_control.py service control validation funnel (opnsense/plugins/pull/5258)
|
||||
* Remove: “Add Handler” shortcut command (opnsense/plugins/pull/5260)
|
||||
* Add: Layer 4 upstream originate TLS feature (opnsense/plugins/pull/5263)
|
||||
* Cleanup: Simplify reload command handling (opnsense/plugins/pull/5267)
|
||||
* Cleanup: Use BaseField cast helpers in certificate extraction script (opnsense/plugins/pull/5268)
|
||||
* Cleanup: Remove CDATA in help texts, fix typos, remove obsolete links, add missing selectpicker style (opnsense/plugins/pull/5261)
|
||||
* Cleanup: Use BaseField cast helpers in validation messages (opnsense/plugins/pull/5263)
|
||||
|
||||
2.0.4
|
||||
|
||||
Add: DNS-01 challenge delegation via CNAME (contributed by sdsys-ch) (opnsense/plugins/pull/4950)
|
||||
Fix: Enabling HTTP access log wrongly excluded the process logs (opnsense/plugins/pull/4974)
|
||||
Fix: fix setup.sh script not setting correct ownership in www user mode (opnsense/plugins/pull/4976)
|
||||
Fix: Prevent sudo on startup via skip_install_trust (opnsense/plugins/pull/5015)
|
||||
Fix: Fix race condition that moved domain filter selectpicker into invisible tab (opnsense/plugins/pull/5076)
|
||||
* Add: DNS-01 challenge delegation via CNAME (contributed by sdsys-ch) (opnsense/plugins/pull/4950)
|
||||
* Fix: Enabling HTTP access log wrongly excluded the process logs (opnsense/plugins/pull/4974)
|
||||
* Fix: fix setup.sh script not setting correct ownership in www user mode (opnsense/plugins/pull/4976)
|
||||
* Fix: Prevent sudo on startup via skip_install_trust (opnsense/plugins/pull/5015)
|
||||
* Fix: Fix race condition that moved domain filter selectpicker into invisible tab (opnsense/plugins/pull/5076)
|
||||
|
||||
2.0.3
|
||||
|
||||
Add: Tabulator groupBy of domain and subdomain (opnsense/plugins/pull/4909)
|
||||
Cleanup: Grid HTML and style
|
||||
Fix: Tabulator 'Data Load Response Blocked' warning
|
||||
Fix: setup.sh interaction with caddy storage and permissions (opnsense/plugins/pull/4911)
|
||||
Fix: Emit subdomain http access logs when wildcard parent has logging enabled (opnsense/plugins/issues/4914)
|
||||
* Add: Tabulator groupBy of domain and subdomain (opnsense/plugins/pull/4909)
|
||||
* Cleanup: Grid HTML and style
|
||||
* Fix: Tabulator 'Data Load Response Blocked' warning
|
||||
* Fix: setup.sh interaction with caddy storage and permissions (opnsense/plugins/pull/4911)
|
||||
* Fix: Emit subdomain http access logs when wildcard parent has logging enabled (opnsense/plugins/issues/4914)
|
||||
|
||||
2.0.2
|
||||
|
||||
Add: Global server timeout options (opnsense/plugins/pull/4778)
|
||||
Cleanup: Change all camelCase to snake_case in api notations (opnsense/plugins/pull/4767,4768,4776)
|
||||
Cleanup: Use SimpleActionButton in general.volt (opnsense/plugins/pull/4779)
|
||||
Cleanup: Change em into px, fix key/value display in formatter (opnsense/plugins/pull/4807)
|
||||
Cleanup: Remove obsolete model_relation_domain formatter (opnsense/plugins/pull/4813)
|
||||
* Add: Global server timeout options (opnsense/plugins/pull/4778)
|
||||
* Cleanup: Change all camelCase to snake_case in api notations (opnsense/plugins/pull/4767,4768,4776)
|
||||
* Cleanup: Use SimpleActionButton in general.volt (opnsense/plugins/pull/4779)
|
||||
* Cleanup: Change em into px, fix key/value display in formatter (opnsense/plugins/pull/4807)
|
||||
* Cleanup: Remove obsolete model_relation_domain formatter (opnsense/plugins/pull/4813)
|
||||
|
||||
2.0.1
|
||||
|
||||
Add: Active health checks to handlers (contributed by zaben903) (opnsense/plugins/pull/4721)
|
||||
Fix: Add handler command sometimes clearing domain selection in open dialogue (opnsense/plugins/pull/4748)
|
||||
* Add: Active health checks to handlers (contributed by zaben903) (opnsense/plugins/pull/4721)
|
||||
* Fix: Add handler command sometimes clearing domain selection in open dialogue (opnsense/plugins/pull/4748)
|
||||
|
||||
2.0.0
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2023-2024 Cedrik Pischem
|
||||
* Copyright (C) 2023-2026 Cedrik Pischem
|
||||
* Copyright (C) 2015 Deciso B.V.
|
||||
*
|
||||
* All rights reserved.
|
||||
@@ -46,28 +46,4 @@ class ServiceController extends ApiMutableServiceControllerBase
|
||||
// Caddy can use a reload action instead
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function validateAction()
|
||||
{
|
||||
$backend = new Backend();
|
||||
|
||||
// First, reload the template to ensure the latest configuration is used
|
||||
$backend->configdRun("template reload " . self::$internalServiceTemplate);
|
||||
|
||||
// Validate the Caddyfile
|
||||
$validateResult = trim($backend->configdRun('caddy validate'));
|
||||
|
||||
// Attempt to parse the JSON output from the validation result
|
||||
if (($jsonStartPos = strpos($validateResult, '{"message":')) !== false) {
|
||||
$jsonOutput = substr($validateResult, $jsonStartPos);
|
||||
$result = json_decode($jsonOutput, true);
|
||||
|
||||
if (is_array($result) && isset($result['status'])) {
|
||||
return ["status" => $result['status'], "message" => $result['message']];
|
||||
}
|
||||
}
|
||||
|
||||
// If unable to parse the expected JSON output, return a generic error message
|
||||
return ["status" => "failed", "message" => gettext("Unable to parse the validation result.")];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<id>accesslist.accesslistName</id>
|
||||
<label>Access List Name</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a name for this access list.]]></help>
|
||||
<help>Enter a name for this access list.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>accesslist.clientIps</id>
|
||||
@@ -11,13 +11,13 @@
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<allownew>true</allownew>
|
||||
<help><![CDATA[Enter the client IP addresses or networks for this access list. Accepts multiple IPv4/IPv6 addresses or networks.]]></help>
|
||||
<help>Enter the client IP addresses or networks for this access list. Accepts multiple IPv4/IPv6 addresses or networks.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>accesslist.accesslistInvert</id>
|
||||
<label>Invert List</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[If checked, the access list logic will be inverted (i.e., the listed IPs will be blocked instead of allowed).]]></help>
|
||||
<help>If checked, the access list logic will be inverted (i.e., the listed IPs will be blocked instead of allowed).</help>
|
||||
<grid_view>
|
||||
<type>boolean</type>
|
||||
<formatter>boolean</formatter>
|
||||
@@ -28,7 +28,7 @@
|
||||
<label>HTTP Response Code</label>
|
||||
<type>text</type>
|
||||
<hint>abort</hint>
|
||||
<help><![CDATA[Set a custom HTTP response code that should be returned to the requesting client when the access list does not match. If empty, the connection is aborted with no response.]]></help>
|
||||
<help>Set a custom HTTP response code that should be returned to the requesting client when the access list does not match. If empty, the connection is aborted with no response.</help>
|
||||
<advanced>true</advanced>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
@@ -38,7 +38,7 @@
|
||||
<id>accesslist.HttpResponseMessage</id>
|
||||
<label>HTTP Response Message</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Set a custom HTTP response message in addition to the HTTP response code. If empty, the default HTTP response message for the chosen HTTP response code will be used.]]></help>
|
||||
<help>Set a custom HTTP response message in addition to the HTTP response code. If empty, the default HTTP response message for the chosen HTTP response code will be used.</help>
|
||||
<advanced>true</advanced>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
@@ -48,7 +48,7 @@
|
||||
<id>accesslist.RequestMatcher</id>
|
||||
<label>Request Matcher</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Set the request matcher that will be applied to this access list.]]></help>
|
||||
<help>Set the request matcher that will be applied to this access list.</help>
|
||||
<advanced>true</advanced>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
@@ -58,6 +58,6 @@
|
||||
<id>accesslist.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a description for this access list.]]></help>
|
||||
<help>Enter a description for this access list.</help>
|
||||
</field>
|
||||
</form>
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
<id>basicauth.basicauthuser</id>
|
||||
<label>User</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a username. Afterwards, select it in a "Domain" or "Subdomain" to restrict access with basic auth.]]></help>
|
||||
<help>Enter a username. Afterwards, select it in a "Domain" or "Subdomain" to restrict access with Basic Auth.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>basicauth.basicauthpass</id>
|
||||
<label>Password</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a password. It will be hashed with bcrypt. It can only be set and changed but will not be visible anymore.]]></help>
|
||||
<help>Enter a password. It will be hashed with bcrypt. It can only be set and changed but will not be visible anymore.</help>
|
||||
<grid_view>
|
||||
<ignore>true</ignore>
|
||||
</grid_view>
|
||||
@@ -18,6 +18,6 @@
|
||||
<id>basicauth.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a description for this user.]]></help>
|
||||
<help>Enter a description for this user.</help>
|
||||
</field>
|
||||
</form>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<id>handle.enabled</id>
|
||||
<label>Enabled</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Enable this handler.]]></help>
|
||||
<help>Enable this handler.</help>
|
||||
<grid_view>
|
||||
<width>20</width>
|
||||
<type>boolean</type>
|
||||
@@ -18,7 +18,7 @@
|
||||
<id>handle.reverse</id>
|
||||
<label>Domain</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select a domain to handle.]]></help>
|
||||
<help>Select a domain to handle.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -27,7 +27,7 @@
|
||||
<id>handle.subdomain</id>
|
||||
<label>Subdomain</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select a subdomain to handle. Make sure to additionaly choose a wildcard domain as "Domain". Leave unset, if not using subdomains.]]></help>
|
||||
<help>Select a subdomain to handle. Make sure to additionally choose a wildcard domain as "Domain". Leave unset, if not using subdomains.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -40,7 +40,7 @@
|
||||
<id>handle.HandleType</id>
|
||||
<label>Handler</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Choose a handling type: "handle" (default) will keep the path in all requests. "handle_path" will strip the path from all requests.]]></help>
|
||||
<help>Choose a handling type: "handle" (default) will keep the path in all requests. "handle_path" will strip the path from all requests.</help>
|
||||
<advanced>true</advanced>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
@@ -51,7 +51,7 @@
|
||||
<label>Path</label>
|
||||
<type>text</type>
|
||||
<hint>any</hint>
|
||||
<help><![CDATA[Enter a path to handle. Choose a pattern like "/*" or "/example/*". Leave empty to handle any paths (recommended). Any request matching this pattern will be handled by the chosen directive.]]></help>
|
||||
<help>Enter a path to handle. Choose a pattern like "/*" or "/example/*". Leave empty to handle any paths (recommended). Any request matching this pattern will be handled by the chosen directive.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -66,8 +66,8 @@
|
||||
<id>handle.accesslist</id>
|
||||
<label>Access List</label>
|
||||
<type>dropdown</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<help><![CDATA[Select an Access List to restrict access to this handler. If unset, any local or remote client is allowed access.]]></help>
|
||||
<style>selectpicker style_reverse_proxy</style>
|
||||
<help>Select an Access List to restrict access to this handler. If unset, any local or remote client is allowed access.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -78,7 +78,7 @@
|
||||
<type>select_multiple</type>
|
||||
<size>5</size>
|
||||
<style>selectpicker style_reverse_proxy</style>
|
||||
<help><![CDATA[Select Users to restrict access to this path. If unset, any user is allowed access.]]></help>
|
||||
<help>Select Users to restrict access to this path. If unset, any user is allowed access.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -88,7 +88,7 @@
|
||||
<label>Forward Auth</label>
|
||||
<type>checkbox</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<help><![CDATA[Enable or disable Forward Auth. Requires an "Auth Provider" in "General Settings". Headers are set automatically to the standard of the chosen provider. Enabling this option will additionally generate the forward_auth directive in front of the reverse_proxy directive inside the scope of this handler.]]></help>
|
||||
<help>Enable or disable Forward Auth. Requires an "Auth Provider" in "General Settings". Headers are set automatically to the standard of the chosen provider. Enabling this option will additionally generate the forward_auth directive in front of the reverse_proxy directive inside the scope of this handler.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
<type>boolean</type>
|
||||
@@ -103,7 +103,7 @@
|
||||
<id>handle.HandleDirective</id>
|
||||
<label>Directive</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Choose a handling directive: "reverse_proxy" will proxy all HTTP traffic to the selected upstream. "redir" will create a HTTP redirect.]]></help>
|
||||
<help>Choose a handling directive: "reverse_proxy" will proxy all HTTP traffic to the selected upstream. "redir" will create a HTTP redirect.</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
@@ -116,7 +116,7 @@
|
||||
<label>HTTP Version</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker style_reverse_proxy</style>
|
||||
<help><![CDATA[The default versions are highly recommended. Choose a HTTP version for the upstream destination. HTTP/3 (HTTP over QUIC) requires HTTPS, and only establishes connections to webservers that also support HTTP/3.]]></help>
|
||||
<help>The default versions are highly recommended. Choose a HTTP version for the upstream destination. HTTP/3 (HTTP over QUIC) requires HTTPS, and only establishes connections to web servers that also support HTTP/3.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -128,7 +128,7 @@
|
||||
<type>select_multiple</type>
|
||||
<size>5</size>
|
||||
<style>selectpicker style_reverse_proxy</style>
|
||||
<help><![CDATA[Select one or multiple headers. Caddy sets "X-Forwarded-For", "X-Forwarded-Proto" and "X-Forwarded-Host" by default, adding them here is not needed. Setting a wrong configuration can be a security risk or break functionality.]]></help>
|
||||
<help>Select one or multiple headers. Caddy sets "X-Forwarded-For", "X-Forwarded-Proto" and "X-Forwarded-Host" by default, adding them here is not needed. Setting a wrong configuration can be a security risk or break functionality.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -139,7 +139,7 @@
|
||||
<type>text</type>
|
||||
<hint>120</hint>
|
||||
<style>style_reverse_proxy</style>
|
||||
<help><![CDATA[Leave empty to use default. Keepalive is either 0 (off) or a duration value that specifies how long to keep connections open (timeout) in seconds.]]></help>
|
||||
<help>Leave empty to use default. Keepalive is either 0 (off) or a duration value that specifies how long to keep connections open (timeout) in seconds.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -152,7 +152,7 @@
|
||||
<id>handle.HttpTls</id>
|
||||
<label>Protocol</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Enable or disable HTTP over TLS (HTTPS) to communicate with the upstream destination. Caddy uses HTTP with the upstream destination by default.]]></help>
|
||||
<help>Enable or disable HTTP over TLS (HTTPS) to communicate with the upstream destination. Caddy uses HTTP with the upstream destination by default.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -163,7 +163,7 @@
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<allownew>true</allownew>
|
||||
<help><![CDATA[Enter a domain name or IP address of the upstream destination. If multiple are chosen, they will be load balanced with the default random policy. A health check can be activated by populating "Upstream Fail Duration" in advanced mode. When directive is "redir", only the first domain will be evaluated.]]></help>
|
||||
<help>Enter a domain name or IP address of the upstream destination. If multiple are chosen, they will be load balanced with the default random policy. A health check can be activated by populating "Upstream Fail Duration" in advanced mode. When directive is "redir", only the first domain will be evaluated.</help>
|
||||
<grid_view>
|
||||
<formatter>to_domain</formatter>
|
||||
</grid_view>
|
||||
@@ -172,7 +172,7 @@
|
||||
<id>handle.ToPort</id>
|
||||
<label>Upstream Port</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Leave empty to use the default port or choose a custom port for the upstream destination.]]></help>
|
||||
<help>Leave empty to use the default port or choose a custom port for the upstream destination.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -181,7 +181,7 @@
|
||||
<id>handle.ToPath</id>
|
||||
<label>Upstream Path</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[When directive is "reverse_proxy", enter a path prefix like "/guacamole" that should be prepended to the upstream request. This is useful for destinations that have a virtual directory as their base path. When directive is "redir", add the path the request should be redirected to; leaving it empty will append {uri}.]]></help>
|
||||
<help>When directive is "reverse_proxy", enter a path prefix like "/guacamole" that should be prepended to the upstream request. This is useful for destinations that have a virtual directory as their base path. When directive is "redir", add the path the request should be redirected to; leaving it empty will append {uri}.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -191,7 +191,7 @@
|
||||
<label>TLS Insecure Skip Verify</label>
|
||||
<type>checkbox</type>
|
||||
<style>style_tls_handle</style>
|
||||
<help><![CDATA[Caddy uses HTTP by default to connect to the Upstream. If the Upstream is only reachable via HTTPS, this option disables the TLS handshake verification. This makes the connection insecure and vulnerable to man-in-the-middle attacks. In private networks the risk is low, though do not use in production if possible. It is advised to either use plain HTTP, or proper TLS handling by using the options in "Trust".]]></help>
|
||||
<help>Caddy uses HTTP by default to connect to the Upstream. If the Upstream is only reachable via HTTPS, this option disables the TLS handshake verification. This makes the connection insecure and vulnerable to man-in-the-middle attacks. In private networks the risk is low, though do not use in production if possible. It is advised to either use plain HTTP, or proper TLS handling by using the options in "Trust".</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
<type>boolean</type>
|
||||
@@ -203,7 +203,7 @@
|
||||
<label>TLS Trust Pool</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker style_tls_handle</style>
|
||||
<help><![CDATA[Choose a CA or self-signed certificate to trust from "System - Trust - Authorities". Useful if the upstream destination only accepts TLS connections and offers a self signed certificate. Adding that certificate here will allow for the encrypted connection to succeed.]]></help>
|
||||
<help>Choose a CA or self-signed certificate to trust from "System - Trust - Authorities". Useful if the upstream destination only accepts TLS connections and offers a self signed certificate. Adding that certificate here will allow for the encrypted connection to succeed.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -213,28 +213,16 @@
|
||||
<label>TLS Server Name</label>
|
||||
<type>text</type>
|
||||
<style>style_tls_handle</style>
|
||||
<help><![CDATA[Enter a hostname or IP address that matches the SAN "Subject Alternative Name" of the offered upstream certificate. This will change the SNI "Server Name Indication" of Caddy. Setting an IP address as "Upstream Domain", enabling "TLS" and selecting a "TLS Trust Pool", would make the SAN of the offered upstream certificate not match with the SNI of Caddy, since it will be an IP address instead of a hostname. Setting the hostname of the certificate here, fixes this issue. Please note that only SAN certificates are supported; CN "Common Name" will not work.]]></help>
|
||||
<help>Enter a hostname or IP address that matches the SAN "Subject Alternative Name" of the offered upstream certificate. This will change the SNI "Server Name Indication" of Caddy. Setting an IP address as "Upstream Domain", enabling "TLS" and selecting a "TLS Trust Pool", would make the SAN of the offered upstream certificate not match with the SNI of Caddy, since it will be an IP address instead of a hostname. Setting the hostname of the certificate here, fixes this issue. Please note that only SAN certificates are supported; CN "Common Name" will not work.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
</field>
|
||||
<field>
|
||||
<id>handle.HttpNtlm</id>
|
||||
<label>NTLM</label>
|
||||
<type>checkbox</type>
|
||||
<style>style_tls_handle</style>
|
||||
<help><![CDATA[Enable or disable NTLM. Needed to reverse proxy an Exchange Server. Warning: NTLM has been deprecated by Microsoft. This option will stay for as long as the optional http.reverse_proxy.transport.http_ntlm module can be compiled without errors.]]></help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
<type>boolean</type>
|
||||
<formatter>boolean</formatter>
|
||||
</grid_view>
|
||||
</field>
|
||||
<field>
|
||||
<id>handle.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a description for this handler.]]></help>
|
||||
<help>Enter a description for this handler.</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
@@ -247,7 +235,7 @@
|
||||
<label>Load Balance Policy</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker style_reverse_proxy</style>
|
||||
<help><![CDATA[lb_policy is the name of the load balancing policy, along with any options. For policies that involve hashing, the highest-random-weight (HRW) algorithm is used to ensure that a client or request with the same hash key is mapped to the same upstream, even if the list of upstreams change.]]></help>
|
||||
<help>lb_policy is the name of the load balancing policy, along with any options. For policies that involve hashing, the highest-random-weight (HRW) algorithm is used to ensure that a client or request with the same hash key is mapped to the same upstream, even if the list of upstreams change.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -258,7 +246,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>off</hint>
|
||||
<help><![CDATA[lb_retries is how many times to retry selecting available backends for each request if the next available host is down. If lb_try_duration is also configured, then retries may stop early if the duration is reached. In other words, the retry duration takes precedence over the retry count.]]></help>
|
||||
<help>lb_retries is how many times to retry selecting available backends for each request if the next available host is down. If lb_try_duration is also configured, then retries may stop early if the duration is reached. In other words, the retry duration takes precedence over the retry count.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -269,7 +257,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>0</hint>
|
||||
<help><![CDATA[lb_try_duration is a duration value that defines how long to try selecting available backends for each request if the next available host is down. Clients will wait for up to this long while the load balancer tries to find an available upstream host. A reasonable starting point might be 5s since the HTTP transport's default dial timeout is 3s, so that should allow for at least one retry if the first selected upstream cannot be reached.]]></help>
|
||||
<help>lb_try_duration is a duration value that defines how long to try selecting available backends for each request if the next available host is down. Clients will wait for up to this long while the load balancer tries to find an available upstream host. A reasonable starting point might be 5s since the HTTP transport's default dial timeout is 3s, so that should allow for at least one retry if the first selected upstream cannot be reached.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -280,7 +268,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>250</hint>
|
||||
<help><![CDATA[lb_try_interval is a duration value that defines how long to wait between selecting the next host from the pool. Only relevant when a request to an upstream host fails. Be aware that setting this to 0 with a non-zero lb_try_duration can cause the CPU to spin if all backends are down and latency is very low.]]></help>
|
||||
<help>lb_try_interval is a duration value that defines how long to wait between selecting the next host from the pool. Only relevant when a request to an upstream host fails. Be aware that setting this to 0 with a non-zero lb_try_duration can cause the CPU to spin if all backends are down and latency is very low.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -291,7 +279,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>off</hint>
|
||||
<help><![CDATA[fail_duration enables a passive health check when multiple destinations in "Upstream Domain" are set. It is a value that defines how long to remember a failed request. A duration of 1 or more seconds enables passive health checking. A reasonable starting point might be 30s to balance error rates with responsiveness when bringing an unhealthy upstream back online.]]></help>
|
||||
<help>fail_duration enables a passive health check when multiple destinations in "Upstream Domain" are set. It is a value that defines how long to remember a failed request. A duration of 1 or more seconds enables passive health checking. A reasonable starting point might be 30s to balance error rates with responsiveness when bringing an unhealthy upstream back online.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -302,7 +290,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>1</hint>
|
||||
<help><![CDATA[max_fails is the maximum number of failed requests within fail_duration that are needed before considering an upstream to be down.]]></help>
|
||||
<help>max_fails is the maximum number of failed requests within fail_duration that are needed before considering an upstream to be down.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -313,7 +301,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>off</hint>
|
||||
<help><![CDATA[unhealthy_status counts a request as failed if the response comes back with one of these status codes. Can be a 3-digit status code or a status code class ending in xx, for example: 404 or 5xx.]]></help>
|
||||
<help>unhealthy_status counts a request as failed if the response comes back with one of these status codes. Can be a 3-digit status code or a status code class ending in xx, for example: 404 or 5xx.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -324,7 +312,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>off</hint>
|
||||
<help><![CDATA[unhealthy_latency is a duration value in ms that counts a request as failed if it takes this long to get a response.]]></help>
|
||||
<help>unhealthy_latency is a duration value in ms that counts a request as failed if it takes this long to get a response.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -335,7 +323,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>off</hint>
|
||||
<help><![CDATA[unhealthy_request_count is the permissible number of simultaneous requests to a backend before marking it as down. In other words, if a particular backend is currently handling this many requests, then it is considered "overloaded" and other backends will be preferred instead. This should be a reasonably large number; configuring this means that the proxy will have a limit of unhealthy_request_count × upstreams_count total simultaneous requests, and any requests after that point will result in an error due to no upstreams being available.]]></help>
|
||||
<help>unhealthy_request_count is the permissible number of simultaneous requests to a backend before marking it as down. In other words, if a particular backend is currently handling this many requests, then it is considered "overloaded" and other backends will be preferred instead. This should be a reasonably large number; configuring this means that the proxy will have a limit of unhealthy_request_count × upstreams_count total simultaneous requests, and any requests after that point will result in an error due to no upstreams being available.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -345,7 +333,7 @@
|
||||
<label>Active Health URI</label>
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<help><![CDATA[health_uri is the URI path (and optional query) for active health checks.]]></help>
|
||||
<help>health_uri is the URI path (and optional query) for active health checks.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -355,7 +343,7 @@
|
||||
<label>Active Health Upstream</label>
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<help><![CDATA[health_upstream is the ip:port to use for active health checks, if different from the upstream. This should be used in tandem with health_header and {http.reverse_proxy.active.target_upstream}]]></help>
|
||||
<help>health_upstream is the ip:port to use for active health checks, if different from the upstream. This should be used in tandem with health_header and {http.reverse_proxy.active.target_upstream}</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -365,7 +353,7 @@
|
||||
<label>Active Health Port</label>
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<help><![CDATA[health_port is the port to use for active health checks, if different from the upstream's port. Ignored if health_upstream is used.]]></help>
|
||||
<help>health_port is the port to use for active health checks, if different from the upstream's port. Ignored if health_upstream is used.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -376,7 +364,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>30</hint>
|
||||
<help><![CDATA[health_interval is a duration value that defines how often to perform active health checks. Default: 30s.]]></help>
|
||||
<help>health_interval is a duration value that defines how often to perform active health checks. Default: 30s.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -387,7 +375,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>1</hint>
|
||||
<help><![CDATA[health_passes is the number of consecutive health checks required before marking the backend as healthy again. Default: 1.]]></help>
|
||||
<help>health_passes is the number of consecutive health checks required before marking the backend as healthy again. Default: 1.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -398,7 +386,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>1</hint>
|
||||
<help><![CDATA[health_fails is the number of consecutive health checks required before marking the backend as unhealthy. Default: 1.]]></help>
|
||||
<help>health_fails is the number of consecutive health checks required before marking the backend as unhealthy. Default: 1.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -409,7 +397,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>5</hint>
|
||||
<help><![CDATA[health_timeout is a duration value that defines how long to wait for a reply before marking the backend as down. Default: 5s.]]></help>
|
||||
<help>health_timeout is a duration value that defines how long to wait for a reply before marking the backend as down. Default: 5s.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -420,7 +408,7 @@
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<hint>200</hint>
|
||||
<help><![CDATA[health_status is the HTTP status code to expect from a healthy backend. Can be a 3-digit status code, or a status code class ending in xx. For example: 200 (which is the default), or 2xx.]]></help>
|
||||
<help>health_status is the HTTP status code to expect from a healthy backend. Can be a 3-digit status code, or a status code class ending in xx. For example: 200 (which is the default), or 2xx.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -430,7 +418,7 @@
|
||||
<label>Active Health Body</label>
|
||||
<type>text</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<help><![CDATA[health_body is a substring or regular expression to match on the response body of an active health check. If the backend does not return a matching body, it will be marked as down.]]></help>
|
||||
<help>health_body is a substring or regular expression to match on the response body of an active health check. If the backend does not return a matching body, it will be marked as down.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -440,7 +428,7 @@
|
||||
<label>Active Health Follow Redirects</label>
|
||||
<type>checkbox</type>
|
||||
<style>style_reverse_proxy</style>
|
||||
<help><![CDATA[health_follow_redirects will cause the health check to follow redirects provided by upstream. By default, a redirect response would cause the health check to count as a fail.]]></help>
|
||||
<help>health_follow_redirects will cause the health check to follow redirects provided by upstream. By default, a redirect response would cause the health check to count as a fail.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
<type>boolean</type>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<id>header.HeaderUpDown</id>
|
||||
<label>Header</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA["header_up" sets, adds (with the "+" prefix), deletes (with the "-" prefix), or performs a replacement (by using two arguments, a search and replacement) in a request header going upstream to the backend. "header_down" sets, adds (with the "+" prefix), deletes (with the "-" prefix), or performs a replacement (by using two arguments, a search and replacement) in a response header coming downstream from the backend. For more information: https://caddyserver.com/docs/caddyfile/directives/reverse_proxy#headers]]></help>
|
||||
<help>"header_up" sets, adds (with the "+" prefix), deletes (with the "-" prefix), or performs a replacement (by using two arguments, a search and replacement) in a request header going upstream to the backend. "header_down" sets, adds (with the "+" prefix), deletes (with the "-" prefix), or performs a replacement (by using two arguments, a search and replacement) in a response header coming downstream from the backend.</help>
|
||||
<grid_view>
|
||||
<width>120</width>
|
||||
</grid_view>
|
||||
@@ -12,13 +12,13 @@
|
||||
<id>header.HeaderType</id>
|
||||
<label>Header Type</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a header, for example "Host". Use the "+" or "-" prefix to add or remove this header, for example "-Host" or "+Host". A suffix match like "-Host-*" is also supported. To replace a header, use "Host" without "+" or "-".]]></help>
|
||||
<help>Enter a header, for example "Host". Use the "+" or "-" prefix to add or remove this header, for example "-Host" or "+Host". A suffix match like "-Host-*" is also supported. To replace a header, use "Host" without "+" or "-".</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>header.HeaderValue</id>
|
||||
<label>Header Value</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a value for the selected header. One of the most common options is "{upstream_hostport}". It is also possible to use a regular expression to search for a specific value in a header. For example: "^prefix-([A-Za-z0-9]*)$" which uses the regular expression language RE2 included in Go.]]></help>
|
||||
<help>Enter a value for the selected header. One of the most common options is "{upstream_hostport}". It is also possible to use a regular expression to search for a specific value in a header. For example: "^prefix-([A-Za-z0-9]*)$" which uses the regular expression language RE2 included in Go.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -27,7 +27,7 @@
|
||||
<id>header.HeaderReplace</id>
|
||||
<label>Header Replace</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[If a regular expression is used to search for a Header Value, the replacement string can be set here. For example: "replaced-$1-suffix" which expands the replacement string, allowing the use of captured values, "$1" being the first capture group.]]></help>
|
||||
<help>If a regular expression is used to search for a Header Value, the replacement string can be set here. For example: "replaced-$1-suffix" which expands the replacement string, allowing the use of captured values, "$1" being the first capture group.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -36,6 +36,6 @@
|
||||
<id>header.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a description for this header.]]></help>
|
||||
<help>Enter a description for this header.</help>
|
||||
</field>
|
||||
</form>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<id>layer4.enabled</id>
|
||||
<label>Enabled</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Enable this Layer4 route.]]></help>
|
||||
<help>Enable this Layer4 route.</help>
|
||||
<grid_view>
|
||||
<width>20</width>
|
||||
<type>boolean</type>
|
||||
@@ -14,7 +14,7 @@
|
||||
<id>layer4.Sequence</id>
|
||||
<label>Sequence</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Rules are sorted based on the sequence number, higher number means lower priority. Rules without a sequence number will be processed first.]]></help>
|
||||
<help>Rules are sorted based on the sequence number, a higher number means lower priority. Rules without a sequence number will be processed first.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -27,7 +27,7 @@
|
||||
<id>layer4.Type</id>
|
||||
<label>Routing Type</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Choose either "listener_wrappers" for multiplexing protocols on the default HTTP and HTTPS ports on OSI Layer 7, or "global" for raw TCP/UDP traffic routing on a custom "Local port" on OSI Layer 4 with optional OSI Layer 7 protocol matching.]]></help>
|
||||
<help>Choose either "listener_wrappers" for multiplexing protocols on the default HTTP and HTTPS ports on OSI Layer 7, or "global" for raw TCP/UDP traffic routing on a custom "Local port" on OSI Layer 4 with optional OSI Layer 7 protocol matching.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -37,7 +37,7 @@
|
||||
<label>Protocol</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker style_type</style>
|
||||
<help><![CDATA[Match the received traffic on OSI Layer 4, either TCP or UDP. When "Routing Type" is "listener_wrappers", currently only TCP will match.]]></help>
|
||||
<help>Match the received traffic on OSI Layer 4, either TCP or UDP. When "Routing Type" is "listener_wrappers", currently only TCP will match.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -47,7 +47,7 @@
|
||||
<label>Local Port</label>
|
||||
<type>text</type>
|
||||
<style>style_type</style>
|
||||
<help><![CDATA[Choose a custom local port to listen on.]]></help>
|
||||
<help>Choose a custom local port to listen on.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -60,7 +60,7 @@
|
||||
<id>layer4.Matchers</id>
|
||||
<label>Matchers</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Match the received traffic on OSI Layer 7. When choosing a protocol like TLS, it will be matched and routed to the upstream destination. When "Routing Type" of the matcher is "listener_wrapper", any unmatched traffic will be received by the "HTTP App" (reverse_proxy). When "Routing Type" of the matcher is "global", unmatched traffic will be consumed and blocked. Choose "ANY" to not match on OSI Layer 7 and allow any traffic.]]></help>
|
||||
<help>Match the received traffic on OSI Layer 7. When choosing a protocol like TLS, it will be matched and routed to the upstream destination. When "Routing Type" of the matcher is "listener_wrapper", any unmatched traffic will be received by the "HTTP App" (reverse_proxy). When "Routing Type" of the matcher is "global", unmatched traffic will be consumed and blocked. Choose "ANY" to not match on OSI Layer 7 and allow any traffic.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>layer4.FromDomain</id>
|
||||
@@ -68,14 +68,14 @@
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize style_domain</style>
|
||||
<allownew>true</allownew>
|
||||
<help><![CDATA[Enter one or multiple domains to route via SNI or Host Header. Wildcard domains and host wildcards are allowed, e.g. "*.example.com" and "*".]]></help>
|
||||
<help>Enter one or multiple domains to route via SNI or Host Header. Wildcard domains and host wildcards are allowed, e.g. "*.example.com" and "*".</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>layer4.FromOpenvpnModes</id>
|
||||
<label>OpenVPN Mode</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker style_openvpn</style>
|
||||
<help><![CDATA[Select the mode matching the OpenVPN Server or Client.]]></help>
|
||||
<help>Select the mode matching the OpenVPN Server or Client.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -87,7 +87,7 @@
|
||||
<style>selectpicker style_openvpn</style>
|
||||
<hint>Any</hint>
|
||||
<size>5</size>
|
||||
<help><![CDATA[Select a Static Key to match. Multiple Static Keys are only supported for tls-crypt2_client mode.]]></help>
|
||||
<help>Select a Static Key to match. Multiple Static Keys are only supported for tls-crypt2_client mode.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -96,7 +96,7 @@
|
||||
<id>layer4.InvertMatchers</id>
|
||||
<label>Invert Matchers</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Invert the sense of the matcher. E.g., if the protocol is TLS, inverting will match all traffic that is not TLS. When domains have been chosen, these will be equally inverted.]]></help>
|
||||
<help>Invert the sense of the matcher. E.g., if the protocol is TLS, inverting will match all traffic that is not TLS. When domains have been chosen, these will be equally inverted.</help>
|
||||
<advanced>true</advanced>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
@@ -109,7 +109,7 @@
|
||||
<label>Terminate TLS</label>
|
||||
<type>checkbox</type>
|
||||
<style>style_domain</style>
|
||||
<help><![CDATA[Terminate TLS before routing to the upstream. Since this requires a certificate, ensure there is a domain configured in "Reverse Proxy" that matches the SNI of "Domain". The best matching SAN or wildcard certificate will be used automatically for this route.]]></help>
|
||||
<help>Terminate TLS before routing to the upstream. Since this requires a certificate, ensure there is a domain configured in "Reverse Proxy" that matches the SNI of "Domain". The best matching SAN or wildcard certificate will be used automatically for this route.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
<type>boolean</type>
|
||||
@@ -126,7 +126,7 @@
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<allownew>true</allownew>
|
||||
<help><![CDATA[Enter a domain name or IP address of the upstream destination. If multiple are chosen, they will be load balanced with the default random policy.]]></help>
|
||||
<help>Enter a domain name or IP address of the upstream destination. If multiple are chosen, they will be load balanced with the default random policy.</help>
|
||||
<grid_view>
|
||||
<formatter>to_domain</formatter>
|
||||
</grid_view>
|
||||
@@ -135,7 +135,17 @@
|
||||
<id>layer4.ToPort</id>
|
||||
<label>Upstream Port</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Choose a custom port for the upstream destination.]]></help>
|
||||
<help>Choose a custom port for the upstream destination.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
</field>
|
||||
<field>
|
||||
<id>layer4.OriginateTls</id>
|
||||
<label>Originate TLS</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker style_terminate_tls</style>
|
||||
<help>Setting this option will establish a new TLS connection to the upstream after it has been terminated.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -144,7 +154,7 @@
|
||||
<id>layer4.ProxyProtocol</id>
|
||||
<label>Proxy Protocol</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Add the HA Proxy Protocol header. Either version 1 or 2 can be chosen. The default is off, since it is only needed when the upstream can use the Proxy Protocol header.]]></help>
|
||||
<help>Add the HA Proxy Protocol header. Either version 1 or 2 can be chosen. The default is off, since it is only needed when the upstream can use the Proxy Protocol header.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -153,7 +163,7 @@
|
||||
<id>layer4.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a description for this Layer4 route.]]></help>
|
||||
<help>Enter a description for this Layer4 route.</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
@@ -165,7 +175,7 @@
|
||||
<label>Load Balance Policy</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker</style>
|
||||
<help><![CDATA[lb_policy is the name of the load balancing policy, along with any options. For policies that involve hashing, the highest-random-weight (HRW) algorithm is used to ensure that a client or request with the same hash key is mapped to the same upstream, even if the list of upstreams change.]]></help>
|
||||
<help>lb_policy is the name of the load balancing policy, along with any options. For policies that involve hashing, the highest-random-weight (HRW) algorithm is used to ensure that a client or request with the same hash key is mapped to the same upstream, even if the list of upstreams changes.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -175,7 +185,7 @@
|
||||
<label>Passive Health Fail Duration (s)</label>
|
||||
<type>text</type>
|
||||
<hint>off</hint>
|
||||
<help><![CDATA[fail_duration enables a passive health check when multiple destinations in "Upstream Domain" are set. It is a value that defines how long to remember a failed request. A duration of 1 or more seconds enables passive health checking. A reasonable starting point might be 30s to balance error rates with responsiveness when bringing an unhealthy upstream back online.]]></help>
|
||||
<help>fail_duration enables a passive health check when multiple destinations in "Upstream Domain" are set. It is a value that defines how long to remember a failed request. A duration of 1 or more seconds enables passive health checking. A reasonable starting point might be 30s to balance error rates with responsiveness when bringing an unhealthy upstream back online.</help>
|
||||
<advanced>true</advanced>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
@@ -186,7 +196,7 @@
|
||||
<label>Passive Health Max Fails</label>
|
||||
<type>text</type>
|
||||
<hint>1</hint>
|
||||
<help><![CDATA[max_fails is the maximum number of failed requests within fail_duration that are needed before considering an upstream to be down.]]></help>
|
||||
<help>max_fails is the maximum number of failed requests within fail_duration that are needed before considering an upstream to be down.</help>
|
||||
<advanced>true</advanced>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
@@ -202,7 +212,7 @@
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<allownew>true</allownew>
|
||||
<help><![CDATA[Enter one or multiple IP addresses and networks. Leaving this empty will allow any remote client to connect. If populated and the remote IP address of a client matches, the connection to the "Upstream Domain" is allowed, otherwise the connection is dropped. Due to restrictions with this matcher, this list can not be inverted.]]></help>
|
||||
<help>Enter one or multiple IP addresses and networks. Leaving this empty will allow any remote client to connect. If populated and the remote IP address of a client matches, the connection to the "Upstream Domain" is allowed, otherwise the connection is dropped. Due to restrictions with this matcher, this list can not be inverted.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<id>reverse.enabled</id>
|
||||
<label>Enabled</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Enable this domain.]]></help>
|
||||
<help>Enable this domain.</help>
|
||||
<grid_view>
|
||||
<width>20</width>
|
||||
<type>boolean</type>
|
||||
@@ -18,7 +18,7 @@
|
||||
<id>reverse.DisableTls</id>
|
||||
<label>Protocol</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[When choosing HTTP, automatic certificate management will be disabled and all traffic to and from this domain will be unencrypted.]]></help>
|
||||
<help>When choosing HTTP, automatic certificate management will be disabled and all traffic to and from this domain will be unencrypted.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -27,7 +27,7 @@
|
||||
<id>reverse.FromDomain</id>
|
||||
<label>Domain</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a domain name. For a base domain, use "example.com" or "opn.example.com". For a wildcard domain, use "*.example.com". Using a wildcard domain with subdomains requires a "DNS Provider" and the "DNS-01 Challenge" or a custom certificate.]]></help>
|
||||
<help>Enter a domain name. For a base domain, use "example.com" or "opn.example.com". For a wildcard domain, use "*.example.com". Using a wildcard domain with subdomains requires a "DNS Provider" and the "DNS-01 Challenge" or a custom certificate.</help>
|
||||
<grid_view>
|
||||
<formatter>from_domain</formatter>
|
||||
</grid_view>
|
||||
@@ -36,7 +36,7 @@
|
||||
<id>reverse.FromPort</id>
|
||||
<label>Port</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Leave empty to use ports 80 and 443 with automatic redirection from HTTP to HTTPS or choose a custom port. Don't forget to allow these ports with a Firewall rule. If the default ports have been changed in "General Settings", leaving this empty will use the chosen alternative ports instead.]]></help>
|
||||
<help>Leave empty to use ports 80 and 443 with automatic redirection from HTTP to HTTPS or choose a custom port. Don't forget to allow these ports with a Firewall rule. If the default ports have been changed in "General Settings", leaving this empty will use the chosen alternative ports instead.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -46,7 +46,7 @@
|
||||
<label>Certificate</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker style_tls_reverse</style>
|
||||
<help><![CDATA[Choose "Auto HTTPS" to get automatic "Let's Encrypt" or "ZeroSSL" certificates; no additional plugin required. Alternatively, choose a custom certificate from "System - Trust - Certificates" for this domain, e.g., certificates managed by the optional os-acme-client plugin.]]></help>
|
||||
<help>Choose "Auto HTTPS" to get automatic "Let's Encrypt" or "ZeroSSL" certificates; no additional plugin required. Alternatively, choose a custom certificate from "System - Trust - Certificates" for this domain, e.g., certificates managed by the optional os-acme-client plugin.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -55,7 +55,7 @@
|
||||
<id>reverse.AcmePassthrough</id>
|
||||
<label>HTTP-01 Challenge Redirection</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a domain name or IP address. The HTTP-01 challenge will be redirected to that destination. This enables an ACME Client behind Caddy to serve "/.well-known/acme-challenge/" on port 80. Caddy will reverse proxy the HTTP-01 challenge for this domain, and will still issue a certificate using the TLS-ALPN-01 challenge or DNS-01 challenge for itself. This option can be used for High Availability when using Caddy with a master and backup OPNsense.]]></help>
|
||||
<help>Enter a domain name or IP address. The HTTP-01 challenge will be redirected to that destination. This enables an ACME Client behind Caddy to serve "/.well-known/acme-challenge/" on port 80. Caddy will reverse proxy the HTTP-01 challenge for this domain, and will still issue a certificate using the TLS-ALPN-01 challenge or DNS-01 challenge for itself. This option can be used for High Availability when using Caddy with a master and backup OPNsense.</help>
|
||||
<advanced>true</advanced>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
@@ -66,7 +66,7 @@
|
||||
<label>DNS-01 Challenge</label>
|
||||
<type>checkbox</type>
|
||||
<style>style_tls_reverse</style>
|
||||
<help><![CDATA[Enable the DNS-01 Challenge for this domain. Requires a "DNS Provider" in "General Settings". This is only needed for wildcard domains, or when the default challenges can not be used due to restrictive firewall policies.]]></help>
|
||||
<help>Enable the DNS-01 Challenge for this domain. Requires a "DNS Provider" in "General Settings". This is only needed for wildcard domains, or when the default challenges can not be used due to restrictive firewall policies.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
<type>boolean</type>
|
||||
@@ -77,7 +77,7 @@
|
||||
<id>reverse.DnsChallengeOverrideDomain</id>
|
||||
<label>DNS-01 Override Domain</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[If using CNAME delegation for DNS-01 challenges, enter the target domain here. The DNS provider will manage TXT records at '_acme-challenge.targetdomain' instead of the certificate domain. Your configured DNS Provider must have write access to this target domain. For wildcard certificates, ensure the CNAME delegation covers the _acme-challenge label. This enables least-privilege setups or can be used as a workaround when the primary DNS provider lacks an API. Leave empty if your DNS Provider has a dedicated field for this.]]></help>
|
||||
<help>If using CNAME delegation for DNS-01 challenges, enter the target domain here. The DNS provider will manage TXT records at '_acme-challenge.targetdomain' instead of the certificate domain. Your configured DNS Provider must have write access to this target domain. For wildcard certificates, ensure the CNAME delegation covers the _acme-challenge label. This enables least-privilege setups or can be used as a workaround when the primary DNS provider lacks an API. Leave empty if your DNS Provider has a dedicated field for this.</help>
|
||||
<advanced>true</advanced>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
@@ -87,7 +87,7 @@
|
||||
<id>reverse.DynDns</id>
|
||||
<label>Dynamic DNS</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Enable or disable Dynamic DNS. Requires a "DNS Provider" in "General Settings". The DNS records of this domain will be automatically updated. A wildcard domain will create a "*.example.com" record. A base domain will create a "example.com" or "opn.example.com" record. Some providers need subdomains to set records for domains like "opn.example.com"; in that case use the checkbox in the subdomains tab.]]></help>
|
||||
<help>Enable or disable Dynamic DNS. Requires a "DNS Provider" in "General Settings". The DNS records of this domain will be automatically updated. A wildcard domain will create a "*.example.com" record. A base domain will create a "example.com" or "opn.example.com" record. Some providers need subdomains to set records for domains like "opn.example.com"; in that case use the checkbox in the subdomains tab.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
<type>boolean</type>
|
||||
@@ -98,7 +98,7 @@
|
||||
<id>reverse.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a description for this domain.]]></help>
|
||||
<help>Enter a description for this domain.</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
@@ -108,7 +108,7 @@
|
||||
<id>reverse.accesslist</id>
|
||||
<label>Access List</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select an Access List to restrict access to this domain. If unset, any local or remote client is allowed access.]]></help>
|
||||
<help>Select an Access List to restrict access to this domain. If unset, any local or remote client is allowed access.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -118,7 +118,7 @@
|
||||
<label>Basic Auth</label>
|
||||
<type>select_multiple</type>
|
||||
<size>5</size>
|
||||
<help><![CDATA[Select Users to restrict access to this domain. Basic Auth matches after Access Lists. If unset, any user is allowed access. When using CrowdSec, authorization failures will result in automatic bans.]]></help>
|
||||
<help>Select Users to restrict access to this domain. Basic Auth matches after Access Lists. If unset, any user is allowed access.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -127,7 +127,7 @@
|
||||
<id>reverse.ClientAuthTrustPool</id>
|
||||
<label>Client Auth Trust Pool</label>
|
||||
<type>select_multiple</type>
|
||||
<help><![CDATA[Choose multiple CAs or self-signed certificates from "System - Trust - Authorities". Client Auth is activated as soon as at least one certificate has been chosen. Important: Certificate revocation lists are not evaluated. If you need granular control, provide individual self-signed certificates for each device, and unset them to block access. Though keep in mind that if no certificate is left in this field, Client Auth will be deactivated.]]></help>
|
||||
<help>Choose multiple CAs or self-signed certificates from "System - Trust - Authorities". Client Auth is activated as soon as at least one certificate has been chosen. Important: Certificate revocation lists are not evaluated. If you need granular control, provide individual self-signed certificates for each device, and unset them to block access. Though keep in mind that if no certificate is left in this field, Client Auth will be deactivated.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -137,7 +137,7 @@
|
||||
<label>Client Auth Mode</label>
|
||||
<type>dropdown</type>
|
||||
<advanced>true</advanced>
|
||||
<help><![CDATA["request" - Ask clients for a certificate, but allow even if there isn't one; do not verify it. "require" - Require clients to present a certificate, but do not verify it. "verify_if_given" - Ask clients for a certificate; allow even if there isn't one, but verify it if there is. "require_and_verify" - Require clients to present a valid certificate that is verified.]]></help>
|
||||
<help>"request" - Ask clients for a certificate, but allow even if there isn't one; do not verify it. "require" - Require clients to present a certificate, but do not verify it. "verify_if_given" - Ask clients for a certificate; allow even if there isn't one, but verify it if there is. "require_and_verify" - Require clients to present a valid certificate that is verified.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -146,7 +146,7 @@
|
||||
<id>reverse.AccessLog</id>
|
||||
<label>HTTP Access Log</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Enable HTTP request logging for this domain and its subdomains. This option is mostly used for troubleshooting, audits and CrowdSec. It will log every single request.]]></help>
|
||||
<help>Enable HTTP request logging for this domain and its subdomains. This option is mostly used for troubleshooting. It will log every single request.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
<type>boolean</type>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<id>subdomain.enabled</id>
|
||||
<label>Enabled</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Enable this subdomain.]]></help>
|
||||
<help>Enable this subdomain.</help>
|
||||
<grid_view>
|
||||
<width>20</width>
|
||||
<type>boolean</type>
|
||||
@@ -18,7 +18,7 @@
|
||||
<id>subdomain.reverse</id>
|
||||
<label>Domain</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select a wildcard domain for this subdomain.]]></help>
|
||||
<help>Select a wildcard domain for this subdomain.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -27,13 +27,13 @@
|
||||
<id>subdomain.FromDomain</id>
|
||||
<label>Subdomain</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a subdomain. For example, "opn.example.com" if the wildcard domain is "*.example.com". All subdomains use the same ports and protocols as their parent wildcard domain.]]></help>
|
||||
<help>Enter a subdomain. For example, "opn.example.com" if the wildcard domain is "*.example.com". All subdomains use the same ports and protocols as their parent wildcard domain.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>subdomain.DynDns</id>
|
||||
<label>Dynamic DNS</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Enable or disable Dynamic DNS. Requires a "DNS Provider" in "General Settings". The DNS records of this subdomain will be automatically updated.]]></help>
|
||||
<help>Enable or disable Dynamic DNS. Requires a "DNS Provider" in "General Settings". The DNS records of this subdomain will be automatically updated.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
<type>boolean</type>
|
||||
@@ -44,7 +44,7 @@
|
||||
<id>subdomain.AcmePassthrough</id>
|
||||
<label>HTTP-01 Challenge Redirection</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a domain name or IP address. The HTTP-01 challenge will be redirected to that destination. This enables an ACME Client behind Caddy to serve "/.well-known/acme-challenge/" on port 80. Caddy will reverse proxy the HTTP-01 challenge for this subdomain.]]></help>
|
||||
<help>Enter a domain name or IP address. The HTTP-01 challenge will be redirected to that destination. This enables an ACME Client behind Caddy to serve "/.well-known/acme-challenge/" on port 80. Caddy will reverse proxy the HTTP-01 challenge for this subdomain.</help>
|
||||
<advanced>true</advanced>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
@@ -54,7 +54,7 @@
|
||||
<id>subdomain.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a description for this subdomain.]]></help>
|
||||
<help>Enter a description for this subdomain.</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
@@ -64,7 +64,7 @@
|
||||
<id>subdomain.accesslist</id>
|
||||
<label>Access List</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select an Access List to restrict access to this subdomain. If unset, any local or remote client is allowed access.]]></help>
|
||||
<help>Select an Access List to restrict access to this subdomain. If unset, any local or remote client is allowed access.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -74,7 +74,7 @@
|
||||
<label>Basic Auth</label>
|
||||
<type>select_multiple</type>
|
||||
<size>5</size>
|
||||
<help><![CDATA[Select Users to restrict access to this subdomain. Basic Auth matches after Access Lists. If unset, any user is allowed access.]]></help>
|
||||
<help>Select Users to restrict access to this subdomain. Basic Auth matches after Access Lists. If unset, any user is allowed access.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -83,7 +83,7 @@
|
||||
<id>subdomain.ClientAuthTrustPool</id>
|
||||
<label>Client Auth Trust Pool</label>
|
||||
<type>select_multiple</type>
|
||||
<help><![CDATA[Choose multiple CAs or self-signed certificates from "System - Trust - Authorities". Client Auth is activated as soon as at least one certificate has been chosen. Important: Certificate revocation lists are not evaluated. If you need granular control, provide individual self-signed certificates for each device, and unset them to block access. Though keep in mind that if no certificate is left in this field, Client Auth will be deactivated.]]></help>
|
||||
<help>Choose multiple CAs or self-signed certificates from "System - Trust - Authorities". Client Auth is activated as soon as at least one certificate has been chosen. Important: Certificate revocation lists are not evaluated. If you need granular control, provide individual self-signed certificates for each device, and unset them to block access. Though keep in mind that if no certificate is left in this field, Client Auth will be deactivated.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
@@ -93,7 +93,7 @@
|
||||
<label>Client Auth Mode</label>
|
||||
<type>dropdown</type>
|
||||
<advanced>true</advanced>
|
||||
<help><![CDATA["request" - Ask clients for a certificate, but allow even if there isn't one; do not verify it. "require" - Require clients to present a certificate, but do not verify it. "verify_if_given" - Ask clients for a certificate; allow even if there isn't one, but verify it if there is. "require_and_verify" - Require clients to present a valid certificate that is verified.]]></help>
|
||||
<help>"request" - Ask clients for a certificate, but allow even if there isn't one; do not verify it. "require" - Require clients to present a certificate, but do not verify it. "verify_if_given" - Ask clients for a certificate; allow even if there isn't one, but verify it if there is. "require_and_verify" - Require clients to present a valid certificate that is verified.</help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
|
||||
@@ -4,25 +4,25 @@
|
||||
<id>caddy.general.enabled</id>
|
||||
<label>Enable Caddy</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Enable or disable the Caddy web server.]]></help>
|
||||
<help>Enable or disable the Caddy web server.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.EnableLayer4</id>
|
||||
<label>Enable Layer4 Proxy</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Enable Layer4 Proxy to stream TCP/UDP. Layer4 Proxy matches before the Reverse Proxy; both can be used concurrently. More information: https://github.com/mholt/caddy-l4]]></help>
|
||||
<help>Enable Layer4 Proxy to stream TCP/UDP. Layer4 Proxy matches before the Reverse Proxy; both can be used concurrently.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.TlsEmail</id>
|
||||
<label>ACME Email</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter the email address for certificate notifications. This is required to receive automatic certificates from "Let's Encrypt" and "ZeroSSL".]]></help>
|
||||
<help>Enter the email address for certificate notifications. This is required to receive automatic certificates from "Let's Encrypt" and "ZeroSSL".</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.TlsAutoHttps</id>
|
||||
<label>Auto HTTPS</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select the Auto HTTPS option. "On (default)" creates automatic certificates using "Let's Encrypt" or "ZeroSSL". "Off" turns all automatic certificate requests off.]]></help>
|
||||
<help>Select the Auto HTTPS option. "On (default)" creates automatic certificates using "Let's Encrypt" or "ZeroSSL". "Off" turns all automatic certificate requests off.</help>
|
||||
</field>
|
||||
</tab>
|
||||
<tab id="general-advanced" description="Advanced Settings">
|
||||
@@ -34,7 +34,7 @@
|
||||
<id>caddy.general.DisableSuperuser</id>
|
||||
<label>System User</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Run this service as "www" user and group, instead of "root". This setting increases security, but comes with the hard restriction that the well-known port range can not be used anymore. After enabling and saving this setting, the service has to be totally restarted. For this, please disable Caddy and press Apply. Afterwards enable Caddy and press Apply. This setting is reversible by following the same steps.]]></help>
|
||||
<help>Run this service as "www" user and group, instead of "root". This setting increases security, but comes with the hard restriction that the well-known port range can not be used anymore. After enabling and saving this setting, the service has to be totally restarted. For this, please disable Caddy and press Apply. Afterwards enable Caddy and press Apply. This setting is reversible by following the same steps.</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
@@ -44,21 +44,21 @@
|
||||
<id>caddy.general.HttpVersions</id>
|
||||
<label>HTTP Versions</label>
|
||||
<type>select_multiple</type>
|
||||
<help><![CDATA[Select the HTTP versions for the frontend listeners. By default, QUIC (HTTP/3) is disabled.]]></help>
|
||||
<help>Select the HTTP versions for the frontend listeners. By default, QUIC (HTTP/3) is disabled.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.HttpPort</id>
|
||||
<label>HTTP Port</label>
|
||||
<type>text</type>
|
||||
<hint>80</hint>
|
||||
<help><![CDATA[If the default HTTP port is changed to e.g. 8080, then a port forward from port 80 to 8080 is necessary to issue automatic certificates with the HTTP-01 challenge and serve clients the reverse proxied resources.]]></help>
|
||||
<help>If the default HTTP port is changed to e.g. 8080, then a port forward from port 80 to 8080 is necessary to issue automatic certificates with the HTTP-01 challenge and serve clients the reverse proxied resources.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.HttpsPort</id>
|
||||
<label>HTTPS Port</label>
|
||||
<type>text</type>
|
||||
<hint>443</hint>
|
||||
<help><![CDATA[If the default HTTPS port is changed to e.g. 8443, then a port forward from port 443 to 8443 is necessary to issue automatic certificates with the TLS-ALPN-01 challenge and serve clients the reverse proxied resources.]]></help>
|
||||
<help>If the default HTTPS port is changed to e.g. 8443, then a port forward from port 443 to 8443 is necessary to issue automatic certificates with the TLS-ALPN-01 challenge and serve clients the reverse proxied resources.</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
@@ -68,7 +68,7 @@
|
||||
<id>caddy.general.accesslist</id>
|
||||
<label>Trusted Proxies</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select an Access List to set IP ranges of Trusted Proxies. Access Lists can be added in "Reverse Proxy - Access". If Caddy is not the first server being connected to by clients (for example, when a "CDN" is in front of Caddy), configure "Trusted Proxies" with a list of IP ranges (CIDRs) from which incoming requests are trusted to have sent good values for these headers. Additionally, set the same Access List to the domains the Trusted Proxies connect to.]]></help>
|
||||
<help>Select an Access List to set IP ranges of Trusted Proxies. Access Lists can be added in "Reverse Proxy - Access". If Caddy is not the first server being connected to by clients (for example, when a "CDN" is in front of Caddy), configure "Trusted Proxies" with a list of IP ranges (CIDRs) from which incoming requests are trusted to have sent good values for these headers. Additionally, set the same Access List to the domains the Trusted Proxies connect to.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.ClientIpHeaders</id>
|
||||
@@ -78,42 +78,42 @@
|
||||
<size>5</size>
|
||||
<style>selectpicker</style>
|
||||
<hint>X-Forwarded-For</hint>
|
||||
<help><![CDATA[Select one or multiple headers to extract the real client IP. Headers can be added in "Reverse Proxy - Headers". As example, setting "X-Forwarded-For" and "Cf-Connecting-Ip" can extract the real client IP from Cloudflare.]]></help>
|
||||
<help>Select one or multiple headers to extract the real client IP. Headers can be added in "Reverse Proxy - Headers". As example, setting "X-Forwarded-For" and "Cf-Connecting-Ip" can extract the real client IP from Cloudflare.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.GracePeriod</id>
|
||||
<label>Grace Period</label>
|
||||
<type>text</type>
|
||||
<hint>10</hint>
|
||||
<help><![CDATA[Defines the grace period for shutting down Caddy during a reload in seconds. If clients do not finish their requests within the grace period, the server will be forcefully terminated to allow the reload to complete and free up resources. This can influence how long "Apply" of new configurations take, since Caddy waits for all open connections to close. If the grace period is over and Caddy is unresponsive, there will be a forced kill and service restart.]]></help>
|
||||
<help>Defines the grace period for shutting down Caddy during a reload in seconds. If clients do not finish their requests within the grace period, the server will be forcefully terminated to allow the reload to complete and free up resources. This can influence how long "Apply" of new configurations take, since Caddy waits for all open connections to close. If the grace period is over and Caddy is unresponsive, there will be a forced kill and service restart.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.timeout_read_body</id>
|
||||
<label>Read Body Timeout</label>
|
||||
<type>text</type>
|
||||
<hint>no timout</hint>
|
||||
<help><![CDATA[read_body is a duration value in seconds that sets how long to allow a read from a client's upload. Setting this to a short, non-zero value can mitigate slowloris attacks, but may also affect legitimately slow clients.]]></help>
|
||||
<hint>no timeout</hint>
|
||||
<help>read_body is a duration value in seconds that sets how long to allow a read from a client's upload. Setting this to a short, non-zero value can mitigate slowloris attacks, but may also affect legitimately slow clients.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.timeout_read_header</id>
|
||||
<label>Read Header Timeout</label>
|
||||
<type>text</type>
|
||||
<hint>no timout</hint>
|
||||
<help><![CDATA[read_header is a duration value in seconds that sets how long to allow a read from a client's request headers.]]></help>
|
||||
<hint>no timeout</hint>
|
||||
<help>read_header is a duration value in seconds that sets how long to allow a read from a client's request headers.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.timeout_write</id>
|
||||
<label>Write Timeout</label>
|
||||
<type>text</type>
|
||||
<hint>no timout</hint>
|
||||
<help><![CDATA[write is a duration value in seconds that sets how long to allow a write to a client. Note that setting this to a small value when serving large files may negatively affect legitimately slow clients.]]></help>
|
||||
<hint>no timeout</hint>
|
||||
<help>write is a duration value in seconds that sets how long to allow a write to a client. Note that setting this to a small value when serving large files may negatively affect legitimately slow clients.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.timeout_idle</id>
|
||||
<label>Idle Timeout</label>
|
||||
<type>text</type>
|
||||
<hint>300</hint>
|
||||
<help><![CDATA[idle is a duration value in seconds that sets the maximum time to wait for the next request when keep-alives are enabled. Defaults value helps to avoid resource exhaustion.]]></help>
|
||||
<help>idle is a duration value in seconds that sets the maximum time to wait for the next request when keep-alives are enabled. The default value helps to avoid resource exhaustion.</help>
|
||||
</field>
|
||||
</tab>
|
||||
<tab id="general-logsettings" description="Log Settings">
|
||||
@@ -121,26 +121,26 @@
|
||||
<id>caddy.general.LogLevel</id>
|
||||
<label>Log Level</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select the minimum global Log Level. "INFO" is the default and should not be changed without a reason, as it displays the ACME Client messages for automatic certificates. This setting does not influence the HTTP Access logs; they always use "INFO", which is their lowest supported Log Level.]]></help>
|
||||
<help>Select the minimum global Log Level. "INFO" is the default and should not be changed without a reason, as it displays the ACME Client messages for automatic certificates. This setting does not influence the HTTP Access logs; they always use "INFO", which is their lowest supported Log Level.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.LogCredentials</id>
|
||||
<label>Log Credentials</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Log all cookies and authorization in HTTP request logging. Use this option combined with "HTTP Access Log" in a "Domain". Enable this option only for troubleshooting.]]></help>
|
||||
<help>Log all cookies and authorization in HTTP request logging. Use this option combined with "HTTP Access Log" in a "Domain". Enable this option only for troubleshooting.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.LogAccessPlain</id>
|
||||
<label>Log HTTP Access in JSON Format</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[Log HTTP access in a standard JSON logfile per domain, e.g., for processing by CrowdSec. Use this option combined with "HTTP Access Log" in a "Domain". Enabling this will make the HTTP Access Log disappear from the standard Log File. Logs can be found in the filesystem at "/var/log/caddy/access/".]]></help>
|
||||
<help>Log HTTP access in a standard JSON logfile per domain. Use this option combined with "HTTP Access Log" in a "Domain". Enabling this will make the HTTP Access Log disappear from the standard Log File. Logs can be found in the filesystem at "/var/log/caddy/access/".</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.LogAccessPlainKeep</id>
|
||||
<label>Keep HTTP Access JSON Logs for (days)</label>
|
||||
<hint>10</hint>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Specify how many days to keep the JSON access logs.]]></help>
|
||||
<help>Specify how many days to keep the JSON access logs.</help>
|
||||
</field>
|
||||
</tab>
|
||||
<tab id="general-dnsprovider" description="DNS Provider">
|
||||
@@ -148,13 +148,13 @@
|
||||
<id>caddy.general.TlsDnsProvider</id>
|
||||
<label>DNS Provider</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select the DNS Provider. If you cannot find your provider here, consider using os-acme-client for the DNS-01 Challenge and os-ddclient for Dynamic DNS as alternatives.]]></help>
|
||||
<help>Select the DNS Provider. If you cannot find your provider here, consider using os-acme-client for the DNS-01 Challenge and os-ddclient for Dynamic DNS as alternatives.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.TlsDnsApiKey</id>
|
||||
<label>API Key</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[This is the standard field for the API Key.]]></help>
|
||||
<help>This is the standard field for the API Key.</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
@@ -164,27 +164,27 @@
|
||||
<id>caddy.general.TlsDnsPropagationResolvers</id>
|
||||
<label>Resolvers</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Leave empty to use the system resolvers (default). Resolvers customizes the DNS resolvers used when performing the DNS challenge; these take precedence over system resolvers or any default ones. If set here, the resolvers will propagate to all configured certificate issuers. If the system resolvers use DNS over TLS, setting an external resolver here is required or the DNS challenge will fail.]]></help>
|
||||
<help>Leave empty to use the system resolvers (default). Resolvers customizes the DNS resolvers used when performing the DNS challenge; these take precedence over system resolvers or any default ones. If set here, the resolvers will propagate to all configured certificate issuers. If the system resolvers use DNS over TLS, setting an external resolver here is required or the DNS challenge will fail.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.TlsDnsPropagationTimeout</id>
|
||||
<label>Disable Propagation Timeout</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[This will disable propagation_timeout.]]></help>
|
||||
<help>This will disable propagation_timeout.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.TlsDnsPropagationTimeoutPeriod</id>
|
||||
<label>Propagation Timeout</label>
|
||||
<type>text</type>
|
||||
<hint>120</hint>
|
||||
<help><![CDATA[propagation_timeout is a duration value in seconds that sets the maximum time to wait for the DNS TXT records to appear when using the DNS challenge.]]></help>
|
||||
<help>propagation_timeout is a duration value in seconds that sets the maximum time to wait for the DNS TXT records to appear when using the DNS challenge.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.TlsDnsPropagationDelay</id>
|
||||
<label>Propagation Delay</label>
|
||||
<type>text</type>
|
||||
<hint>0</hint>
|
||||
<help><![CDATA[propagation_delay is a duration value in seconds that sets how long to wait before starting DNS TXT records propagation checks when using the DNS challenge.]]></help>
|
||||
<help>propagation_delay is a duration value in seconds that sets how long to wait before starting DNS TXT records propagation checks when using the DNS challenge.</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
@@ -194,7 +194,7 @@
|
||||
<id>caddy.general.TlsDnsEchDomain</id>
|
||||
<label>ECH Domain</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enables Encrypted ClientHello (ECH) by using the specified public domain name as the plaintext server name (SNI) in TLS handshakes. More information: https://caddyserver.com/docs/caddyfile/options#ech]]></help>
|
||||
<help>Enables Encrypted ClientHello (ECH) by using the specified public domain name as the plaintext server name (SNI) in TLS handshakes.</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
@@ -204,38 +204,38 @@
|
||||
<id>caddy.general.DynDnsIpVersions</id>
|
||||
<label>IP Version</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select the DynDns IP Version: "IPv4+IPv6" to set IPv4 A-Records and IPv6 AAAA-Records, "IPv4 only" for only A-Records, "IPv6 only" for only AAAA-Records.]]></help>
|
||||
<help>Select the DynDns IP Version: "IPv4+IPv6" to set IPv4 A-Records and IPv6 AAAA-Records, "IPv4 only" for only A-Records, "IPv6 only" for only AAAA-Records.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.DynDnsUpdateOnly</id>
|
||||
<label>Update Only</label>
|
||||
<type>checkbox</type>
|
||||
<help><![CDATA[If enabled, no new DNS records will be created. Only existing records will be updated. This means that the A or AAAA records need to be created manually ahead of time.]]></help>
|
||||
<help>If enabled, no new DNS records will be created. Only existing records will be updated. This means that the A or AAAA records need to be created manually ahead of time.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.DynDnsInterval</id>
|
||||
<label>Check Interval</label>
|
||||
<type>text</type>
|
||||
<hint>1800</hint>
|
||||
<help><![CDATA[Set the interval in seconds to poll for changes in the IP address. Leave empty to use system defaults.]]></help>
|
||||
<help>Set the interval in seconds to poll for changes in the IP address. Leave empty to use system defaults.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.DynDnsTtl</id>
|
||||
<label>Time to Live</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Set the TTL (Time to Live) for DNS records in seconds. Leave empty to use the default of an already existing TTL (when updating only) or the default of the provider API (when creating new records). If explicitely set, values should be as defined in rfc2181 section 8.]]></help>
|
||||
<help>Set the TTL (Time to Live) for DNS records in seconds. Leave empty to use the default of an already existing TTL (when updating only) or the default of the provider API (when creating new records). If explicitly set, values should be as defined in RFC 2181 Section 8.”</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.DynDnsSimpleHttp</id>
|
||||
<label>Check Http</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter a URL to test the current IP address of the firewall via the HTTP protocol. This is generally not needed as Caddy uses default providers to test the current IP addresses. If a custom provider is preferred, enter the "https://" link to an IP address testing website.]]></help>
|
||||
<help>Enter a URL to test the current IP address of the firewall via the HTTP protocol. This is generally not needed as Caddy uses default providers to test the current IP addresses. If a custom provider is preferred, enter the "https://" link to an IP address testing website.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.DynDnsInterface</id>
|
||||
<label>Check Interface</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select an interface to extract the current IP addresses of the firewall. This is generally not needed as Caddy uses default providers to test the current IP addresses. Depending on the specified DynDns IP Version, at most one IPv6 Global Unicast Address and one IPv4 non-RFC1918 Address will be extracted.]]></help>
|
||||
<help>Select an interface to extract the current IP addresses of the firewall. This is generally not needed as Caddy uses default providers to test the current IP addresses. Depending on the specified DynDns IP Version, at most one IPv6 Global Unicast Address and one IPv4 non-RFC1918 Address will be extracted.</help>
|
||||
</field>
|
||||
</tab>
|
||||
<tab id="general-authprovider" description="Auth Provider">
|
||||
@@ -243,31 +243,31 @@
|
||||
<id>caddy.general.AuthProvider</id>
|
||||
<label>Forward Auth Provider</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Select a Forward Auth Provider. It can be added inside a "Handler" by enabling the "Forward Auth" checkbox. For Authelia only the basic subdomain example is supported. More information: https://www.authelia.com/integration/proxies/caddy/#basic-examples. For Authentik custom headers are not supported. More information: https://docs.goauthentik.io/docs/providers/proxy/server_caddy]]></help>
|
||||
<help>Select a Forward Auth Provider. It can be added inside a "Handler" by enabling the "Forward Auth" checkbox.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.AuthToTls</id>
|
||||
<label>Protocol</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[Enable or disable HTTP over TLS (HTTPS) to communicate with the Forward Auth Provider.]]></help>
|
||||
<help>Enable or disable HTTP over TLS (HTTPS) to communicate with the Forward Auth Provider.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.AuthToDomain</id>
|
||||
<label>Forward Auth Domain</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter the domain name or IP address of the chosen Forward Auth Provider.]]></help>
|
||||
<help>Enter the domain name or IP address of the chosen Forward Auth Provider.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.AuthToPort</id>
|
||||
<label>Forward Auth Port</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter the listen port of the chosen Forward Auth Provider.]]></help>
|
||||
<help>Enter the listen port of the chosen Forward Auth Provider.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.AuthToUri</id>
|
||||
<label>Forward Auth URI</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enter the URI of the authz api endpoint.]]></help>
|
||||
<help>Enter the URI of the authz api endpoint.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.CopyHeaders</id>
|
||||
@@ -276,7 +276,7 @@
|
||||
<type>select_multiple</type>
|
||||
<size>5</size>
|
||||
<style>selectpicker</style>
|
||||
<help><![CDATA[Select headers to copy in addition to the default of the chosen provider. Headers can be added in "Reverse Proxy - Headers". As example, copying "Authorization" can pass Basic Auth credentials from the Auth Provider to the reverse proxied application.]]></help>
|
||||
<help>Select headers to copy in addition to the default of the chosen provider. Headers can be added in "Reverse Proxy - Headers". As example, copying "Authorization" can pass Basic Auth credentials from the Auth Provider to the reverse proxied application.</help>
|
||||
</field>
|
||||
</tab>
|
||||
<activetab>general-settings</activetab>
|
||||
|
||||
@@ -42,8 +42,8 @@ class Caddy extends BaseModel
|
||||
$combos = [];
|
||||
foreach ($this->reverseproxy->reverse->iterateItems() as $item) {
|
||||
$key = $item->__reference;
|
||||
$fromDomain = (string) $item->FromDomain;
|
||||
$fromPort = (string) $item->FromPort;
|
||||
$fromDomain = $item->FromDomain->getValue();
|
||||
$fromPort = $item->FromPort->getValue();
|
||||
|
||||
if ($fromPort === '') {
|
||||
$defaultPorts = ['80', '443'];
|
||||
@@ -78,11 +78,11 @@ class Caddy extends BaseModel
|
||||
{
|
||||
foreach ($this->reverseproxy->reverse->iterateItems() as $item) {
|
||||
if ($item->isFieldChanged()) {
|
||||
if ((string) $item->DisableTls === '1') {
|
||||
if ($item->DisableTls->isEqual('1')) {
|
||||
$conflictChecks = [
|
||||
'DnsChallenge' => (string) $item->DnsChallenge === '1',
|
||||
'AcmePassthrough' => !empty((string) $item->AcmePassthrough),
|
||||
'CustomCertificate' => !empty((string) $item->CustomCertificate)
|
||||
'DnsChallenge' => $item->DnsChallenge->isEqual('1'),
|
||||
'AcmePassthrough' => !$item->AcmePassthrough->isEmpty(),
|
||||
'CustomCertificate' => !$item->CustomCertificate->isEmpty()
|
||||
];
|
||||
|
||||
$conflictFields = array_keys(array_filter($conflictChecks));
|
||||
@@ -110,9 +110,9 @@ class Caddy extends BaseModel
|
||||
*/
|
||||
private function checkSuperuserPorts($messages)
|
||||
{
|
||||
if ((string)$this->general->DisableSuperuser === '1') {
|
||||
$httpPort = !empty((string)$this->general->HttpPort) ? (string)$this->general->HttpPort : 80;
|
||||
$httpsPort = !empty((string)$this->general->HttpsPort) ? (string)$this->general->HttpsPort : 443;
|
||||
if ($this->general->DisableSuperuser->isEqual('1')) {
|
||||
$httpPort = !$this->general->HttpPort->isEmpty() ? $this->general->HttpPort->asInt() : 80;
|
||||
$httpsPort = !$this->general->HttpsPort->isEmpty() ? $this->general->HttpsPort->asInt() : 443;
|
||||
|
||||
// Check default HTTP port
|
||||
if ($httpPort < 1024) {
|
||||
@@ -136,7 +136,7 @@ class Caddy extends BaseModel
|
||||
|
||||
// Check ports under domain configurations
|
||||
foreach ($this->reverseproxy->reverse->iterateItems() as $item) {
|
||||
$fromPort = !empty((string)$item->FromPort) ? (string)$item->FromPort : null;
|
||||
$fromPort = !$item->FromPort->isEmpty() ? $item->FromPort->asInt() : null;
|
||||
|
||||
if ($fromPort !== null && $fromPort < 1024) {
|
||||
$messages->appendMessage(new Message(
|
||||
@@ -155,7 +155,7 @@ class Caddy extends BaseModel
|
||||
}
|
||||
|
||||
foreach ($this->reverseproxy->layer4->iterateItems() as $item) {
|
||||
$fromPort = !empty((string)$item->FromPort) ? (string)$item->FromPort : null;
|
||||
$fromPort = !$item->FromPort->isEmpty() ? $item->FromPort->asInt() : null;
|
||||
|
||||
if ($fromPort !== null && $fromPort < 1024) {
|
||||
$messages->appendMessage(new Message(
|
||||
@@ -177,27 +177,27 @@ class Caddy extends BaseModel
|
||||
|
||||
private function checkLayer4Matchers($messages)
|
||||
{
|
||||
foreach ($this->reverseproxy->layer4->iterateItems() as $item) {
|
||||
if ($item->isFieldChanged()) {
|
||||
$key = $item->__reference;
|
||||
foreach ($this->reverseproxy->layer4->iterateItems() as $layer4) {
|
||||
if ($layer4->isFieldChanged()) {
|
||||
$key = $layer4->__reference;
|
||||
if (
|
||||
in_array((string)$item->Matchers, ['httphost', 'tlssni', 'quicsni']) &&
|
||||
empty((string)$item->FromDomain)
|
||||
in_array($layer4->Matchers->getValue(), ['httphost', 'tlssni', 'quicsni']) &&
|
||||
$layer4->FromDomain->isEmpty()
|
||||
) {
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(
|
||||
gettext(
|
||||
'When "%s" matcher is selected, domain is required.'
|
||||
),
|
||||
$item->Matchers
|
||||
$layer4->Matchers->getValue()
|
||||
),
|
||||
$key . ".FromDomain"
|
||||
));
|
||||
} elseif (
|
||||
!in_array((string)$item->Matchers, ['httphost', 'tlssni', 'quicsni']) &&
|
||||
!in_array($layer4->Matchers->getValue(), ['httphost', 'tlssni', 'quicsni']) &&
|
||||
(
|
||||
!empty((string)$item->FromDomain) &&
|
||||
(string)$item->FromDomain != '*'
|
||||
!$layer4->FromDomain->isEmpty() &&
|
||||
!$layer4->FromDomain->isEqual('*')
|
||||
)
|
||||
) {
|
||||
$messages->appendMessage(new Message(
|
||||
@@ -205,96 +205,101 @@ class Caddy extends BaseModel
|
||||
gettext(
|
||||
'When "%s" matcher is selected, domain must be empty or *.'
|
||||
),
|
||||
$item->Matchers
|
||||
$layer4->Matchers->getValue()
|
||||
),
|
||||
$key . ".FromDomain"
|
||||
));
|
||||
}
|
||||
|
||||
if (!in_array((string)$item->Matchers, ['tlssni', 'quicsni']) && !empty((string)$item->TerminateTls)) {
|
||||
if (!in_array($layer4->Matchers->getValue(), ['tlssni', 'quicsni']) && !$layer4->TerminateTls->isEmpty()) {
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(
|
||||
gettext(
|
||||
'When "%s" matcher is selected, TLS can not be terminated.'
|
||||
),
|
||||
$item->Matchers
|
||||
$layer4->Matchers->getValue()
|
||||
),
|
||||
$key . ".TerminateTls"
|
||||
));
|
||||
}
|
||||
|
||||
if ((string)$item->Matchers !== 'openvpn' && !empty((string)$item->FromOpenvpnModes)) {
|
||||
if ($layer4->TerminateTls->isEmpty() && !$layer4->OriginateTls->isEmpty()) {
|
||||
$messages->appendMessage(new Message(
|
||||
gettext(
|
||||
'This field cannot be selected without terminating TLS.'
|
||||
),
|
||||
$key . ".OriginateTls"
|
||||
));
|
||||
}
|
||||
|
||||
if (!$layer4->Matchers->isEqual('openvpn') && !$layer4->FromOpenvpnModes->isEmpty()) {
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(
|
||||
gettext(
|
||||
'When "%s" matcher is selected, field must be empty.'
|
||||
),
|
||||
$item->Matchers
|
||||
$layer4->Matchers->getValue()
|
||||
),
|
||||
$key . ".FromOpenvpnModes"
|
||||
));
|
||||
}
|
||||
|
||||
if ((string)$item->Matchers !== 'openvpn' && !empty((string)$item->FromOpenvpnStaticKey)) {
|
||||
if (!$layer4->Matchers->isEqual('openvpn') && !$layer4->FromOpenvpnStaticKey->isEmpty()) {
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(
|
||||
gettext(
|
||||
'When "%s" matcher is selected, field must be empty.'
|
||||
),
|
||||
$item->Matchers
|
||||
$layer4->Matchers->getValue()
|
||||
),
|
||||
$key . ".FromOpenvpnStaticKey"
|
||||
));
|
||||
}
|
||||
|
||||
if ((string)$item->Type === 'global' && empty((string)$item->FromPort)) {
|
||||
if ($layer4->Type->isEqual('global') && $layer4->FromPort->isEmpty()) {
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(
|
||||
gettext(
|
||||
'When routing type is "%s", port is required.'
|
||||
),
|
||||
$item->Type
|
||||
$layer4->Type->getValue()
|
||||
),
|
||||
$key . ".FromPort"
|
||||
));
|
||||
} elseif ((string)$item->Type !== 'global' && !empty((string)$item->FromPort)) {
|
||||
} elseif (!$layer4->Type->isEqual('global') && !$layer4->FromPort->isEmpty()) {
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(
|
||||
gettext(
|
||||
'When routing type is "%s", port must be empty.'
|
||||
),
|
||||
$item->Type
|
||||
$layer4->Type->getValue()
|
||||
),
|
||||
$key . ".FromPort"
|
||||
));
|
||||
}
|
||||
|
||||
if ((string)$item->Type !== 'global' && ((string)$item->Protocol !== 'tcp')) {
|
||||
if (!$layer4->Type->isEqual('global') && !$layer4->Protocol->isEqual('tcp')) {
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(
|
||||
gettext(
|
||||
'When routing type is "%s", protocol must be TCP.'
|
||||
),
|
||||
$item->Type
|
||||
$layer4->Type->getValue()
|
||||
),
|
||||
$key . ".Protocol"
|
||||
));
|
||||
}
|
||||
|
||||
if (
|
||||
(string)$item->Type !== 'global' &&
|
||||
(
|
||||
(string)$item->Matchers == 'tls' ||
|
||||
(string)$item->Matchers == 'http' ||
|
||||
(string)$item->Matchers == 'quic'
|
||||
)
|
||||
!$layer4->Type->isEqual('global') &&
|
||||
in_array($layer4->Matchers->getValue(), ['tls', 'http', 'quic'])
|
||||
) {
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(
|
||||
gettext(
|
||||
'When routing type is "%s", matchers "HTTP", "TLS" or "QUIC" cannot be chosen.'
|
||||
),
|
||||
$item->Type
|
||||
$layer4->Type->getValue()
|
||||
),
|
||||
$key . ".Matchers"
|
||||
));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<model>
|
||||
<mount>//Pischem/caddy</mount>
|
||||
<description>Caddy Reverse Proxy</description>
|
||||
<version>1.3.7</version>
|
||||
<version>1.3.8</version>
|
||||
<items>
|
||||
<general>
|
||||
<enabled type="BooleanField">
|
||||
@@ -401,15 +401,6 @@
|
||||
<https value="1">https://</https>
|
||||
<h2c value="2">h2c://</h2c>
|
||||
</OptionValues>
|
||||
<Constraints>
|
||||
<check001>
|
||||
<ValidationMessage>HTTPS and NTLM must be enabled at the same time.</ValidationMessage>
|
||||
<type>DependConstraint</type>
|
||||
<addFields>
|
||||
<field1>HttpNtlm</field1>
|
||||
</addFields>
|
||||
</check001>
|
||||
</Constraints>
|
||||
</HttpTls>
|
||||
<HttpVersion type="OptionField">
|
||||
<BlankDesc>HTTP/1.1, HTTP/2 (default)</BlankDesc>
|
||||
@@ -423,13 +414,6 @@
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<MaximumValue>86400</MaximumValue>
|
||||
</HttpKeepalive>
|
||||
<HttpNtlm type="BooleanField">
|
||||
<Constraints>
|
||||
<check001>
|
||||
<reference>HttpNtlm.check001</reference>
|
||||
</check001>
|
||||
</Constraints>
|
||||
</HttpNtlm>
|
||||
<HttpTlsInsecureSkipVerify type="BooleanField"/>
|
||||
<HttpTlsTrustedCaCerts type="CertificateField">
|
||||
<Type>ca</Type>
|
||||
@@ -668,6 +652,12 @@
|
||||
<ToPort type="PortField">
|
||||
<Required>Y</Required>
|
||||
</ToPort>
|
||||
<OriginateTls type="OptionField">
|
||||
<OptionValues>
|
||||
<tls>TLS (Verify certificate)</tls>
|
||||
<tls_insecure_skip_verify>TLS (Skip verification)</tls_insecure_skip_verify>
|
||||
</OptionValues>
|
||||
</OriginateTls>
|
||||
<ProxyProtocol type="OptionField">
|
||||
<BlankDesc>Off (default)</BlankDesc>
|
||||
<OptionValues>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{#
|
||||
# Copyright (c) 2024 Cedrik Pischem
|
||||
# Copyright (c) 2024-2026 Cedrik Pischem
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -75,27 +75,6 @@
|
||||
a_tag.remove(); // Remove the anchor tag
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a BootstrapDialog alert with custom settings.
|
||||
*
|
||||
* @param {string} type - Type of the dialog based on BootstrapDialog types.
|
||||
* @param {string} title - Title of the dialog.
|
||||
* @param {string} message - Message to be displayed in the dialog.
|
||||
*/
|
||||
function showDialogAlert(type, title, message) {
|
||||
BootstrapDialog.show({
|
||||
type: type,
|
||||
title: title,
|
||||
message: message,
|
||||
buttons: [{
|
||||
label: '{{ lang._('Close') }}',
|
||||
action: function(dialogRef) {
|
||||
dialogRef.close();
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch and display Caddyfile and JSON configuration
|
||||
fetchAndDisplay('/api/caddy/diagnostics/caddyfile', '#caddyfileDisplay');
|
||||
fetchAndDisplay('/api/caddy/diagnostics/config', '#jsonDisplay');
|
||||
@@ -116,19 +95,6 @@
|
||||
downloadContent(content, filename, "text/plain");
|
||||
});
|
||||
|
||||
// Event handler for the Validate Caddyfile button
|
||||
$('#validateCaddyfile').click(function() {
|
||||
ajaxGet('/api/caddy/service/validate', null, function(data, status) {
|
||||
if (status === "success" && data && data['status'].toLowerCase() === 'ok') {
|
||||
showDialogAlert(BootstrapDialog.TYPE_SUCCESS, "{{ lang._('Validation Successful') }}", data['message']);
|
||||
} else {
|
||||
showDialogAlert(BootstrapDialog.TYPE_WARNING, "{{ lang._('Validation Error') }}", data['message']); // Show error message from the API
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
showDialogAlert(BootstrapDialog.TYPE_DANGER, "{{ lang._('Validation Request Failed') }}", error); // Show AJAX error
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -163,7 +129,6 @@
|
||||
<div class="content-box">
|
||||
<pre id="caddyfileDisplay" class="display-area"></pre>
|
||||
<button class="btn btn-primary download-btn" id="downloadCaddyfile" type="button">{{ lang._('Download') }}</button>
|
||||
<button class="btn btn-secondary" id="validateCaddyfile" type="button">{{ lang._('Validate Caddyfile') }}</button>
|
||||
<br/><br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{#
|
||||
# Copyright (c) 2023-2025 Cedrik Pischem
|
||||
# Copyright (c) 2023-2026 Cedrik Pischem
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -33,31 +33,6 @@
|
||||
updateServiceControlUI('caddy');
|
||||
});
|
||||
|
||||
/**
|
||||
* Displays an alert message to the user.
|
||||
*
|
||||
* @param {string} message - The message to display.
|
||||
* @param {string} [type="error"] - The type of alert (error or success).
|
||||
*/
|
||||
function showAlert(message, type = "error") {
|
||||
const alertClass = type === "error" ? "alert-danger" : "alert-success";
|
||||
const messageArea = $("#messageArea");
|
||||
messageArea.stop(true, true).hide();
|
||||
messageArea.removeClass("alert-success alert-danger").addClass(alertClass).html(message);
|
||||
messageArea.fadeIn(500).delay(15000).fadeOut(500, function() {
|
||||
$(this).html('');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralizes error handling.
|
||||
* @param {string} type - The type of error.
|
||||
* @param {string} message - The error message.
|
||||
*/
|
||||
function handleError(type, message) {
|
||||
showAlert(message, type);
|
||||
}
|
||||
|
||||
// Event binding for saving forms
|
||||
$('[id^="save_general-"]').each(function () {
|
||||
const $btn = $(this);
|
||||
@@ -77,25 +52,13 @@
|
||||
"/api/caddy/general/set",
|
||||
formId,
|
||||
function () {
|
||||
ajaxGet("/api/caddy/service/validate", null, function (data, status) {
|
||||
if (status === "success" && data && data['status'].toLowerCase() === 'ok') {
|
||||
dfObj.resolve();
|
||||
} else {
|
||||
showAlert(data?.message || "{{ lang._('Validation Error') }}", "error");
|
||||
dfObj.reject();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
showAlert("{{ lang._('Validation request failed: ') }}" + error, "error");
|
||||
dfObj.reject();
|
||||
});
|
||||
dfObj.resolve();
|
||||
},
|
||||
true,
|
||||
function (errorData) {
|
||||
showAlert(errorData.message || "{{ lang._('Validation Error') }}", "error");
|
||||
function () {
|
||||
dfObj.reject();
|
||||
}
|
||||
);
|
||||
|
||||
return dfObj.promise();
|
||||
}
|
||||
});
|
||||
@@ -111,8 +74,4 @@
|
||||
|
||||
<div id="generalTabsContent" class="content-box tab-content">
|
||||
{{ partial("layout_partials/base_tabs_content", ['formData': generalForm]) }}
|
||||
<!-- Message Area for error/success messages -->
|
||||
<div style="max-width: 98%; margin: 10px auto;">
|
||||
<div id="messageArea" class="alert alert-info" style="display: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{#
|
||||
# Copyright (c) 2023-2025 Cedrik Pischem
|
||||
# Copyright (c) 2023-2026 Cedrik Pischem
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -96,79 +96,31 @@
|
||||
{% if entrypoint == 'reverse_proxy' %}
|
||||
|
||||
if (["{{ formGridReverseProxy['table_id'] }}", "{{ formGridSubdomain['table_id'] }}"].includes(grid_id)) {
|
||||
const update_filter = function (selectValues) {
|
||||
suppressFilterReload = true;
|
||||
|
||||
return $('#reverseFilter')
|
||||
.fetch_options('/api/caddy/reverse_proxy/get_all_reverse_domains')
|
||||
.done(function () {
|
||||
$('#reverseFilter')
|
||||
.selectpicker('val', selectValues)
|
||||
.selectpicker('refresh');
|
||||
|
||||
// manually update icon (since we skip .change())
|
||||
const hasSelection = Array.isArray(selectValues) && selectValues.length > 0;
|
||||
$('#reverseFilterIcon')
|
||||
.toggleClass('text-success fa-filter-circle-xmark', hasSelection)
|
||||
.toggleClass('fa-filter', !hasSelection);
|
||||
|
||||
$('#maintabs a[href="#handlers"]').tab('show');
|
||||
|
||||
// manually reload just the handlers grid
|
||||
const grid_id = "{{ formGridHandle['table_id'] }}";
|
||||
if (all_grids[grid_id]) {
|
||||
all_grids[grid_id].bootgrid('reload');
|
||||
}
|
||||
})
|
||||
.always(function () {
|
||||
suppressFilterReload = false;
|
||||
});
|
||||
};
|
||||
|
||||
commands.search_handler = {
|
||||
method: function () {
|
||||
const rowUuid = $(this).data("row-id");
|
||||
if (!rowUuid) return;
|
||||
|
||||
update_filter([rowUuid]);
|
||||
suppressFilterReload = true;
|
||||
|
||||
$('#reverseFilter')
|
||||
.selectpicker('val', [rowUuid])
|
||||
.selectpicker('refresh');
|
||||
|
||||
$('#reverseFilterIcon')
|
||||
.removeClass('fa-filter')
|
||||
.addClass('text-success fa-filter-circle-xmark');
|
||||
|
||||
$('#maintabs a[href="#handlers"]').tab('show');
|
||||
|
||||
all_grids["{{ formGridHandle['table_id'] }}"]?.bootgrid('reload');
|
||||
|
||||
suppressFilterReload = false;
|
||||
},
|
||||
classname: 'fa fa-fw fa-search',
|
||||
title: "{{ lang._('Search Handler') }}",
|
||||
sequence: 20
|
||||
};
|
||||
|
||||
commands.add_handler = {
|
||||
method: function () {
|
||||
const rowUuid = $(this).data("row-id");
|
||||
if (!rowUuid) return;
|
||||
|
||||
open_add_dialog = function (selectValues) {
|
||||
update_filter(selectValues);
|
||||
|
||||
// Ensure selectpicker has values selected before click on add button
|
||||
$('#reverseFilter').one('changed.bs.select', function (e) {
|
||||
$("#" + "{{ formGridHandle['table_id'] }}")
|
||||
.find("button[data-action='add']")
|
||||
.trigger('click');
|
||||
});
|
||||
};
|
||||
|
||||
// Resolve reverse domains, as subdomains need wildcard domain and subdomain in dialog
|
||||
if (grid_id === "{{ formGridSubdomain['table_id'] }}") {
|
||||
ajaxGet(`/api/caddy/reverse_proxy/get_{{ formGridSubdomain['table_id'] }}/` + rowUuid, {}, function (rowData) {
|
||||
const reverseUuids = rowData?.subdomain?.reverse || {};
|
||||
const selectedReverse = Object.entries(reverseUuids).find(([uuid, entry]) => entry.selected === 1);
|
||||
const selectValues = selectedReverse ? [selectedReverse[0], rowUuid] : [rowUuid];
|
||||
open_add_dialog(selectValues);
|
||||
});
|
||||
} else {
|
||||
open_add_dialog([rowUuid]);
|
||||
}
|
||||
},
|
||||
classname: 'fa fa-fw fa-plus',
|
||||
title: "{{ lang._('Add Handler') }}",
|
||||
sequence: 10
|
||||
};
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
@@ -279,28 +231,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Displays an alert message to the user.
|
||||
*
|
||||
* @param {string} message - The message to display.
|
||||
* @param {string} [type="error"] - The type of alert (error or success).
|
||||
*/
|
||||
function showAlert(message, type = "error") {
|
||||
const alertClass = type === "error" ? "alert-danger" : "alert-success";
|
||||
const messageArea = $("#messageArea");
|
||||
|
||||
messageArea.stop(true, true).hide();
|
||||
messageArea.removeClass("alert-success alert-danger").addClass(alertClass).html(message);
|
||||
messageArea.fadeIn(500).delay(15000).fadeOut(500, function() {
|
||||
$(this).html('');
|
||||
});
|
||||
}
|
||||
|
||||
// Hide message area when starting new actions
|
||||
$('input, select, textarea').on('change', function() {
|
||||
$("#messageArea").hide();
|
||||
});
|
||||
|
||||
// Populate domain filter selectpicker
|
||||
$('#reverseFilter').fetch_options('/api/caddy/reverse_proxy/get_all_reverse_domains');
|
||||
|
||||
@@ -311,26 +241,8 @@
|
||||
$('#reverseFilter').trigger('change');
|
||||
});
|
||||
|
||||
// Reconfigure button with custom validation
|
||||
$("#reconfigureAct").SimpleActionButton({
|
||||
onPreAction: function() {
|
||||
const dfObj = new $.Deferred();
|
||||
|
||||
ajaxGet("/api/caddy/service/validate", null, function(data, status) {
|
||||
if (status === "success" && data && data['status'].toLowerCase() === 'ok') {
|
||||
dfObj.resolve();
|
||||
} else {
|
||||
showAlert(data['message'], "error");
|
||||
dfObj.reject();
|
||||
}
|
||||
}).fail(function(xhr, status, error) {
|
||||
showAlert("{{ lang._('Validation request failed: ') }}" + error, "error");
|
||||
dfObj.reject();
|
||||
});
|
||||
|
||||
return dfObj.promise();
|
||||
}
|
||||
});
|
||||
// Reconfigure button
|
||||
$("#reconfigureAct").SimpleActionButton();
|
||||
|
||||
{% if entrypoint == 'reverse_proxy' %}
|
||||
|
||||
@@ -371,12 +283,13 @@
|
||||
|
||||
{% endif %}
|
||||
|
||||
$("#handle\\.HttpTls, #handle\\.HandleDirective, #reverse\\.DisableTls, #layer4\\.Matchers, #layer4\\.Type").on("keyup change", function () {
|
||||
$("#handle\\.HttpTls, #handle\\.HandleDirective, #reverse\\.DisableTls, #layer4\\.Matchers, #layer4\\.Type, #layer4\\.TerminateTls").on("keyup change", function () {
|
||||
const http_tls = String($("#handle\\.HttpTls").val() || "")
|
||||
const handle_directive = String($("#handle\\.HandleDirective").val() || "")
|
||||
const disable_tls = String($("#reverse\\.DisableTls").val() || "")
|
||||
const layer4_matchers = String($("#layer4\\.Matchers").val() || "")
|
||||
const layer4_type = String($("#layer4\\.Type").val() || "")
|
||||
const layer4_terminate_tls = $("#layer4\\.TerminateTls").is(":checked");
|
||||
|
||||
const styleVisibility = [
|
||||
{
|
||||
@@ -403,6 +316,10 @@
|
||||
class: "style_type",
|
||||
visible: layer4_type === "global"
|
||||
},
|
||||
{
|
||||
class: "style_terminate_tls",
|
||||
visible: layer4_terminate_tls
|
||||
},
|
||||
];
|
||||
|
||||
styleVisibility.forEach(style => {
|
||||
@@ -439,13 +356,7 @@
|
||||
const $initial = $tabs.filter(`[href="${location.hash}"]`).first();
|
||||
($initial.length ? $initial : $tabs.first()).tab('show');
|
||||
|
||||
// Trigger handlers tab too (even if not active) to ensure command buttons always work
|
||||
$(document).one('ajaxStop', function () {
|
||||
$('a[href="#handlers"]').triggerHandler('shown.bs.tab');
|
||||
});
|
||||
|
||||
updateServiceControlUI('caddy');
|
||||
$('<div id="messageArea" class="alert alert-info" style="display: none;"></div>').insertBefore('#change_message_base_form');
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -512,11 +423,11 @@
|
||||
<div id="domains" class="tab-pane fade in active">
|
||||
<!-- Reverse Proxy -->
|
||||
<h1 class="custom-header">{{ lang._('Domains') }}</h1>
|
||||
{{ partial('layout_partials/base_bootgrid_table', formGridReverseProxy + {'command_width': '160'})}}
|
||||
{{ partial('layout_partials/base_bootgrid_table', formGridReverseProxy + {'command_width': '120'})}}
|
||||
|
||||
<!-- Subdomains Tab -->
|
||||
<h1 class="custom-header">{{ lang._('Subdomains') }}</h1>
|
||||
{{ partial('layout_partials/base_bootgrid_table', formGridSubdomain + {'command_width': '160'})}}
|
||||
{{ partial('layout_partials/base_bootgrid_table', formGridSubdomain + {'command_width': '120'})}}
|
||||
</div>
|
||||
|
||||
<!-- Handle Tab -->
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 Cedrik Pischem
|
||||
* Copyright (C) 2024-2026 Cedrik Pischem
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -49,24 +49,25 @@ $tempDir = '/usr/local/etc/caddy/certificates/';
|
||||
// leaf certificate chain
|
||||
$certificateRefs = [];
|
||||
|
||||
foreach ((new Caddy())->reverseproxy->reverse->iterateItems() as $reverseItem) {
|
||||
$certRef = (string)$reverseItem->CustomCertificate;
|
||||
if (!empty($certRef)) {
|
||||
$certificateRefs[] = $certRef;
|
||||
$caddyMdl = new Caddy();
|
||||
|
||||
foreach ($caddyMdl->reverseproxy->reverse->iterateItems() as $reverseItem) {
|
||||
if (!$reverseItem->CustomCertificate->isEmpty()) {
|
||||
$certificateRefs[] = $reverseItem->CustomCertificate->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
$certificateRefs = array_unique($certificateRefs);
|
||||
|
||||
foreach ((new Cert())->cert->iterateItems() as $cert) {
|
||||
$refid = (string)$cert->refid;
|
||||
$refid = $cert->refid->getValue();
|
||||
|
||||
if (in_array($refid, $certificateRefs, true)) {
|
||||
$certChain = base64_decode((string)$cert->crt);
|
||||
$certKey = base64_decode((string)$cert->prv);
|
||||
$certChain = base64_decode($cert->crt->getValue());
|
||||
$certKey = base64_decode($cert->prv->getValue());
|
||||
|
||||
if (!empty((string)$cert->caref)) {
|
||||
$ca = CertStore::getCaChain((string)$cert->caref);
|
||||
if (!$cert->caref->isEmpty()) {
|
||||
$ca = CertStore::getCaChain($cert->caref->getValue());
|
||||
if ($ca) {
|
||||
$certChain .= "\n" . $ca;
|
||||
}
|
||||
@@ -80,36 +81,24 @@ foreach ((new Cert())->cert->iterateItems() as $cert) {
|
||||
// ca certificate
|
||||
$caCertRefs = [];
|
||||
|
||||
foreach ((new Caddy())->reverseproxy->handle->iterateItems() as $handleItem) {
|
||||
$caCertField = (string)$handleItem->HttpTlsTrustedCaCerts;
|
||||
|
||||
if (!empty($caCertField)) {
|
||||
$caCertRefs[] = $caCertField;
|
||||
foreach ($caddyMdl->reverseproxy->handle->iterateItems() as $handleItem) {
|
||||
if (!$handleItem->HttpTlsTrustedCaCerts->isEmpty()) {
|
||||
$caCertRefs[] = $handleItem->HttpTlsTrustedCaCerts->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ((new Caddy())->reverseproxy->reverse->iterateItems() as $reverseItem) {
|
||||
$caCertField = (string)$reverseItem->ClientAuthTrustPool;
|
||||
|
||||
if (!empty($caCertField)) {
|
||||
$refs = array_map('trim', explode(',', $caCertField));
|
||||
foreach ($refs as $ref) {
|
||||
if (!empty($ref)) {
|
||||
$caCertRefs[] = $ref;
|
||||
}
|
||||
foreach ($caddyMdl->reverseproxy->reverse->iterateItems() as $reverseItem) {
|
||||
foreach (explode(',', $reverseItem->ClientAuthTrustPool->getValue()) as $ref) {
|
||||
if (!empty($ref)) {
|
||||
$caCertRefs[] = $ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ((new Caddy())->reverseproxy->subdomain->iterateItems() as $subdomainItem) {
|
||||
$caCertField = (string)$subdomainItem->ClientAuthTrustPool;
|
||||
|
||||
if (!empty($caCertField)) {
|
||||
$refs = array_map('trim', explode(',', $caCertField));
|
||||
foreach ($refs as $ref) {
|
||||
if (!empty($ref)) {
|
||||
$caCertRefs[] = $ref;
|
||||
}
|
||||
foreach ($caddyMdl->reverseproxy->subdomain->iterateItems() as $subdomainItem) {
|
||||
foreach (explode(',', $subdomainItem->ClientAuthTrustPool->getValue()) as $ref) {
|
||||
if (!empty($ref)) {
|
||||
$caCertRefs[] = $ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,17 +106,17 @@ foreach ((new Caddy())->reverseproxy->subdomain->iterateItems() as $subdomainIte
|
||||
$caCertRefs = array_unique($caCertRefs);
|
||||
|
||||
foreach ((new Ca())->ca->iterateItems() as $caItem) {
|
||||
$refid = (string)$caItem->refid;
|
||||
$refid = $caItem->refid->getValue();
|
||||
if (in_array($refid, $caCertRefs, true)) {
|
||||
$caCert = base64_decode((string)$caItem->crt);
|
||||
$caCert = base64_decode($caItem->crt->getValue());
|
||||
$writeFileIfChanged($tempDir . $refid . '.pem', $caCert);
|
||||
}
|
||||
}
|
||||
|
||||
// openvpn static keys
|
||||
foreach ((new Caddy())->reverseproxy->layer4openvpn->iterateItems() as $openvpnItem) {
|
||||
foreach ($caddyMdl->reverseproxy->layer4openvpn->iterateItems() as $openvpnItem) {
|
||||
$writeFileIfChanged(
|
||||
$tempDir . (string)$openvpnItem->getAttributes()['uuid'] . '.key',
|
||||
(string)$openvpnItem->StaticKey
|
||||
$tempDir . $openvpnItem->getAttributes()['uuid'] . '.key',
|
||||
$openvpnItem->StaticKey->getValue()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
#!/usr/local/bin/python3
|
||||
|
||||
#
|
||||
# Copyright (c) 2023-2024 Cedrik Pischem
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import signal
|
||||
import time
|
||||
|
||||
|
||||
def kill_and_start_caddy(pidfile):
|
||||
"""
|
||||
Caddy can fail to reload in rare circumstances when
|
||||
persistent keepalive connections are open with the NTLM
|
||||
module active
|
||||
"""
|
||||
if os.path.exists(pidfile):
|
||||
try:
|
||||
with open(pidfile, 'r') as f:
|
||||
pid = int(f.read().strip())
|
||||
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
time.sleep(2)
|
||||
subprocess.run(["service", "caddy", "start"], check=True)
|
||||
except Exception as e:
|
||||
print(f"Error: {str(e)}")
|
||||
else:
|
||||
subprocess.run(["service", "caddy", "start"], check=True)
|
||||
|
||||
|
||||
def run_service_command(service_action, action_message):
|
||||
"""
|
||||
Includes special actions like a validation and
|
||||
timeouts that force a restart when caddy is unresponsive
|
||||
"""
|
||||
result = {"message": action_message}
|
||||
pidfile = "/var/run/caddy/caddy.pid"
|
||||
|
||||
if service_action == "validate":
|
||||
try:
|
||||
validation_output = subprocess.check_output(
|
||||
["caddy", "validate", "--config", "/usr/local/etc/caddy/Caddyfile"], stderr=subprocess.STDOUT,
|
||||
text=True)
|
||||
if "Valid configuration" in validation_output:
|
||||
result["status"] = "ok"
|
||||
result["message"] = "Caddy configuration is valid."
|
||||
else:
|
||||
error_msg = next((line for line in validation_output.split('\n') if line.startswith("Error:")),
|
||||
"Caddy configuration is not valid.")
|
||||
result["status"] = "failed"
|
||||
result["message"] = error_msg
|
||||
except subprocess.CalledProcessError as e:
|
||||
error_msg = next((line for line in e.output.split('\n') if line.startswith("Error:")), "Validation failed.")
|
||||
result["status"] = "failed"
|
||||
result["message"] = error_msg
|
||||
elif service_action in ["stop", "restart", "reloadssl"]:
|
||||
try:
|
||||
proc = subprocess.Popen(["service", "caddy", service_action])
|
||||
try:
|
||||
proc.wait(timeout=20)
|
||||
result["status"] = "ok"
|
||||
except subprocess.TimeoutExpired:
|
||||
kill_and_start_caddy(pidfile)
|
||||
result["status"] = "ok"
|
||||
result["message"] = f"{service_action.capitalize()} took too long, Caddy was forcefully restarted."
|
||||
except subprocess.CalledProcessError as e:
|
||||
result["status"] = "failed"
|
||||
result["message"] = str(e)
|
||||
else:
|
||||
try:
|
||||
subprocess.run(["service", "caddy", service_action], check=True)
|
||||
result["status"] = "ok"
|
||||
except subprocess.CalledProcessError as e:
|
||||
result["status"] = "failed"
|
||||
result["message"] = str(e)
|
||||
|
||||
return json.dumps(result)
|
||||
|
||||
|
||||
# "cmd_action": "service_action"
|
||||
actions = {
|
||||
"start": "start",
|
||||
"stop": "stop",
|
||||
"restart": "restart",
|
||||
"reload": "reloadssl",
|
||||
"validate": "validate"
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
action = sys.argv[1]
|
||||
if action in actions:
|
||||
cmd_action = action
|
||||
service_action = actions[action]
|
||||
message = f"{cmd_action.capitalize()} Caddy service"
|
||||
|
||||
# Call setup script for 'validate' and 'reloadssl' actions. This is needed because the setup script triggers
|
||||
# the caddy_certs.php script, which exports all certificates into the filesystem. Caddy reloads certificates
|
||||
# when reloadssl is used. Because it is a non-standard command, the caddy_setup script will not be triggered
|
||||
# in /etc/rc.conf.d/caddy. The validate command needs it to make sure all certificates are in the filesystem,
|
||||
# because otherwise the validation fails.
|
||||
if service_action in ["validate", "reloadssl"]:
|
||||
subprocess.run(["/usr/local/opnsense/scripts/OPNsense/Caddy/setup.sh"], check=True)
|
||||
|
||||
print(run_service_command(service_action, message))
|
||||
else:
|
||||
print(json.dumps({"status": "failed", "message": f"Unknown action: {action}"}))
|
||||
else:
|
||||
print(json.dumps({"status": "failed", "message": "No action provided"}))
|
||||
@@ -1,35 +1,29 @@
|
||||
[start]
|
||||
command:/usr/local/opnsense/scripts/OPNsense/Caddy/caddy_control.py start
|
||||
command:service caddy start
|
||||
parameters:
|
||||
type:script
|
||||
message:Starting Caddy service
|
||||
|
||||
[stop]
|
||||
command:/usr/local/opnsense/scripts/OPNsense/Caddy/caddy_control.py stop
|
||||
command:service caddy stop
|
||||
parameters:
|
||||
type:script
|
||||
message:Stopping Caddy service
|
||||
|
||||
[restart]
|
||||
command:/usr/local/opnsense/scripts/OPNsense/Caddy/caddy_control.py restart
|
||||
command:service caddy restart
|
||||
parameters:
|
||||
type:script
|
||||
message:Restarting Caddy service
|
||||
description:Restart Caddy service
|
||||
|
||||
[reload]
|
||||
command:/usr/local/opnsense/scripts/OPNsense/Caddy/caddy_control.py reload
|
||||
command:/usr/local/opnsense/scripts/OPNsense/Caddy/setup.sh; service caddy reloadssl
|
||||
parameters:
|
||||
type:script
|
||||
message:Reloading Caddy configuration
|
||||
message:Reloading Caddy service
|
||||
description:Reload Caddy service
|
||||
|
||||
[validate]
|
||||
command:/usr/local/opnsense/scripts/OPNsense/Caddy/caddy_control.py validate
|
||||
parameters:
|
||||
type:script_output
|
||||
message:Validating Caddy configuration
|
||||
|
||||
[status]
|
||||
command:/usr/local/sbin/pluginctl -s caddy status
|
||||
parameters:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{#
|
||||
# Copyright (c) 2023-2025 Cedrik Pischem
|
||||
# Copyright (c) 2023-2026 Cedrik Pischem
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -485,11 +485,7 @@ http://{{ domain }} {
|
||||
handle.HttpTlsTrustedCaCerts or
|
||||
handle.HttpTlsServerName -%}
|
||||
{% if has_transport_options %}
|
||||
{% if handle.HttpNtlm|default("0") == "1" %}
|
||||
transport http_ntlm {
|
||||
{% else %}
|
||||
transport http {
|
||||
{% endif %}
|
||||
{% if handle.HttpVersion %}
|
||||
{% set version_map = {'http1': 1.1, 'http2': 2, 'http3': 3} %}
|
||||
versions {{ version_map[handle.HttpVersion] }}
|
||||
|
||||
@@ -26,22 +26,28 @@
|
||||
{% if layer4.TerminateTls|default("0") == "1" %}
|
||||
tls
|
||||
{% endif %}
|
||||
proxy {% for domain in layer4.ToDomain.split(',') %}
|
||||
proxy {
|
||||
{% for domain in layer4.ToDomain.split(',') %}
|
||||
{% set is_ipv6 = (':' in domain) %}
|
||||
{{ layer4.Protocol }}/{{ '[' if is_ipv6 }}{{ domain }}{{ ']' if is_ipv6 }}:{{ layer4.ToPort }}{% if not loop.last %} {% endif %}
|
||||
{% endfor %} {
|
||||
{% if layer4.lb_policy|default("") %}
|
||||
lb_policy {{ layer4.lb_policy }}
|
||||
{% endif %}
|
||||
{% if layer4.PassiveHealthFailDuration|default("") %}
|
||||
fail_duration {{ layer4.PassiveHealthFailDuration }}s
|
||||
{% endif %}
|
||||
{% if layer4.PassiveHealthMaxFails|default("") %}
|
||||
max_fails {{ layer4.PassiveHealthMaxFails }}
|
||||
{% endif %}
|
||||
{% if layer4.ProxyProtocol %}
|
||||
proxy_protocol {{ layer4.ProxyProtocol }}
|
||||
{% endif %}
|
||||
upstream {{ layer4.Protocol }}/{{ '[' if is_ipv6 }}{{ domain }}{{ ']' if is_ipv6 }}:{{ layer4.ToPort }} {
|
||||
{% if layer4.OriginateTls %}
|
||||
{{ layer4.OriginateTls }}
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
{% if layer4.lb_policy|default("") %}
|
||||
lb_policy {{ layer4.lb_policy }}
|
||||
{% endif %}
|
||||
{% if layer4.PassiveHealthFailDuration|default("") %}
|
||||
fail_duration {{ layer4.PassiveHealthFailDuration }}s
|
||||
{% endif %}
|
||||
{% if layer4.PassiveHealthMaxFails|default("") %}
|
||||
max_fails {{ layer4.PassiveHealthMaxFails }}
|
||||
{% endif %}
|
||||
{% if layer4.ProxyProtocol %}
|
||||
proxy_protocol {{ layer4.ProxyProtocol }}
|
||||
{% endif %}
|
||||
}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user