www/caddy: include os-caddy into OPNsense plugins (#3840)

This commit is contained in:
Monviech
2024-03-08 12:52:21 +01:00
committed by GitHub
parent 5801da41d7
commit 67fb503a71
33 changed files with 3163 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
PLUGIN_NAME= caddy
PLUGIN_VERSION= 1.5.1
PLUGIN_REVISION= 2
PLUGIN_DEPENDS= caddy-custom
PLUGIN_COMMENT= Easy to configure Reverse Proxy based on Caddy with Automatic HTTPS and Dynamic DNS
PLUGIN_MAINTAINER= cedrik@pischem.com
.include "../../Mk/plugins.mk"
+205
View File
@@ -0,0 +1,205 @@
# Caddy Plugin for OPNsense
- This project provides a simple yet powerful plugin for [OPNsense](https://github.com/opnsense) to enable support for [Caddy](https://github.com/caddyserver/caddy).
- The scope is the reverse proxy features.
- The main goal is an easy to configure plugin. Most options that aren't generally needed are hidden behind the advanced mode for this reason.
- The feature set is complete for now.
## Main Features
- Modern and fast Reverse Proxy based on [Caddy](https://caddyserver.com/)
- Automatic Let's Encrypt and ZeroSSL Certificates without configuration with HTTP-01 and TLS-ALPN-01
- ACME DNS-01 challenge with configuration (requires supported DNS Provider)
- Dynamic DNS (DynDns) with configuration (requires supported DNS Provider)
- Supported DNS Providers in GUI: ```cloudflare, duckdns, digitalocean, dnspod, hetzner, godaddy, gandi, ionos, desec, porkbun, route53, acmedns, alidns, googleclouddns, azure, openstack-designate, ovh, namecheap, netlify, namesilo, powerdns, vercel, ddnss, njalla, metaname, linode, tencentcloud, dinahosting, hexonet, mailinabox```
- Use custom certificates from OPNsense certificate store
- Normal domains, wildcard domains and subdomains
- Access Lists to restrict access based on static networks
- Basic Auth to restrict access by username and password
- Syslog-ng integration and HTTP Access Log
- NTLM Transport for Exchange Server
## License
- This project is licensed under the BSD 2-Clause "Simplified" license. See the LICENSE file for details.
- Caddy is licensed under the Apache License, Version 2.0.
- OPNsense is licensed under the BSD 2-Clause “Simplified” license.
## Acknowledgments
- Thanks to the Caddy community/developers for creating a fantastic open source web server.
- Thanks to the OPNsense community/developers for creating a powerful and flexible open source firewall and routing platform.
- Additional big **Thank You** in no particular order: [AdShellevis](https://github.com/Adschellevis), [mimugmail](https://forum.opnsense.org/index.php?action=profile;u=15464), [gspannu](https://github.com/gspannu), [francislavoie](https://caddy.community/u/francislavoie/summary), [matt](https://caddy.community/u/matt/summary), [fichtner](https://github.com/fichtner)
# How to install
- Install "os-caddy" from the OPNsense Plugins.
## Prepare Caddy for use after the installation
**Attention**, additional preparation of OPNsense needed:
- Make sure that port `80` and `443` aren't occupied. You have to change the default listen port to `8443` for example. Go to `System: Settings: Administration` to change the `TCP Port`. Then also enable `HTTP Redirect - Disable web GUI redirect rule`.
- If you have other reverse proxy or webserver plugins installed, make sure they don't use the same ports as Caddy
- Create Firewall rules that allow 80 and 443 TCP to "This Firewall" on WAN and (optionally) LAN, OPT1 etc...
- There is a lot of input validation. If you read all the hints, help texts and error messages, its unlikely that you create a configuration that won't work.
- **Attention**: If you use this in HA (High Availability), only use your own custom certificates. Caddy needs a shared storage for the ACME challenges to work on two or more firewalls in HA at the same time. This is out of scope, since offering shared storage on firewalls where one can potentially fail, would leave the other without storage for Caddy to work with.
# Available Settings in "Services - Caddy Web Server"
**Please note that some options are hidden in advanced mode.**
## General Settings - General
- `Enable` or `disable` Caddy
- `ACME Email`: e.g. `info@example.com`, it's optional.
- `Auto HTTPS`: `On (default)` creates automatic Let's Encrypt Certificates for all Domains that don't have more specific options set, like custom certificates.
- `Trusted Proxies`: Leave empty if you don't use a CDN in front of your OPNsense. If you use Cloudflare or another CDN provider, create an access list with the IP addresses of that CDN and add it here. Add the same Access List to the domain this CDN tries to reach.
- `Abort Connections`: This option, when enabled, aborts all connections to the Reverse Proxy Domain that don't match any specified handler or access list. This setting doesn't affect Let's Encrypt's ability to issue certificates, ensuring secure connections regardless of the option's status. If unchecked, the Reverse Proxy Domain remains accessible even without a matching handler, allowing for connectivity and certificate checks, even in the absence of a configured Backend Server. When using Access Lists, enabling this option is recommended to reject unauthorized connections outright. Without this option, unmatched IP addresses will encounter an empty page instead of an explicit rejection, though the Access Lists continue to function and restrict access.
## General Settings - DNS Provider
- `DNS Provider`: Select the DNS provider for the DNS-01 Challenge and Dynamic DNS. This is optional, since certificates will be requested from Let's Encrypt via HTTP-01 or TLS-ALPN-01 Challenge when this option is unset. You mostly need this for Wildcard Certificates, and for Dynamic DNS. To use the DNS-01 Challenge and Dynamic DNS, enable the checkbox in a Reverse Proxy Domain or Subdomain. For more information: https://github.com/caddy-dns
- `DNS API Standard Field`: This is the standard field for the API Key. Field can be left empty if optional: Cloudflare "api_token", Duckdns "api_token", DigitalOcean "auth_token", DNSPod "auth_token", Hetzner "api_token", Godaddy "api_token", Gandi "bearer_token", IONOS "api_token", deSEC "token", Route53 "access_key_id", Porkbun "api_key", ACME-DNS "username", Netlify "personal_access_token", Namesilo "api_token", Njalla "api_token", Vercel "api_token", Google Cloud DNS "gcp_project", Alidns "access_key_id", Azure "tenant_id", OpenStack Designate "region_name", OVH "endpoint", Namecheap "api_key", PowerDNS "server_url", DDNSS "api_token", Metaname "api_key", Linode "api_token", Tencent Cloud "secret_id", Dinahosting "username", Hexonet "username", Mail-in-a-Box "api_url".
- `DNS API Additional Field 1`: Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Duckdns "override_domain", Route53 "secret_access_key", Porkbun "api_secret_key", ACME-DNS "password", Alidns "access_key_secret", Azure "client_id", OpenStack Designate "tenant_id", OVH "application_key", Namecheap "user", PowerDNS "api_token", DDNSS "username", Metaname "account_reference", Linode "api_url", Tencent Cloud "secret_key", Dinahosting "password", Hexonet "password", Mail-in-a-Box "email_address".
- `DNS API Additional Field 2`: Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "max_retries", ACME-DNS "subdomain", Azure "client_secret", OpenStack Designate "identity_api_version", OVH "application_secret", Namecheap "api_endpoint", DDNSS "password", Linode "api_version", Mail-in-a-Box "password".
- `DNS API Additional Field 3`: Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "aws_profile", ACME-DNS "server_url", Azure "subscription_id", OpenStack Designate "password", OVH "consumer_key", Namecheap "client_ip", DDNS "password".
- `DNS API Additional Field 4`: Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "region", Azure "resource_group_name", OpenStack Designate "username".
- `DNS API Additional Field 5`: Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "token", OpenStack Designate "tenant_name".
- `DNS API Additional Field 6`: Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: OpenStack Designate "auth_url".
- `DNS API Additional Field 7`: Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: OpenStack Designate "endpoint_type".
## General Settings - Dynamic DNS
- `DynDns Check Http`: Optionally, enter an URL to test the current IP address of the firewall via HTTP procotol. Generally, this is not needed. Caddy uses default providers to test the current IP addresses. If you rather use your own, enter the https:// link to an IP address testing website.
- `DynDns Check Interface`: Optionally, select an interface to extract the current IP address of the firewall. Attention, all IP addresses will be read from this interface. Only choose this option if you know the implications.
- `DynDns Check Interval`: Interval to poll for changes of the IP address. The default is 5 minutes. Can be a number between 1 to 1440 minutes.
- `DynDns IP Version`: Leave on None to set IPv4 A-Records and IPv6 AAAA-Records. Select "Ipv4 only" for setting A-Records. Select "IPv6 only" for setting AAAA-Records.
- `DynDns TTL`: Set the TTL (time to live) for DNS Records. The default is 1 hour. Can be a number between 1 to 24 hours.
## General Settings - Log Settings
- `Log Credentials`: Log all Cookies and Authorization in HTTP request logging. Use combined with HTTP Access Log in the Reverse Proxy Domain. Enable this option only for troubleshooting.
- `Log Access in Plain Format`: Don't send HTTP(S) access logs to the central OPNsense logging facility but save them in plain Caddy JSON format in a subdirectory instead. Only effective for Reverse Proxy Domains that have HTTP Access Log enabled. The feature is intended to have access log files processed by e.g. CrowdSec. They can be found in `/var/log/caddy/access`.
- `Keep Plain Access Logs for (days)`: How many days until the plain format log files are deleted.
## Reverse Proxy - Domains
- Press `+` to create a new Reverse Proxy Domain
- `Enable` this new entry
- `Reverse Proxy Domain`: Can either be a domain name or an IP address. If a domain name is chosen, Caddy will automatically try to get an ACME certificate, and the header will be automatically passed to the Server in the backend.
- `Reverse Proxy Port`: Should be the port the OPNsense will listen on. Don't forget to create Firewall rules that allow traffic to this port on `WAN` or `LAN` to `This Firewall`. You can leave this empty if you want to use the default ports of Caddy (`80` and `443`) with automatic redirection from HTTP to HTTPS.
- `Access List`: Restrict the access to this domain to a list of IP addresses you define in the `Access` Tab. This doesn't influence the Let's Encrypt certificate generation, so you can be as restrictive as you want here.
- `Basic Auth`: Restrict the access to this domain to one or multiple users you define in the `Access` Tab. This doesn't influence the Let's Encrypt certificate generation, so you can be as restrictive as you want here.
- `DNS-01 challenge`: Enable this if you want to use the `DNS-01` ACME challenge instead of HTTP challenge. This can be set per entry, so you can have both types of challenges at the same time for different entries. This option needs the `General Settings` - `DNS Provider` and `API KEY` set.
- `Dynamic DNS`: Enable Dynamic DNS, please configure DNS Provider and API Key in General Settings. The DNS Records of this domain will be automatically updated with your DNS Provider.
- `Custom Certificate`: Use a Certificate you imported or generated in `System - Trust - Certificates`. The chain is generated automatically. `Certificate + Intermediate CA + Root CA`, `Certificate + Root CA` and `self signed Certificate` are all fully supported.
- `HTTP Access Log`: Enable the HTTP request logging for this domain and its subdomains. This option is mostly for troubleshooting since it will log every single request.
- `Description`: The description is mandatory. Create descriptions for each domain. Since there could be multiples of the same domain with different ports, do it like this: `foo.example.com` and `foo.example.com.8443`.
## Reverse Proxy - Subdomains
- Press `+` to create a new Reverse Proxy Subdomain
- `Reverse Proxy Domain` - Choose a wildcard domain you prepared in "Reverse Proxy - Domains", it has to be formatted like `*.example.com`
- `Reverse Proxy Subdomain` - Create a name that is seated under the Wildcard domain, for example `foo.example.com` and `bar.example.com`.
- For the other options refer to Domains.
## Reverse Proxy - Handler
Please note that the order that handlers are saved in the scope of each domain or domain/subdomain can influence functionality - The first matching handler wins. So if you put /ui* in front of a more specific handler like /ui/opnsense, the /ui* will match first and /ui/opnsense won't ever match (in the scope of their domain). Right now there isn't an easy way to move the position of handlers in the grid, so you have to clone them if you want to change their order, and delete the old entries afterwards. Most of the time, creating just one empty catch-all handler is the best choice. The template logic makes sure that catch-all handlers are always placed last, after all other handlers.
- Press `+` to create a new `Handler`. A Handler is like a location in nginx.
- `Enable` this new entry.
- `Reverse Proxy Domain`: Select the domain you have created in `Reverse Proxy Domains`.
- `Reverse Proxy Subdomain`: Leave this on `None`. It is not needed without having a wildcard certificate, or a `*.example.com` Domain.
- `Handle Type`: `Handle` or `Handle Path` can be chosen. If in doubt, always use `Handle`, the most common option. `Handle Path` is used to strip the path from the URI. For example if you have example.com/opnsense internally, but want to call it with just example.com externally.
- `Handle Path`: Leave this empty if you want to create a catch all location. You can create multiple Handler entries, and have each of them point at different locations like `/foo/*` or `/foo/bar/*` or `/foo*`.
- `Backend Server Domain`: Should be an internal domain name or an IP Address of the Backend Server that should receive the traffic of the `Reverse Proxy Domain`.
- `Backend Server Port`: Should be the port the Backend Server listens on. This can be left empty to use Caddy default ports 80 and 443.
- `Backend Server Path`: In case the backend application resides in a sub-path of the web root and you don't want this path visible in the frontend URL you can use this setting to prepend an initial path starting with '/' to every backend request. Java applications running in a servlet container like Tomcat are known to behave this way, so you can set it to e.g. '/guacamole' to access Apache Guacamole at the frontend root URL without needing a redirect.
- `TLS`: If your Backend Server only accepts HTTPS, enable this option. If the Backend Server has a globally trusted certificate, this is all you need.
- `TLS Trusted CA Certificates`: Choose a CA certificate to trust for the Backend Server connection. Import your self-signed certificate or your CA certificate into the OPNsense "System - Trust - Authorities" store, and select it here.
- `TLS Server Name`: If the SAN (Subject Alternative Names) of the offered trusted CA certificate or self-signed certificate doesn't match with the IP address or hostname of the `Backend Server Domain`, you can enter it here. This will change the SNI (Server Name Identification) of Caddy to the `TLS Server Name`. IP address e.g. `192.168.1.1` or hostname e.g. `localhost` or `opnsense.local` are all valid choices. Only if the SAN and SNI match, the TLS connection will work, otherwise an error is logged that can be used to troubleshoot.
- `NTLM`: If your Backend Server needs NTLM authentication, enable this option together with `TLS`. For example, Exchange Server.
**Attention**: The GUI doesn't allow "tls_insecure_skip_verify" due to safety reasons, as the Caddy documentation states not to use it. Use the `TLS Trusted CA Certificates` and `TLS Server Name` options instead to get a **secure TLS connection** to your Backend Server. Otherwise, use HTTP. If you really need to use "tls_insecure_skip_verify" and know the implications, use the import statements of custom configuration files.
## Reverse Proxy - Access - Access Lists
- Press `+` to create a new Access List
- `Access List name`: Choose a name for the Access List, for example `private_ips`.
- `Client IP Addresses`: Enter any number of IPv4 and IPv6 addresses or networks that this access list should contain. For example for matching only internal networks, add `192.168.0.0/16` `172.16.0.0/12` `10.0.0.0/8` `127.0.0.1/8` `fd00::/8` `::1`.
- `Invert List`: Invert the logic of the access list. If unchecked, the Client IP Addresses will be ALLOWED, all other IP addresses will be blocked. When checked, the Client IP Addresses will be BLOCKED, all other IP addresses will be allowed.
- Afterwards, go back to Domains or Subdomains and add the Access List you have created to them (advanced mode). All handlers created under these Domains will get an additional matcher. That means, the requests still reach Caddy, but if the IP Addresses don't match with the Access List logic, the request doesn't match any handler and will be dropped before being reverse proxied to any Backend Server. If you are using a CDN, make sure the Access List in General - Trusted Proxies and on each Domain used for that CDN are the same.
## Reverse Proxy - Access - Basic Auth
- Press `+` to create a new User for Basic Auth
- `User`: Enter a username. Afterwards, you can select it in Reverse Proxy Domains or Subdomains to restrict access with basic auth. Usernames are only allowed to have alphanumeric characters.
- `Password`: Enter a password. Write it down. It will be hashed with bcrypt. It can only be set and changed but won't be visible anymore. The hash can't be turned back into the original password.
- Afterwards, go back to Domains or Subdomains and add the one or multiple basic auth users you have created to them (advanced mode). The basic auth matches after access lists, so you can set both to first restrict access by IP address, and then additionally by username and password. Please note that if you delete a user before deselecting it in a domain, the basic auth will stay with no user. If that happens you have to select the "clear all" in the domain or subdomain and save. Don't set basic auth on top of a wildcard domain directly, always set it on the subdomains instead.
# HOW TO Section:
## HOW TO: Create an easy reverse proxy
**Services - Caddy Web Server - General Settings:**
- `Enable` Caddy and press `Apply`
**Services - Caddy Web Server - Reverse Proxy - Domain:**
- Press `+` to create a new Reverse Proxy Domain
- `Reverse Proxy Domain` - `foo.example.com`
- `Description` - `foo.example.com`
- `Save`
**Services - Caddy Web Server - Reverse Proxy - Handler:**
- Press `+` to create a new Handler
- `Reverse Proxy Domain` - `foo.example.com`
- `Backend Server Domain` - `192.168.10.1`
- `Save`
- `Apply`
Done, leave all other fields to default or empty. You don't need the advanced mode options. After just a few seconds the Let's Encrypt Certificate will be installed and everything just works. Check the Logfile for that.
Now you have a "Internet <-- HTTPS --> OPNsense (Caddy) <-- HTTP --> Backend Server" Reverse Proxy.
## HOW TO: Create a wildcard subdomain reverse proxy
- Do everything the same as above, but create your Reverse Proxy Domain like this `*.example.com` and activate the `DNS-01` challenge checkbox.
- OR - `Custom Certificate` - Use a Certificate you imported or generated in `System - Trust - Certificates`. It has to be a wildcard certificate.
- Go to the `Reverse Proxy Subdomain` Tab and create all subdomains that you need in relation to the `*.example.com` domain. So for example `foo.example.com` and `bar.example.com`.
- Create descriptions for each subdomain. Since there could be multiples of the same subdomain with different ports, do it like this: `foo.example.com` and `foo.example.com.8443`.
- In the `Handler` Tab you can now select your `*.example.com` `Reverse Proxy Domain`, and if `Reverse Proxy Subdomain` is `None`, the Handlers are added to the base `Reverse Proxy Domain`. For example, if you want a catch all Handler for all non referenced subdomains.
- If you create a Handler with `*.example.com` as `Reverse Proxy Domain` and `foo.example.com` as `Reverse Proxy Subdomain`, a nested Handler will be generated. You can do all the same configurations as if the subdomain is a normal domain, with multiple Handlers and Handler paths.
## HOW TO: Create a Handle with TLS and a trusted self-signed Certificate
**Example: Reverse Proxy the OPNsense Configuration GUI Website with Caddy**
- Open your OPNsense GUI in a Browser (e.g. Chrome or Firefox). Inspect the certificate. Copy the SAN for later use, for example `OPNsense.localdomain`.
- Save the certificate in your Browser as PEM file. Open it up with a text editor, and copy the contents into a new entry in `System - Trust - Authorities`. Name the certificate e.g. `opnsense-selfsigned`.
- Add a new Reverse Proxy Domain, for example `opn.example.com`. Make sure the name is externally resolvable to the IP of your OPNsense Firewall with Caddy.
- Add a new Handler with the following options (enable advanced mode):
- `Reverse Proxy Domain`: `opn.example.com`
- `Backend Server Domain`: `127.0.0.1`
- `Backend Server Port`: `8443` (Enter the port of your OPNsense GUI. You have changed it from 443 to a different port, since Caddy needs port 443.)
- `TLS`: `X`
- `TLS Trusted CA Certificates`: `opnsense-selfsigned` (The certificate you have saved in `System - Trust - Authorities`)
- `TLS Server Name`: `OPNsense.localdomain` (The SAN of the certificate)
- Save
- Apply
- Open `https://opn.example.com` and it should serve the reverse proxied OPNsense Configuration GUI Website. Check the log file for errors if it doesn't work, most of the time the `TLS Server Name` doesn't match the SAN of the `TLS Trusted CA Certificates`. Please note that Caddy doesn't support CN (Common Name) in certificate since it's been deprecated since many years.
- Additionally, you can create an access list to limit access to the GUI only from trusted IP addresses (recommended). Add that access list to the domain `opn.example.com` in advanced mode. Also, enable `Abort Connections` in the `General` Settings to abort all connections immediately that don't match the access list or the handler.
# Troubleshooting
- You can always test if your current Caddyfile is valid by invoking `/api/caddy/service/validate` - This is also done automatically each time `Apply` is pressed. If you have an invalid configuration, Caddy will refuse to start and show the exact error message.
- Check `/var/log/caddy/caddy.log` or `@latest.log` to find errors. There is also a Caddy Log File in the GUI.
- A good indicator that Caddy is indeed running is this log entry: `serving initial configuration`
- Check the Service Widget and the "General Settings" Service Control buttons. If everything works they should show a green "Play" sign. If Caddy is stopped there is a red "Stop" sign. If Caddy is disabled, there is no widget and no control buttons.
# Build caddy and os-caddy from source
- As build system use a FreeBSD 13.2 - https://github.com/opnsense/tools
- Use xcaddy to build your own caddy binary. Additonal Caddy plugins can be compiled in, here is an example: [Additional Plugins](https://github.com/opnsense/tools/blob/a555d25b11486835460a136af0b8ad2e517ae96b/config/24.1/make.conf#L94)
- Check the +MANIFEST file and put all dependant files into the right paths on your build system. Make sure to check your own file hashes with ```sha256 /path/to/file```.
- Use ```pkg create -M ./+MANIFEST``` in the folder of the ```+MANIFEST``` file.
- For os-caddy.pkg make sure you have the OPNsense tools build system properly set up.
- Build the os-caddy.pkg by going into /usr/plugins/devel/caddy/ and invoking ```make package```
# Custom configuration files
- The Caddyfile has an additional import from the path ```/usr/local/etc/caddy/caddy.d/```. You can place your own custom configuration files inside that adhere to the Caddyfile syntax.
- ```*.global``` will be imported into the global block of the Caddyfile. Global options can be found here: [Global Options Block](https://caddyserver.com/docs/caddyfile/options)
- ```*.conf``` will be imported at the end of the Caddyfile, you can put your own reverse_proxy or other settings there. Don't forget to test your custom configuration with `caddy run --config /usr/local/etc/caddy/Caddyfile`.
# Using the REST API to control the plugin:
The Rest API is now fully integreated with the OPNsense syntax.
https://docs.opnsense.org/development/api.html
All API Actions can be found in the API Controller files ```/usr/local/opnsense/mvc/app/controllers/Pischem/Caddy/Api```
Examples:
- /api/caddy/ReverseProxy/get
- /api/caddy/General/get
- /api/caddy/service/status
- /api/caddy/service/validate
+40
View File
@@ -0,0 +1,40 @@
Caddy - The Ultimate Server - makes your sites more secure, more reliable, and more scalable than any other solution.
By default, Caddy automatically obtains and renews TLS certificates for all your sites.
It's the most advanced HTTPS server in the world.
Reverse Proxy HTTP, HTTPS, FastCGI, WebSockets, gRPC, FastCGI (usually PHP), and more!
WWW: https://caddyserver.com/
Main features of this plugin:
* Easy to configure and reliable! Reverse Proxy any HTTP/HTTPS or WebSocket application in minutes.
* Hard to break! Extensive validations of the configuration on each save and apply.
* Automatic Let's Encrypt and ZeroSSL Certificates with HTTP-01 and TLS-ALPN-01 challenge
* DNS-01 challenge and Dynamic DNS with supported DNS Providers built right in
* Use custom certificates from OPNsense certificate store
* Wildcard Domain and Subdomain support
* Access Lists to restrict access based on static networks
* Basic Auth to restrict access by username and password
* Syslog-ng integration and HTTP Access Log
* NTLM Transport
Plugin Changelog
================
1.5.1
* More DNS Providers added: netlify, namesilo, njalla, vercel, googleclouddns, alidns, powerdns, tencentcloud, dinahosting, metaname, hexonet, ddnss, linode, mailinabox, ovh, namecheap, azure, openstack-designate.
* More input fields and better documentation added for the DNS Provider API Keys.
* Changed rc.d script to standard freebsd poudriere one packaged with the caddy-custom binary, included setup.sh script to rc.conf.d/caddy.
* Updated dependancy to caddy-custom instead of caddy.
* Removed +POST_DEINSTALL.post and +POST_INSTALL.post.
* Turned syslog-ng configuration from template to static file.
* A few typos in the general.volt and reverse_proxy.volt corrected.
* The RealInterfaceField custom Fieldtype was removed and replaced with an OPNsense integrated template function to read the interface name.
* Enable $internalModelUseSafeDelete in ReverseProxyController.php - Items can only be deleted when they are not referenced by other items, making deleting in the GUI safer since there can't be any orphaned configuration left behind.
* Migration script M1_1_3 from "Description" to "description" added. Lower case description is needed to be in line with some OPNsense integrated functions.
1.5.0
* Initial release
@@ -0,0 +1,64 @@
<?php
/*
* 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.
*/
function caddy_services()
{
global $config;
$services = array();
if (isset($config['Pischem']['caddy']['general']['enabled']) &&
$config['Pischem']['caddy']['general']['enabled'] == 1) {
$services[] = array(
'description' => gettext('Caddy Web Server'),
'configd' => array(
'restart' => array('caddy restart'),
'start' => array('caddy start'),
'stop' => array('caddy stop'),
),
'name' => 'caddy',
'pidfile' => '/var/run/caddy/caddy.pid'
);
}
return $services;
}
function caddy_xmlrpc_sync()
{
$result = array();
$result[] = array(
'description' => gettext('Caddy Web Server'),
'section' => 'Pischem.caddy',
'id' => 'caddy',
'services' => ["caddy"],
);
return $result;
}
@@ -0,0 +1,48 @@
###################################################################
# Local syslog-ng configuration [caddy].
###################################################################
# DO NOT EDIT THIS FILE -- OPNsense auto-generated file
#
# Define Unix socket source for Caddy
source s_caddy {
unix-dgram("/var/caddy/var/run/log");
};
# Parser for Caddy log levels
parser p_caddy_levels {
channel {
filter {
message(".*debug.*") or
message(".*info.*") or
message(".*warn.*") or
message(".*error.*") or
message(".*panic.*") or
message(".*fatal.*");
};
rewrite {
set-severity("7" condition(message(".*debug.*"))); # DEBUG -> Debug
set-severity("6" condition(message(".*info.*"))); # INFO -> Informational
set-severity("4" condition(message(".*warn.*"))); # WARN -> Warning
set-severity("3" condition(message(".*error.*"))); # ERROR -> Error
set-severity("2" condition(message(".*panic.*"))); # PANIC -> Critical
set-severity("1" condition(message(".*fatal.*"))); # FATAL -> Alert
};
};
};
# Destination for Caddy logs
destination d_local_caddy {
file(
"/var/log/caddy/caddy_${YEAR}${MONTH}${DAY}.log"
create-dirs(yes)
flags(syslog-protocol)
);
};
# Log path for processing Caddy logs
log {
source(s_caddy);
parser(p_caddy_levels);
rewrite { set("caddy" value("PROGRAM")); };
destination(d_local_caddy);
};
@@ -0,0 +1,41 @@
<?php
/**
* Copyright (C) 2023-2024 Cedrik Pischem
* Copyright (C) 2015 Deciso B.V.
*
* 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.
*
*/
namespace OPNsense\Caddy\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
use OPNsense\Core\Config;
class GeneralController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'caddy';
protected static $internalModelClass = 'OPNsense\Caddy\Caddy';
}
@@ -0,0 +1,215 @@
<?php
/**
* Copyright (C) 2023-2024 Cedrik Pischem
* Copyright (C) 2015 Deciso B.V.
*
* 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.
*
*/
namespace OPNsense\Caddy\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
class ReverseProxyController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'caddy';
protected static $internalModelClass = 'OPNsense\Caddy\Caddy';
protected static $internalModelUseSafeDelete = true;
/*ReverseProxy Section*/
public function searchReverseProxyAction()
{
return $this->searchBase("reverseproxy.reverse", ['enabled', 'FromDomain', 'FromPort', 'accesslist', 'basicauth', 'DnsChallenge', 'CustomCertificate', 'AccessLog', 'DynDns', 'description']);
}
public function setReverseProxyAction($uuid)
{
return $this->setBase("reverse", "reverseproxy.reverse", $uuid);
}
public function addReverseProxyAction()
{
return $this->addBase("reverse", "reverseproxy.reverse");
}
public function getReverseProxyAction($uuid = null)
{
return $this->getBase("reverse", "reverseproxy.reverse", $uuid);
}
public function delReverseProxyAction($uuid)
{
return $this->delBase("reverseproxy.reverse", $uuid);
}
public function toggleReverseProxyAction($uuid, $enabled = null)
{
return $this->toggleBase("reverseproxy.reverse", $uuid, $enabled);
}
/*Subdomain Section*/
public function searchSubdomainAction()
{
return $this->searchBase("reverseproxy.subdomain", ['enabled', 'reverse', 'FromDomain', 'FromPort', 'accesslist', 'basicauth', 'DynDns', 'description']);
}
public function setSubdomainAction($uuid)
{
return $this->setBase("subdomain", "reverseproxy.subdomain", $uuid);
}
public function addSubdomainAction()
{
return $this->addBase("subdomain", "reverseproxy.subdomain");
}
public function getSubdomainAction($uuid = null)
{
return $this->getBase("subdomain", "reverseproxy.subdomain", $uuid);
}
public function delSubdomainAction($uuid)
{
return $this->delBase("reverseproxy.subdomain", $uuid);
}
public function toggleSubdomainAction($uuid, $enabled = null)
{
return $this->toggleBase("reverseproxy.subdomain", $uuid, $enabled);
}
/*Handler Section*/
public function searchHandleAction()
{
return $this->searchBase("reverseproxy.handle", ['enabled', 'reverse', 'subdomain', 'HandleType', 'HandlePath', 'ToDomain', 'ToPort', 'ToPath', 'HttpTls', 'HttpTlsTrustedCaCerts', 'HttpTlsServerName', 'HttpNtlm', 'description']);
}
public function setHandleAction($uuid)
{
return $this->setBase("handle", "reverseproxy.handle", $uuid);
}
public function addHandleAction()
{
return $this->addBase("handle", "reverseproxy.handle");
}
public function getHandleAction($uuid = null)
{
return $this->getBase("handle", "reverseproxy.handle", $uuid);
}
public function delHandleAction($uuid)
{
return $this->delBase("reverseproxy.handle", $uuid);
}
public function toggleHandleAction($uuid, $enabled = null)
{
return $this->toggleBase("reverseproxy.handle", $uuid, $enabled);
}
/* AccessList Section */
public function searchAccessListAction()
{
return $this->searchBase("reverseproxy.accesslist", ['accesslistName', 'clientIps', 'accesslistInvert', 'description']);
}
public function setAccessListAction($uuid)
{
return $this->setBase("accesslist", "reverseproxy.accesslist", $uuid);
}
public function addAccessListAction()
{
return $this->addBase("accesslist", "reverseproxy.accesslist");
}
public function getAccessListAction($uuid = null)
{
return $this->getBase("accesslist", "reverseproxy.accesslist", $uuid);
}
public function delAccessListAction($uuid)
{
return $this->delBase("reverseproxy.accesslist", $uuid);
}
/* BasicAuth Section */
public function searchBasicAuthAction()
{
return $this->searchBase("reverseproxy.basicauth", ['basicauthuser', 'basicauthpass', 'description']);
}
public function setBasicAuthAction($uuid)
{
if ($this->request->isPost()) {
$postData = $this->request->getPost();
if (isset($postData['basicauth']['basicauthpass']) && !empty(trim($postData['basicauth']['basicauthpass']))) {
$plainPassword = $postData['basicauth']['basicauthpass'];
$hashedPassword = password_hash($plainPassword, PASSWORD_BCRYPT);
$_POST['basicauth']['basicauthpass'] = $hashedPassword;
}
}
return $this->setBase("basicauth", "reverseproxy.basicauth", $uuid);
}
public function addBasicAuthAction()
{
if ($this->request->isPost()) {
$postData = $this->request->getPost();
if (isset($postData['basicauth']['basicauthpass']) && !empty(trim($postData['basicauth']['basicauthpass']))) {
$plainPassword = $postData['basicauth']['basicauthpass'];
$hashedPassword = password_hash($plainPassword, PASSWORD_BCRYPT);
$_POST['basicauth']['basicauthpass'] = $hashedPassword;
}
}
return $this->addBase("basicauth", "reverseproxy.basicauth");
}
public function getBasicAuthAction($uuid = null)
{
return $this->getBase("basicauth", "reverseproxy.basicauth", $uuid);
}
public function delBasicAuthAction($uuid)
{
return $this->delBase("reverseproxy.basicauth", $uuid);
}
}
@@ -0,0 +1,67 @@
<?php
/**
* Copyright (C) 2023-2024 Cedrik Pischem
* Copyright (C) 2015 Deciso B.V.
*
* 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.
*
*/
namespace OPNsense\Caddy\Api;
use OPNsense\Base\ApiMutableServiceControllerBase;
use OPNsense\Core\Backend;
class ServiceController extends ApiMutableServiceControllerBase
{
protected static $internalServiceClass = '\OPNsense\Caddy\Caddy';
protected static $internalServiceTemplate = 'OPNsense/Caddy';
protected static $internalServiceEnabled = 'general.enabled';
protected static $internalServiceName = 'caddy';
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" => "Unable to parse the validation result."];
}
}
@@ -0,0 +1,47 @@
<?php
/**
* Copyright (C) 2023-2024 Cedrik Pischem
* Copyright (C) 2015 Deciso B.V.
*
* 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.
*
*/
namespace OPNsense\Caddy;
use OPNsense\Base\IndexController;
class GeneralController extends IndexController
{
public function indexAction()
{
// Assign the general settings form to the view
$this->view->pick('OPNsense/Caddy/general');
$this->view->generalForm = $this->getForm("general");
$this->view->dnsproviderForm = $this->getForm("dnsprovider");
$this->view->dynamicdnsForm = $this->getForm("dynamicdns");
$this->view->logsettingsForm = $this->getForm("logsettings");
}
}
@@ -0,0 +1,45 @@
<?php
/**
* Copyright (C) 2023-2024 Cedrik Pischem
* Copyright (C) 2015 Deciso B.V.
*
* 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.
*
*/
namespace OPNsense\Caddy;
use OPNsense\Base\IndexController;
class ReverseProxyController extends IndexController {
public function indexAction() {
$this->view->pick('OPNsense/Caddy/reverse_proxy');
$this->view->formDialogReverseProxy = $this->getForm("dialogReverseProxy");
$this->view->formDialogSubdomain = $this->getForm("dialogSubdomain");
$this->view->formDialogHandle = $this->getForm("dialogHandle");
$this->view->formDialogAccessList = $this->getForm("dialogAccessList");
$this->view->formDialogBasicAuth = $this->getForm("dialogBasicAuth");
}
}
@@ -0,0 +1,28 @@
<form>
<field>
<id>accesslist.accesslistName</id>
<label>Access List Name</label>
<type>text</type>
<help><![CDATA[Enter a name for this access list.]]></help>
</field>
<field>
<id>accesslist.clientIps</id>
<label>Client IP Addresses</label>
<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>
</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>
</field>
<field>
<id>accesslist.description</id>
<label>Description</label>
<type>text</type>
<help><![CDATA[Enter a description for this access list.]]></help>
</field>
</form>
@@ -0,0 +1,20 @@
<form>
<field>
<id>basicauth.basicauthuser</id>
<label>User</label>
<type>text</type>
<help><![CDATA[Enter a username. Afterwards, you can select it in Reverse Proxy Domains or Subdomains 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 won't be visible anymore.]]></help>
</field>
<field>
<id>basicauth.description</id>
<label>Description</label>
<type>text</type>
<help><![CDATA[Enter a description for this user.]]></help>
</field>
</form>
@@ -0,0 +1,91 @@
<form>
<field>
<id>handle.enabled</id>
<label>enabled</label>
<type>checkbox</type>
<help><![CDATA[Enable this handler.]]></help>
</field>
<field>
<id>handle.reverse</id>
<label>Reverse Proxy Domain</label>
<type>dropdown</type>
<help><![CDATA[Select a reverse proxy domain to which this handler should be added.]]></help>
</field>
<field>
<id>handle.subdomain</id>
<label>Reverse Proxy Subdomain</label>
<type>dropdown</type>
<help><![CDATA[Optionally, select a reverse proxy subdomain to which this handler should be added. In most cases, leaving this as "None" will be the best choice.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>handle.HandleType</id>
<label>Handle Type</label>
<type>dropdown</type>
<help><![CDATA[Select the handler type. In most cases, leaving this as "handle" will be the best choice.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>handle.HandlePath</id>
<label>Handle Path</label>
<type>text</type>
<help><![CDATA[Enter a handler like '/*' or '/example/*', or leave blank for a catch-all handler (recommended). You can define multiple handlers per domain/subdomain by creating additional entries. Save more specific handlers first, as the first matching handler is prioritized. Blank handlers are processed last automatically. To reorder, clone handlers in the desired sequence and delete old ones.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>handle.ToDomain</id>
<label>Backend Server Domain</label>
<type>text</type>
<hint>192.168.1.1</hint>
<help><![CDATA[Enter the internal domain name or IP address of the backend server destination for this handler.]]></help>
</field>
<field>
<id>handle.ToPort</id>
<label>Backend Server Port</label>
<type>text</type>
<hint>443</hint>
<help><![CDATA[Enter the port number of the backend server. Leave this empty for bind to port 80. For HTTPS, use 443.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>handle.ToPath</id>
<label>Backend Path</label>
<type>text</type>
<help><![CDATA[Enter a path prefix like '/guacamole' that should be prepended to the backend request because the application demands it.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>handle.HttpTls</id>
<label>TLS</label>
<type>checkbox</type>
<help><![CDATA[Use HTTP over TLS (HTTPS) to communicate with the Backend Server. In most cases, leaving this unchecked will be the best choice. Caddy uses HTTP for communication with the Backend Server by default.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>handle.HttpTlsTrustedCaCerts</id>
<label>TLS Trusted CA Certificate</label>
<type>dropdown</type>
<help><![CDATA[If TLS is enabled, and you are not using a globally trusted server certificate on your Backend Server, you can choose a CA certificate or self-signed certificate to trust from "System - Trust - Authorities".]]></help>
<advanced>true</advanced>
</field>
<field>
<id>handle.HttpTlsServerName</id>
<label>TLS Server Name</label>
<type>text</type>
<help><![CDATA[Optionally, specify a hostname or IP address that matches the SAN of the "TLS Trusted CA Certificate". Please note that only SAN certificates are supported; CN will not work.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>handle.HttpNtlm</id>
<label>NTLM</label>
<type>checkbox</type>
<help><![CDATA[If "TLS" has been checked, check "NTLM" in addition for reverse proxying an Exchange Server. In most other cases, leaving this unchecked will be the best choice.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>handle.description</id>
<label>Description</label>
<type>text</type>
<help><![CDATA[Enter a description for this handler.]]></help>
</field>
</form>
@@ -0,0 +1,71 @@
<form>
<field>
<id>reverse.enabled</id>
<label>enabled</label>
<type>checkbox</type>
<help><![CDATA[Enable this reverse proxy domain.]]></help>
</field>
<field>
<id>reverse.FromDomain</id>
<label>Reverse Proxy Domain</label>
<type>text</type>
<hint>example.com</hint>
<help><![CDATA[Enter a domain name or IP address. For a wildcard domain, use *.example.com. Only use wildcard domains with a wildcard certificate. Don't forget to create a firewall rule that allows port 80 and 443 to "This Firewall".]]></help>
</field>
<field>
<id>reverse.FromPort</id>
<label>Reverse Proxy Port</label>
<type>text</type>
<hint>443</hint>
<help><![CDATA[Enter the port number. Leave this empty to bind to port 80 and 443 with automatic redirection. Don't forget to create a firewall rule that allows this port to "This Firewall".]]></help>
<advanced>true</advanced>
</field>
<field>
<id>reverse.accesslist</id>
<label>Access List</label>
<type>dropdown</type>
<help><![CDATA[Optionally, select an Access List to restrict access to this domain. If left as "None", any local or remote client is allowed access. In most cases, leaving this as "None" will be the best choice.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>reverse.basicauth</id>
<label>Basic Auth</label>
<type>select_multiple</type>
<size>5</size>
<help><![CDATA[Optionally, select Users to restrict access to this domain. Basic Auth matches after Access Lists. If left as "None", any client is allowed access. In most cases, leaving this as "None" will be the best choice.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>reverse.DnsChallenge</id>
<label>DNS-01 challenge</label>
<type>checkbox</type>
<help><![CDATA[Enable DNS-01 challenge for ACME, please configure DNS Provider and API Key in General Settings. In most cases, leaving this option unchecked will be the best choice. The automatic Let's Encrypt HTTP challenge will be used if this option is unchecked, which needs no further configuration.]]></help>
</field>
<field>
<id>reverse.DynDns</id>
<label>Dynamic DNS</label>
<type>checkbox</type>
<help><![CDATA[Enable Dynamic DNS, please configure DNS Provider and API Key in General Settings. The DNS Records of this domain will be automatically updated with your DNS Provider.]]></help>
</field>
<field>
<id>reverse.CustomCertificate</id>
<label>Custom Certificate</label>
<type>dropdown</type>
<help><![CDATA[Choose your own certificate from System Trust Certificates. Make sure you have imported the full chain. In most cases, leaving this as "None" will be the best choice.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>reverse.AccessLog</id>
<label>HTTP Access Log</label>
<type>checkbox</type>
<help><![CDATA[Enable the HTTP request logging for this domain and its subdomains. This option is mostly for troubleshooting since it will log every single request.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>reverse.description</id>
<label>Description</label>
<type>text</type>
<hint>example.com.443</hint>
<help><![CDATA[Enter a description for this reverse proxy domain.]]></help>
</field>
</form>
@@ -0,0 +1,57 @@
<form>
<field>
<id>subdomain.enabled</id>
<label>enabled</label>
<type>checkbox</type>
<help><![CDATA[Enable this reverse proxy subdomain.]]></help>
</field>
<field>
<id>subdomain.reverse</id>
<label>Reverse Proxy Domain</label>
<type>dropdown</type>
<help><![CDATA[Select a domain, to which this subdomain should be added.]]></help>
</field>
<field>
<id>subdomain.FromDomain</id>
<label>Reverse Proxy Subdomain</label>
<type>text</type>
<hint>opn.example.com</hint>
<help><![CDATA[Enter the subdomain name (e.g., 'opn.example.com' if your wildcard domain is '*.example.com').]]></help>
</field>
<field>
<id>subdomain.FromPort</id>
<label>Reverse Proxy Port</label>
<type>text</type>
<hint>443</hint>
<help><![CDATA[Enter the port number. Leave this empty to bind to port 80 and 443 with automatic redirection. Don't forget to create a firewall rule that allows this destination port to "This Firewall".]]></help>
<advanced>true</advanced>
</field>
<field>
<id>subdomain.accesslist</id>
<label>Access List</label>
<type>dropdown</type>
<help><![CDATA[Optionally, select an Access List to restrict access to this subdomain. If left as "None", any local or remote client is allowed access. In most cases, leaving this as "None" will be the best choice.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>subdomain.basicauth</id>
<label>Basic Auth</label>
<type>select_multiple</type>
<size>5</size>
<help><![CDATA[Optionally, select Users to restrict access to this subdomain. Basic Auth matches after Access Lists. If left as "None", any client is allowed access. In most cases, leaving this as "None" will be the best choice.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>subdomain.DynDns</id>
<label>Dynamic DNS</label>
<type>checkbox</type>
<help><![CDATA[Enable Dynamic DNS, please configure DNS Provider and API Key in General Settings. The DNS Records of this subdomain will be automatically updated with your DNS Provider.]]></help>
</field>
<field>
<id>subdomain.description</id>
<label>Description</label>
<type>text</type>
<hint>opn.example.com.443</hint>
<help><![CDATA[Enter a description for this reverse proxy subdomain.]]></help>
</field>
</form>
@@ -0,0 +1,63 @@
<form>
<field>
<id>caddy.general.TlsDnsProvider</id>
<label>DNS Provider</label>
<type>dropdown</type>
<help><![CDATA[Select the DNS provider for the DNS-01 Challenge and Dynamic DNS. This is optional, since certificates will be requested from Let's Encrypt via HTTP Challenge when this option is unset. You mostly need this for Wildcard Certificates, and for Dynamic DNS. To use the DNS-01 Challenge and Dynamic DNS, enable the checkbox in a Reverse Proxy Domain or Subdomain. For more information: https://github.com/caddy-dns]]></help>
</field>
<field>
<id>caddy.general.TlsDnsApiKey</id>
<label>DNS API Standard Field</label>
<type>text</type>
<help><![CDATA[This is the standard field for the API Key. Field can be left empty if optional: Cloudflare "api_token", Duckdns "api_token", DigitalOcean "auth_token", DNSPod "auth_token", Hetzner "api_token", Godaddy "api_token", Gandi "bearer_token", IONOS "api_token", deSEC "token", Route53 "access_key_id", Porkbun "api_key", ACME-DNS "username", Netlify "personal_access_token", Namesilo "api_token", Njalla "api_token", Vercel "api_token", Google Cloud DNS "gcp_project", Alidns "access_key_id", Azure "tenant_id", OpenStack Designate "region_name", OVH "endpoint", Namecheap "api_key", PowerDNS "server_url", DDNSS "api_token", Metaname "api_key", Linode "api_token", Tencent Cloud "secret_id", Dinahosting "username", Hexonet "username", Mail-in-a-Box "api_url".]]></help>
</field>
<field>
<id>caddy.general.TlsDnsSecretApiKey</id>
<label>DNS API Additional Field 1</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Duckdns "override_domain", Route53 "secret_access_key", Porkbun "api_secret_key", ACME-DNS "password", Alidns "access_key_secret", Azure "client_id", OpenStack Designate "tenant_id", OVH "application_key", Namecheap "user", PowerDNS "api_token", DDNSS "username", Metaname "account_reference", Linode "api_url", Tencent Cloud "secret_key", Dinahosting "password", Hexonet "password", Mail-in-a-Box "email_address".]]></help>
<advanced>true</advanced>
</field>
<field>
<id>caddy.general.TlsDnsOptionalField1</id>
<label>DNS API Additional Field 2</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "max_retries", ACME-DNS "subdomain", Azure "client_secret", OpenStack Designate "identity_api_version", OVH "application_secret", Namecheap "api_endpoint", DDNSS "password", Linode "api_version", Mail-in-a-Box "password".]]></help>
<advanced>true</advanced>
</field>
<field>
<id>caddy.general.TlsDnsOptionalField2</id>
<label>DNS API Additional Field 3</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "aws_profile", ACME-DNS "server_url", Azure "subscription_id", OpenStack Designate "password", OVH "consumer_key", Namecheap "client_ip", DDNS "password".]]></help>
<advanced>true</advanced>
</field>
<field>
<id>caddy.general.TlsDnsOptionalField3</id>
<label>DNS API Additional Field 4</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "region", Azure "resource_group_name", OpenStack Designate "username".]]></help>
<advanced>true</advanced>
</field>
<field>
<id>caddy.general.TlsDnsOptionalField4</id>
<label>DNS API Additional Field 5</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "token", OpenStack Designate "tenant_name".]]></help>
<advanced>true</advanced>
</field>
<field>
<id>caddy.general.TlsDnsOptionalField5</id>
<label>DNS API Additional Field 6</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: OpenStack Designate "auth_url".]]></help>
<advanced>true</advanced>
</field>
<field>
<id>caddy.general.TlsDnsOptionalField6</id>
<label>DNS API Additional Field 7</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: OpenStack Designate "endpoint_type".]]></help>
<advanced>true</advanced>
</field>
</form>
@@ -0,0 +1,34 @@
<form>
<field>
<id>caddy.general.DynDnsSimpleHttp</id>
<label>DynDns Check Http</label>
<type>text</type>
<help><![CDATA[Optionally, enter a URL to test the current IP address of the firewall via HTTP protocol. Generally, this is not needed. Caddy uses default providers to test the current IP addresses. If you'd rather use your own, enter the https:// link to an IP address testing website.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>caddy.general.DynDnsInterface</id>
<label>DynDns Check Interface</label>
<type>dropdown</type>
<help><![CDATA[Optionally, select an interface to extract the current IP address of the firewall. Attention, all IP addresses will be read from this interface. Only choose this option if you know the implications.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>caddy.general.DynDnsCheckInterval</id>
<label>DynDns Check Interval</label>
<type>text</type>
<help><![CDATA[Interval to poll for changes of the IP address. The default is 5 minutes. Can be a number between 1 to 1440 minutes.]]></help>
</field>
<field>
<id>caddy.general.DynDnsIpVersions</id>
<label>DynDns IP Version</label>
<type>dropdown</type>
<help><![CDATA[Leave on None to set IPv4 A-Records and IPv6 AAAA-Records. Select "IPv4 only" for setting A-Records. Select "IPv6 only" for setting AAAA-Records.]]></help>
</field>
<field>
<id>caddy.general.DynDnsTTL</id>
<label>DynDns TTL</label>
<type>text</type>
<help><![CDATA[Set the TTL (time to live) for DNS Records. The default is 1 hour. Can be a number between 1 to 24 hours.]]></help>
</field>
</form>
@@ -0,0 +1,33 @@
<form>
<field>
<id>caddy.general.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help><![CDATA[Enable or disable the Caddy web server.]]></help>
</field>
<field>
<id>caddy.general.TlsEmail</id>
<label>ACME Email</label>
<type>text</type>
<hint>info@example.com</hint>
<help><![CDATA[Enter the email address for certificate notifications.]]></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 without needing any configuration.]]></help>
</field>
<field>
<id>caddy.general.abort</id>
<label>Abort Connections</label>
<type>checkbox</type>
<help><![CDATA[Abort all connections that don't have a matching handle or access list. This option doesn't conflict with Let's Encrypt. Disable it for troubleshooting purposes, e.g., testing if the Reverse Proxy Domain works and the Certificate has been installed. For production use, enabling this option is recommended.]]></help>
</field>
<field>
<id>caddy.general.accesslist</id>
<label>Trusted Proxies</label>
<type>dropdown</type>
<help><![CDATA[Select an Access List of Trusted Proxies. If Caddy is not the first server being connected to by your clients (for example when a CDN is in front of Caddy), you may 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 your Trusted Proxy connects to.]]></help>
</field>
</form>
@@ -0,0 +1,23 @@
<form>
<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 combined with HTTP Access Log in the Reverse Proxy 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 combined with HTTP Access Log in the Reverse Proxy Domain. Enabling this will make the HTTP Access Log dissappear from the standard "Log File" in the GUI. They can be found in the filesystem "/var/log/caddy/access/"]]></help>
<advanced>true</advanced>
</field>
<field>
<id>caddy.general.LogAccessPlainKeep</id>
<label>Keep HTTP Access JSON Logs for (days)</label>
<hint>10</hint>
<type>text</type>
<help><![CDATA[How many days to keep the JSON access logs.]]></help>
<advanced>true</advanced>
</field>
</form>
@@ -0,0 +1,18 @@
<acl>
<page-caddy-general>
<name>Services: Caddy Web Server: General Settings</name>
<description>Allow access to Caddy General Settings</description>
<patterns>
<pattern>ui/caddy/general/*</pattern>
<pattern>api/caddy/general/*</pattern>
</patterns>
</page-caddy-general>
<page-caddy-reverse-proxy>
<name>Services: Caddy Web Server: Reverse Proxy</name>
<description>Allow access to Caddy Reverse Proxy</description>
<patterns>
<pattern>ui/caddy/reverse_proxy/*</pattern>
<pattern>api/caddy/reverse_proxy/*</pattern>
</patterns>
</page-caddy-reverse-proxy>
</acl>

Some files were not shown because too many files have changed in this diff Show More