mirror of
https://github.com/opnsense/plugins.git
synced 2026-06-09 00:42:34 -04:00
www/nginx: merge version 0.2 from master
This commit is contained in:
parent
684a9a44ac
commit
0ad85a75ba
40 changed files with 2853 additions and 0 deletions
|
|
@ -81,6 +81,7 @@ sysutils/vmware -- VMware tools
|
|||
sysutils/xen -- Xen guest utilities
|
||||
www/c-icap -- c-icap connects the web proxy with a virus scanner
|
||||
www/cache -- Webserver cache
|
||||
www/nginx -- Nginx HTTP server and reverse proxy
|
||||
www/web-proxy-sso -- Kerberos authentication module
|
||||
www/web-proxy-useracl -- Group and user ACL for the web proxy
|
||||
```
|
||||
|
|
|
|||
8
www/nginx/Makefile
Normal file
8
www/nginx/Makefile
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
PLUGIN_NAME= nginx
|
||||
PLUGIN_VERSION= 0.2
|
||||
PLUGIN_COMMENT= Nginx HTTP server and reverse proxy
|
||||
PLUGIN_DEPENDS= nginx
|
||||
PLUGIN_MAINTAINER= franz.fabian.94@gmail.com
|
||||
PLUGIN_DEVEL= yes
|
||||
|
||||
.include "../../Mk/plugins.mk"
|
||||
8
www/nginx/pkg-descr
Normal file
8
www/nginx/pkg-descr
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
NGINX is a high performance edge web server with the lowest memory footprint
|
||||
and the key features to build modern and efficient web infrastructure.
|
||||
|
||||
NGINX functionality includes HTTP server, HTTP and mail reverse proxy, caching,
|
||||
load balancing, compression, request throttling, connection multiplexing and
|
||||
reuse, SSL offload and HTTP media streaming.
|
||||
|
||||
WWW: https://nginx.org/
|
||||
23
www/nginx/src/etc/nginx/views/opnsense_error_404.html
Normal file
23
www/nginx/src/etc/nginx/views/opnsense_error_404.html
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Request Denied</title>
|
||||
<meta name="generator" content="OPNsense" />
|
||||
<meta name="language" content="en-US" />
|
||||
<style>
|
||||
body {
|
||||
background-color: black;
|
||||
}
|
||||
h1, p {
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Not Found</h1>
|
||||
<p>The resource you want to access is not available.</p>
|
||||
<p>Please contact the webmaster if you think this is an error.</p>
|
||||
</body>
|
||||
</html>
|
||||
23
www/nginx/src/etc/nginx/views/opnsense_server_error.html
Normal file
23
www/nginx/src/etc/nginx/views/opnsense_server_error.html
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Request Denied</title>
|
||||
<meta name="generator" content="OPNsense" />
|
||||
<meta name="language" content="en-US" />
|
||||
<style>
|
||||
body {
|
||||
background-color: black;
|
||||
}
|
||||
h1, p {
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Server Error</h1>
|
||||
<p>Sorry, but something went wrong on our side.</p>
|
||||
<p>There is nothing you can do except waiting until we fix the issue.</p>
|
||||
</body>
|
||||
</html>
|
||||
60
www/nginx/src/etc/nginx/views/waf_denied.html
Normal file
60
www/nginx/src/etc/nginx/views/waf_denied.html
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017-2018 Franco Fichtner <franco@opnsense.org>
|
||||
* Copyright (C) 2016 IT-assistans Sverige AB
|
||||
* Copyright (C) 2015-2016 Deciso B.V.
|
||||
* Copyright (C) 2018 Fabian Franz
|
||||
* 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\Nginx\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableServiceControllerBase;
|
||||
use OPNsense\Core\Backend;
|
||||
|
||||
class ServiceController extends ApiMutableServiceControllerBase
|
||||
{
|
||||
static protected $internalServiceClass = '\OPNsense\Nginx\Nginx';
|
||||
static protected $internalServiceTemplate = 'OPNsense/Nginx';
|
||||
static protected $internalServiceEnabled = 'general.enabled';
|
||||
static protected $internalServiceName = 'nginx';
|
||||
|
||||
/**
|
||||
* override parent method - stopping nginx is not allowed because otherwise you would loose
|
||||
* access to the web interface
|
||||
*/
|
||||
public function stopAction()
|
||||
{
|
||||
return array('status' => 'failed');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* reconfigure with optional stop, generate config and start / reload
|
||||
* @return array response message
|
||||
* @throws \Exception when configd action fails
|
||||
* @throws \ReflectionException when model can't be instantiated
|
||||
*/
|
||||
public function reconfigureAction()
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
$this->sessionClose();
|
||||
$model = $this->getModel();
|
||||
$backend = new Backend();
|
||||
if ($this->reconfigureForceRestart()) {
|
||||
$backend->configdRun('nginx stop');
|
||||
}
|
||||
$backend->configdRun('template reload OPNsense/Nginx');
|
||||
$runStatus = $this->statusAction();
|
||||
if ($runStatus['status'] != 'running') {
|
||||
$backend->configdRun('nginx start');
|
||||
} else {
|
||||
$backend->configdRun('nginx reload');
|
||||
}
|
||||
return array('status' => 'ok');
|
||||
} else {
|
||||
return array('status' => 'failed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve status of service
|
||||
* @return array response message
|
||||
* @throws \Exception when configd action fails
|
||||
*/
|
||||
public function statusAction()
|
||||
{
|
||||
$backend = new Backend();
|
||||
$model = $this->getModel();
|
||||
$response = $backend->configdRun('nginx status');
|
||||
|
||||
if (strpos($response, 'not running') > 0) {
|
||||
$status = 'stopped';
|
||||
} elseif (strpos($response, 'is running') > 0) {
|
||||
$status = 'running';
|
||||
} else {
|
||||
$status = 'unknown';
|
||||
}
|
||||
|
||||
return array('status' => $status);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Fabian Franz
|
||||
* 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\Nginx\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableModelControllerBase;
|
||||
|
||||
class SettingsController extends ApiMutableModelControllerBase
|
||||
{
|
||||
static protected $internalModelClass = '\OPNsense\Nginx\Nginx';
|
||||
static protected $internalModelName = 'nginx';
|
||||
|
||||
// User List
|
||||
|
||||
public function searchuserlistAction()
|
||||
{
|
||||
return $this->searchBase('userlist', array('name', 'users'));
|
||||
}
|
||||
|
||||
public function getuserlistAction($uuid = null)
|
||||
{
|
||||
$this->sessionClose();
|
||||
return $this->getBase('userlist', 'userlist', $uuid);
|
||||
}
|
||||
|
||||
public function adduserlistAction()
|
||||
{
|
||||
return $this->addBase('userlist', 'userlist');
|
||||
}
|
||||
|
||||
public function deluserlistAction($uuid)
|
||||
{
|
||||
return $this->delBase('userlist', $uuid);
|
||||
}
|
||||
|
||||
public function setuserlistAction($uuid)
|
||||
{
|
||||
return $this->setBase('userlist', 'userlist', $uuid);
|
||||
}
|
||||
|
||||
// Credential
|
||||
public function searchcredentialAction()
|
||||
{
|
||||
return $this->searchBase('credential', array('username'));
|
||||
}
|
||||
|
||||
public function getcredentialAction($uuid = null)
|
||||
{
|
||||
$this->sessionClose();
|
||||
return $this->getBase('credential', 'credential', $uuid);
|
||||
}
|
||||
|
||||
public function addcredentialAction()
|
||||
{
|
||||
return $this->addBase('credential', 'credential');
|
||||
}
|
||||
|
||||
public function delcredentialAction($uuid)
|
||||
{
|
||||
return $this->delBase('credential', $uuid);
|
||||
}
|
||||
|
||||
public function setcredentialAction($uuid)
|
||||
{
|
||||
return $this->setBase('credential', 'credential', $uuid);
|
||||
}
|
||||
|
||||
// Upstream
|
||||
public function searchupstreamAction()
|
||||
{
|
||||
return $this->searchBase('upstream', array('description', 'serverentries'));
|
||||
}
|
||||
|
||||
public function getupstreamAction($uuid = null)
|
||||
{
|
||||
$this->sessionClose();
|
||||
return $this->getBase('upstream', 'upstream', $uuid);
|
||||
}
|
||||
|
||||
public function addupstreamAction()
|
||||
{
|
||||
return $this->addBase('upstream', 'upstream');
|
||||
}
|
||||
|
||||
public function delupstreamAction($uuid)
|
||||
{
|
||||
return $this->delBase('upstream', $uuid);
|
||||
}
|
||||
|
||||
public function setupstreamAction($uuid)
|
||||
{
|
||||
return $this->setBase('upstream', 'upstream', $uuid);
|
||||
}
|
||||
|
||||
// Upstream Server
|
||||
public function searchupstreamserverAction()
|
||||
{
|
||||
return $this->searchBase('upstream_server', array('description', 'server', 'priority'));
|
||||
}
|
||||
|
||||
public function getupstreamserverAction($uuid = null)
|
||||
{
|
||||
$this->sessionClose();
|
||||
return $this->getBase('upstream_server', 'upstream_server', $uuid);
|
||||
}
|
||||
|
||||
public function addupstreamserverAction()
|
||||
{
|
||||
return $this->addBase('upstream_server', 'upstream_server');
|
||||
}
|
||||
|
||||
public function delupstreamserverAction($uuid)
|
||||
{
|
||||
return $this->delBase('upstream_server', $uuid);
|
||||
}
|
||||
|
||||
public function setupstreamserverAction($uuid)
|
||||
{
|
||||
return $this->setBase('upstream_server', 'upstream_server', $uuid);
|
||||
}
|
||||
|
||||
// Location
|
||||
public function searchlocationAction()
|
||||
{
|
||||
return $this->searchBase('location', array('description','urlpattern', 'matchtype', 'enable_secrules', 'force_https'));
|
||||
}
|
||||
|
||||
public function getlocationAction($uuid = null)
|
||||
{
|
||||
$this->sessionClose();
|
||||
return $this->getBase('location', 'location', $uuid);
|
||||
}
|
||||
|
||||
public function addlocationAction()
|
||||
{
|
||||
return $this->addBase('location', 'location');
|
||||
}
|
||||
|
||||
public function dellocationAction($uuid)
|
||||
{
|
||||
return $this->delBase('location', $uuid);
|
||||
}
|
||||
|
||||
public function setlocationAction($uuid)
|
||||
{
|
||||
return $this->setBase('location', 'location', $uuid);
|
||||
}
|
||||
|
||||
// Custom Policy
|
||||
public function searchcustompolicyAction()
|
||||
{
|
||||
return $this->searchBase('custom_policy', array('name', 'operator', 'value', 'action'));
|
||||
}
|
||||
|
||||
public function getcustompolicyAction($uuid = null)
|
||||
{
|
||||
$this->sessionClose();
|
||||
return $this->getBase('custompolicy', 'custom_policy', $uuid);
|
||||
}
|
||||
|
||||
public function addcustompolicyAction()
|
||||
{
|
||||
return $this->addBase('custompolicy', 'custom_policy');
|
||||
}
|
||||
|
||||
public function delcustompolicyAction($uuid)
|
||||
{
|
||||
return $this->delBase('custom_policy', $uuid);
|
||||
}
|
||||
|
||||
public function setcustompolicyAction($uuid)
|
||||
{
|
||||
return $this->setBase('custompolicy', 'custom_policy', $uuid);
|
||||
}
|
||||
|
||||
// http server
|
||||
public function searchhttpserverAction()
|
||||
{
|
||||
return $this->searchBase('http_server', array('servername', 'https_only', 'certificate', 'listen_http_port', 'listen_https_port'));
|
||||
}
|
||||
|
||||
public function gethttpserverAction($uuid = null)
|
||||
{
|
||||
$this->sessionClose();
|
||||
return $this->getBase('httpserver', 'http_server', $uuid);
|
||||
}
|
||||
|
||||
public function addhttpserverAction()
|
||||
{
|
||||
return $this->addBase('httpserver', 'http_server');
|
||||
}
|
||||
|
||||
public function delhttpserverAction($uuid)
|
||||
{
|
||||
return $this->delBase('http_server', $uuid);
|
||||
}
|
||||
|
||||
public function sethttpserverAction($uuid)
|
||||
{
|
||||
return $this->setBase('httpserver', 'http_server', $uuid);
|
||||
}
|
||||
|
||||
// naxsi rules
|
||||
public function searchnaxsiruleAction()
|
||||
{
|
||||
return $this->searchBase('naxsi_rule', array('description', 'ruletype', 'message'));
|
||||
}
|
||||
|
||||
public function getnaxsiruleAction($uuid = null)
|
||||
{
|
||||
$this->sessionClose();
|
||||
return $this->getBase('naxsi_rule', 'naxsi_rule', $uuid);
|
||||
}
|
||||
|
||||
public function addnaxsiruleAction()
|
||||
{
|
||||
return $this->addBase('naxsi_rule', 'naxsi_rule');
|
||||
}
|
||||
|
||||
public function delnaxsiruleAction($uuid)
|
||||
{
|
||||
return $this->delBase('naxsi_rule', $uuid);
|
||||
}
|
||||
|
||||
public function setnaxsiruleAction($uuid)
|
||||
{
|
||||
return $this->setBase('naxsi_rule', 'naxsi_rule', $uuid);
|
||||
}
|
||||
|
||||
// http url rewriting
|
||||
public function searchhttprewriteAction()
|
||||
{
|
||||
return $this->searchBase('http_rewrite', array('description', 'source', 'destination', 'flag'));
|
||||
}
|
||||
|
||||
public function gethttprewriteAction($uuid = null)
|
||||
{
|
||||
$this->sessionClose();
|
||||
return $this->getBase('httprewrite', 'http_rewrite', $uuid);
|
||||
}
|
||||
|
||||
public function addhttprewriteAction()
|
||||
{
|
||||
return $this->addBase('httprewrite', 'http_rewrite');
|
||||
}
|
||||
|
||||
public function delhttprewriteAction($uuid)
|
||||
{
|
||||
return $this->delBase('http_rewrite', $uuid);
|
||||
}
|
||||
|
||||
public function sethttprewriteAction($uuid)
|
||||
{
|
||||
return $this->setBase('httprewrite', 'http_rewrite', $uuid);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
/*
|
||||
|
||||
Copyright (C) 2018 Fabian Franz
|
||||
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\Nginx;
|
||||
|
||||
/**
|
||||
* Class IndexController
|
||||
* @package OPNsense/Nginx
|
||||
*/
|
||||
class IndexController extends \OPNsense\Base\IndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->settings = $this->getForm("settings");
|
||||
$this->view->upstream_server = $this->getForm("upstream_server");
|
||||
$this->view->upstream = $this->getForm("upstream");
|
||||
$this->view->location = $this->getForm("location");
|
||||
$this->view->credential = $this->getForm("credential");
|
||||
$this->view->userlist = $this->getForm("userlist");
|
||||
$this->view->httpserver = $this->getForm("httpserver");
|
||||
$this->view->httprewrite = $this->getForm("httprewrite");
|
||||
$this->view->naxsi_rule = $this->getForm("naxsi_rule");
|
||||
$this->view->naxsi_custom_policy = $this->getForm("naxsi_custom_policy");
|
||||
$this->view->pick('OPNsense/Nginx/index');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<form>
|
||||
<field>
|
||||
<id>credential.username</id>
|
||||
<label>Username</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>credential.password</id>
|
||||
<label>Password</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<form>
|
||||
<field>
|
||||
<id>httprewrite.description</id>
|
||||
<label>Short description (to display)</label>
|
||||
<type>text</type>
|
||||
<help>Enter a short description like a name for this redirect.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>httprewrite.source</id>
|
||||
<label>Original URL Pattern (Regex)</label>
|
||||
<type>text</type>
|
||||
<help>Enter a regular expression to match the URL</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>httprewrite.destination</id>
|
||||
<label>New URL Pattern</label>
|
||||
<type>text</type>
|
||||
<help>You may use replacement strings like $1 for the first match group from the source here.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>httprewrite.flag</id>
|
||||
<label>Flag</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker</style>
|
||||
<help>Stop rule processing (break) and perform (internal) redirect (last). Return a moved permanently status code (301) or a teporary redirect (302).</help>
|
||||
</field>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
<form>
|
||||
<field>
|
||||
<id>httpserver.listen_http_port</id>
|
||||
<label>HTTP Listen Port</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.listen_https_port</id>
|
||||
<label>HTTPS Listen Port</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.servername</id>
|
||||
<label>Server Name</label>
|
||||
<allownew>true</allownew>
|
||||
<style>tokenize</style>
|
||||
<type>select_multiple</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.locations</id>
|
||||
<label>Locations</label>
|
||||
<style>selectpicker</style>
|
||||
<type>select_multiple</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.rewrites</id>
|
||||
<label>URL Rewriting</label>
|
||||
<type>select_multiple</type>
|
||||
<style>selectpicker</style>
|
||||
<help>Choose URL rewriting rules.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.root</id>
|
||||
<label>File System Root</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.certificate</id>
|
||||
<label>TLS Certificate</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.ca</id>
|
||||
<label>CA Certificate</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.verify_client</id>
|
||||
<label>Verify Client Certificate</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[<ul><li>On: the certificate is requested and validated. Use this option to protect a service with TLS authentication.</li><li>Off: The certificate is not requested. Choose this option for a normal website.</li><li>Optional: The certificate is requested and validated if existing. Choose this option for websites, with TLS login support or mixed TLS protected API and web content.</li><li>Optional, don't verify: Do accept the certificate and let the application choose what to do. Choose this option, for the same reasons as optional but in this case, the request is passed to the backend without rejecting untrusted certificates.</li></ul>]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.access_log_format</id>
|
||||
<label>Access Log Format</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.enable_acme_support</id>
|
||||
<label>Enable Let's Encrypt Plugin Support</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.charset</id>
|
||||
<label>Charset</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.https_only</id>
|
||||
<label>HTTPS Only</label>
|
||||
<type>checkbox</type>
|
||||
<help>If you check this box, a TLS encrypted connection is enforced.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.block_nonpublic_data</id>
|
||||
<label>Block Configuration Files</label>
|
||||
<type>checkbox</type>
|
||||
<help>Blocks files like .htaccess files or other files not intended for the public.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.naxsi_extensive_log</id>
|
||||
<label>Extensive Naxsi Log</label>
|
||||
<type>checkbox</type>
|
||||
<help>Provide a more verbose WAF log for fixing false positives before going live.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.sendfile</id>
|
||||
<label>Enable Sendfile</label>
|
||||
<type>checkbox</type>
|
||||
<help>Allow the daemon to use the sendfile function.</help>
|
||||
</field>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
<form>
|
||||
<field>
|
||||
<id>location.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.urlpattern</id>
|
||||
<label>URL Pattern</label>
|
||||
<type>text</type>
|
||||
<help>The URL pattern to match.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.matchtype</id>
|
||||
<label>Match Type</label>
|
||||
<type>dropdown</type>
|
||||
<help>Choose how to match on "URL Pattern".</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.rewrites</id>
|
||||
<label>URL Rewriting</label>
|
||||
<type>select_multiple</type>
|
||||
<style>selectpicker</style>
|
||||
<help>Choose URL rewriting rules.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.enable_secrules</id>
|
||||
<label>Enable Security Rules</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable WAF</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.enable_learning_mode</id>
|
||||
<label>Learning Mode</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable learning mode means nothing is blocked but logged.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.xss_block_score</id>
|
||||
<label>Block XSS Score</label>
|
||||
<type>text</type>
|
||||
<help>Block XSS with a score above the specified value using generic detection.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.sqli_block_score</id>
|
||||
<label>Block SQL Injection Score</label>
|
||||
<type>text</type>
|
||||
<help>Block SQL injection with a score above the specified value using generic detection.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.custom_policy</id>
|
||||
<label>Custom Security Policy</label>
|
||||
<type>select_multiple</type>
|
||||
<style>selectpicker</style>
|
||||
<help>Select custom security policies.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.upstream</id>
|
||||
<label>Upstream Servers</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker</style>
|
||||
<help>Select an upstream to proxy to.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.root</id>
|
||||
<label>File System Root</label>
|
||||
<type>text</type>
|
||||
<help>Enter the file system root from which the files are served.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.index</id>
|
||||
<label>Index File</label>
|
||||
<type>select_multiple</type>
|
||||
<help>Enter a list of file extensions, which are served instead of a directory. It is common to use index.html or index.php here.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.autoindex</id>
|
||||
<label>Automatic Index</label>
|
||||
<type>checkbox</type>
|
||||
<help>Check this to serve a file list when a directory is requested. This is useful for serving multiple files with someone without a web application. It is recommended to use this option only with authentication.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.authbasic</id>
|
||||
<label>Basic Authentication</label>
|
||||
<type>text</type>
|
||||
<help>Enter the realm for this directory and enable authentication.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.authbasicuserfile</id>
|
||||
<label>Basic Credentials List</label>
|
||||
<type>dropdown</type>
|
||||
<help>Select a credential list to use.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.advanced_acl</id>
|
||||
<label>Enable Advanced ACLs</label>
|
||||
<type>checkbox</type>
|
||||
<help>Send an authentication request to the OPNsense backend for advanced access control.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.force_https</id>
|
||||
<label>Force HTTPS</label>
|
||||
<type>checkbox</type>
|
||||
<help>Force encrypted connections.</help>
|
||||
</field>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<form>
|
||||
<field>
|
||||
<id>custompolicy.name</id>
|
||||
<type>text</type>
|
||||
<label>Name</label>
|
||||
</field>
|
||||
<field>
|
||||
<id>custompolicy.naxsi_rules</id>
|
||||
<type>select_multiple</type>
|
||||
<allownew>true</allownew>
|
||||
<style>tokenize</style>
|
||||
<label>Rules</label>
|
||||
</field>
|
||||
<field>
|
||||
<id>custompolicy.value</id>
|
||||
<type>text</type>
|
||||
<label>Value</label>
|
||||
</field>
|
||||
<field>
|
||||
<id>custompolicy.operator</id>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker</style>
|
||||
<label>Operator</label>
|
||||
</field>
|
||||
<field>
|
||||
<id>custompolicy.action</id>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker</style>
|
||||
<label>Action</label>
|
||||
</field>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
<form>
|
||||
<field>
|
||||
<id>naxsi_rule.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.message</id>
|
||||
<label>Message</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.negate</id>
|
||||
<label>Negate</label>
|
||||
<type>checkbox</type>
|
||||
<help>If this is box is checked, the score will be added if the rule does not match. Use with care.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.identifier</id>
|
||||
<label>ID</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.ruletype</id>
|
||||
<label>Rule Type</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.regex</id>
|
||||
<label>Use Regular Expressions</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.match_value</id>
|
||||
<label>Match Value</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.match_type</id>
|
||||
<label>Match Type</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.args</id>
|
||||
<label>Arguments</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.url</id>
|
||||
<label>URL</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.headers</id>
|
||||
<label>Headers</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.body</id>
|
||||
<label>Body</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.name</id>
|
||||
<label>Name</label>
|
||||
<type>checkbox</type>
|
||||
<help>Check this box to match the variable name and not its content when matching any of the above checkboxes.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.file_extension</id>
|
||||
<label>File Extension</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.raw_body</id>
|
||||
<label>Raw Body</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.dollar_url</id>
|
||||
<label>URL or URL Pattern</label>
|
||||
<type>text</type>
|
||||
<help>Enter the name of a parameter to match.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.dollar_args_var</id>
|
||||
<label>Named Argument</label>
|
||||
<type>text</type>
|
||||
<help>Enter the name of a parameter to match.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.dollar_body_var</id>
|
||||
<label>Named Body Variable</label>
|
||||
<type>text</type>
|
||||
<help>Enter the name of a variable in the HTTP body to match.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.dollar_headers_var</id>
|
||||
<label>Named Header</label>
|
||||
<type>text</type>
|
||||
<help>Enter the name of an HTTP header to match.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>naxsi_rule.score</id>
|
||||
<label>Score</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
|
||||
</form>
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<form>
|
||||
<tab id="nginx-general" description="General Settings">
|
||||
<subtab id="nginx-general-settings" description="General Settings">
|
||||
<field>
|
||||
<id>nginx.general.enabled</id>
|
||||
<label>Enable nginx</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable or disable the nginx service.</help>
|
||||
</field>
|
||||
</subtab>
|
||||
<subtab id="nginx-http-global" description="Global HTTP Settings">
|
||||
<field>
|
||||
<id>nginx.http.enabled</id>
|
||||
<label>Enable sendfile</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable sendfile support (faster).</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>nginx.http.keepalive_timeout</id>
|
||||
<label>Keepalive Timeout</label>
|
||||
<type>text</type>
|
||||
<help>After this idle time, the client gets disconnected.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>nginx.http.default_type</id>
|
||||
<label>Default MIME-Type</label>
|
||||
<type>text</type>
|
||||
<help>This content type is sent if the file extension is unknown.</help>
|
||||
</field>
|
||||
</subtab>
|
||||
<subtab id="nginx-general-webgui" description="GUI Settings">
|
||||
<field>
|
||||
<id>nginx.webgui.limitnetworks</id>
|
||||
<label>Limit Networks</label>
|
||||
<type>checkbox</type>
|
||||
<help>Limit networks to directly connected networks. Enabling this option is recommended if your nginx instance is reachable via the internet to prevent remote access to the web interface for security reasons. Please note that you can lock yourself out if you are accessing OPNsense via a router without SNAT.</help>
|
||||
</field>
|
||||
</subtab>
|
||||
</tab>
|
||||
<!--
|
||||
<tab id="nginx-mail" description="E-Mail">
|
||||
<subtab id="nginx-mail-pop3" description="POP3">
|
||||
<field>
|
||||
<id>nginx.mail.pop.enabled</id>
|
||||
<label>Enable sendfile</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable sendfile support (faster).</help>
|
||||
</field>
|
||||
</subtab>
|
||||
<subtab id="nginx-mail-pop3" description="IMAP">
|
||||
<field>
|
||||
<id>nginx.mail.imap.enabled</id>
|
||||
<label>Enable sendfile</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable sendfile support (faster).</help>
|
||||
</field>
|
||||
</subtab>
|
||||
</tab>
|
||||
-->
|
||||
<activetab>nginx-general-settings</activetab>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<form>
|
||||
<field>
|
||||
<id>upstream.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>upstream.serverentries</id>
|
||||
<label>Server Entries</label>
|
||||
<style>selectpicker</style>
|
||||
<type>select_multiple</type>
|
||||
</field>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<form>
|
||||
<field>
|
||||
<id>upstream_server.description</id>
|
||||
<label>Beschreibung</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>upstream_server.server</id>
|
||||
<label>Server</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>upstream_server.port</id>
|
||||
<label>Port</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>upstream_server.priority</id>
|
||||
<label>Server Priority</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>upstream_server.max_conns</id>
|
||||
<label>Maximum Connections</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>upstream_server.max_fails</id>
|
||||
<label>Maximum Failures</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>upstream_server.fail_timeout</id>
|
||||
<label>Fail Timeout</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>upstream_server.no_use</id>
|
||||
<label>Do Not Use</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<form>
|
||||
<field>
|
||||
<id>userlist.name</id>
|
||||
<label>Name</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>userlist.users</id>
|
||||
<label>Users</label>
|
||||
<type>select_multiple</type>
|
||||
</field>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<acl>
|
||||
<page-Nginx>
|
||||
<name>nginx</name>
|
||||
<patterns>
|
||||
<pattern>ui/nginx/*</pattern>
|
||||
<pattern>api/nginx/*</pattern>
|
||||
</patterns>
|
||||
</page-Nginx>
|
||||
</acl>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<menu>
|
||||
<Services>
|
||||
<Nginx cssClass="fa fa-shield fa-fw" url="/ui/nginx" />
|
||||
</Services>
|
||||
</menu>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/*
|
||||
Copyright (C) 2017 Fabian Franz
|
||||
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\Nginx;
|
||||
|
||||
use OPNsense\Base\BaseModel;
|
||||
|
||||
class Nginx extends BaseModel
|
||||
{
|
||||
}
|
||||
445
www/nginx/src/opnsense/mvc/app/models/OPNsense/Nginx/Nginx.xml
Normal file
445
www/nginx/src/opnsense/mvc/app/models/OPNsense/Nginx/Nginx.xml
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
<model>
|
||||
<mount>//OPNsense/Nginx</mount>
|
||||
<description>nginx web server, reverse proxy and waf</description>
|
||||
<items>
|
||||
<general>
|
||||
<enabled type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
</general>
|
||||
|
||||
<webgui>
|
||||
<limitnetworks type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</limitnetworks>
|
||||
</webgui>
|
||||
|
||||
<http>
|
||||
<sendfile type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>N</Required>
|
||||
</sendfile>
|
||||
<keepalive_timeout type="IntegerField">
|
||||
<default>60</default>
|
||||
<Required>N</Required>
|
||||
</keepalive_timeout>
|
||||
<default_type type="TextField">
|
||||
<Required>N</Required>
|
||||
</default_type>
|
||||
</http>
|
||||
|
||||
<userlist type="ArrayField">
|
||||
<name type="TextField">
|
||||
<Required>Y</Required>
|
||||
</name>
|
||||
<users type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>credential</items>
|
||||
<display>username</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected user not found</ValidationMessage>
|
||||
<Required>Y</Required>
|
||||
<multiple>Y</multiple>
|
||||
</users>
|
||||
</userlist>
|
||||
|
||||
<credential type="ArrayField">
|
||||
<username type="TextField">
|
||||
<Required>Y</Required>
|
||||
</username>
|
||||
<password type="TextField">
|
||||
<Required>Y</Required>
|
||||
</password>
|
||||
</credential>
|
||||
|
||||
<upstream type="ArrayField">
|
||||
<description type="TextField">
|
||||
<Required>Y</Required>
|
||||
</description>
|
||||
<serverentries type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>upstream_server</items>
|
||||
<display>description</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected server not found</ValidationMessage>
|
||||
<Required>Y</Required>
|
||||
<multiple>Y</multiple>
|
||||
</serverentries>
|
||||
</upstream>
|
||||
|
||||
<upstream_server type="ArrayField">
|
||||
<description type="TextField">
|
||||
<Required>Y</Required>
|
||||
</description>
|
||||
<server type="HostnameField">
|
||||
<Required>Y</Required>
|
||||
</server>
|
||||
<port type="PortField">
|
||||
<Required>Y</Required>
|
||||
</port>
|
||||
<priority type="IntegerField">
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<Required>Y</Required>
|
||||
</priority>
|
||||
<max_conns type="IntegerField">
|
||||
<Required>N</Required>
|
||||
</max_conns>
|
||||
<max_fails type="IntegerField">
|
||||
<Required>N</Required>
|
||||
</max_fails>
|
||||
<fail_timeout type="IntegerField">
|
||||
<Required>N</Required>
|
||||
</fail_timeout>
|
||||
<no_use type="OptionField">
|
||||
<OptionValues>
|
||||
<down>Permanently Unreachable</down>
|
||||
<backup>Backup Server</backup>
|
||||
</OptionValues>
|
||||
<Required>N</Required>
|
||||
</no_use>
|
||||
</upstream_server>
|
||||
|
||||
<location type="ArrayField">
|
||||
<description type="TextField">
|
||||
<Required>Y</Required>
|
||||
</description>
|
||||
<urlpattern type="TextField">
|
||||
<Required>Y</Required>
|
||||
</urlpattern>
|
||||
<matchtype type="OptionField">
|
||||
<OptionValues>
|
||||
<option1 value="=">Exact Match ("=")</option1>
|
||||
<option2 value="~">Case Sensitive Match ("~")</option2>
|
||||
<option3 value="~*">Case Insensitive Match ("~*")</option3>
|
||||
<option4 value="^~">Don't check regular expressions on logest prefix match ("^~")</option4>
|
||||
</OptionValues>
|
||||
<Required>N</Required>
|
||||
</matchtype>
|
||||
<enable_secrules type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</enable_secrules>
|
||||
<enable_learning_mode type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</enable_learning_mode>
|
||||
<xss_block_score type="IntegerField">
|
||||
<Required>N</Required>
|
||||
</xss_block_score>
|
||||
<sqli_block_score type="IntegerField">
|
||||
<Required>N</Required>
|
||||
</sqli_block_score>
|
||||
<custom_policy type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>custom_policy</items>
|
||||
<display>name</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected server not found</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
<multiple>Y</multiple>
|
||||
</custom_policy>
|
||||
<upstream type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>upstream</items>
|
||||
<display>description</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected upstream not found</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
<multiple>N</multiple>
|
||||
</upstream>
|
||||
<root type="TextField">
|
||||
<Required>N</Required>
|
||||
</root>
|
||||
<rewrites type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>http_rewrite</items>
|
||||
<display>description</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected rewrite(s) not found</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
<multiple>Y</multiple>
|
||||
</rewrites>
|
||||
<index type="CSVListField">
|
||||
<Required>N</Required>
|
||||
</index>
|
||||
<autoindex type="BooleanField">
|
||||
<Required>N</Required>
|
||||
</autoindex>
|
||||
<authbasic type="TextField">
|
||||
<Required>N</Required>
|
||||
</authbasic>
|
||||
<authbasicuserfile type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>userlist</items>
|
||||
<display>name</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected server not found</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
<multiple>Y</multiple>
|
||||
</authbasicuserfile>
|
||||
<advanced_acl type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</advanced_acl>
|
||||
<force_https type="TextField">
|
||||
<Required>N</Required>
|
||||
</force_https>
|
||||
</location>
|
||||
|
||||
<custom_policy type="ArrayField">
|
||||
<name type="TextField">
|
||||
<Required>Y</Required>
|
||||
</name>
|
||||
<naxsi_rules type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>naxsi_rule</items>
|
||||
<display>description</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected rule not found</ValidationMessage>
|
||||
<Required>Y</Required>
|
||||
<multiple>Y</multiple>
|
||||
</naxsi_rules>
|
||||
<value type="IntegerField">
|
||||
<Required>Y</Required>
|
||||
</value>
|
||||
<operator type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>>=</default>
|
||||
<OptionValues>
|
||||
<option1 value=">=">Bigger or Equal</option1>
|
||||
<option2 value=">">Bigger</option2>
|
||||
<option3 value="<">Lesser</option3>
|
||||
<option4 value="<=">Lesser or Equal</option4>
|
||||
<option5 value="=">Equal</option5>
|
||||
</OptionValues>
|
||||
</operator>
|
||||
<action type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>BLOCK</default>
|
||||
<OptionValues>
|
||||
<BLOCK>Block Request</BLOCK>
|
||||
<ALLOW>Allow Request</ALLOW>
|
||||
<DROP>Drop The Connection</DROP>
|
||||
<LOG>Log Request</LOG>
|
||||
</OptionValues>
|
||||
</action>
|
||||
</custom_policy>
|
||||
|
||||
<naxsi_rule type="ArrayField">
|
||||
<description type="TextField">
|
||||
<Required>Y</Required>
|
||||
</description>
|
||||
<ruletype type="OptionField">
|
||||
<OptionValues>
|
||||
<main>Main Rule</main>
|
||||
<basic>Basic Rule</basic>
|
||||
</OptionValues>
|
||||
<Required>Y</Required>
|
||||
</ruletype>
|
||||
<message type="TextField">
|
||||
<Required>Y</Required>
|
||||
<pattern>/^[^"]+$/</pattern>
|
||||
</message>
|
||||
<identifier type="IntegerField">
|
||||
<Required>Y</Required>
|
||||
<minValue>1000</minValue>
|
||||
</identifier>
|
||||
<url type="TextField">
|
||||
<Required>N</Required>
|
||||
<pattern>/^[^"]+$/</pattern>
|
||||
</url>
|
||||
<dollar_url type="TextField">
|
||||
<Required>N</Required>
|
||||
<pattern>/^[^"]+$/</pattern>
|
||||
</dollar_url>
|
||||
<match_value type="TextField">
|
||||
<Required>Y</Required>
|
||||
<pattern>/^[^"]+$/</pattern>
|
||||
</match_value>
|
||||
<match_type type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>id</default>
|
||||
<OptionValues>
|
||||
<id>Blacklist</id>
|
||||
<wl>Whitelist</wl>
|
||||
</OptionValues>
|
||||
</match_type>
|
||||
<negate type="BooleanField">
|
||||
<Required>Y</Required>
|
||||
</negate>
|
||||
<score type="IntegerField">
|
||||
<Required>Y</Required>
|
||||
<default>8</default>
|
||||
</score>
|
||||
<regex type="BooleanField">
|
||||
<Required>Y</Required>
|
||||
</regex>
|
||||
<args type="BooleanField">
|
||||
<Required>Y</Required>
|
||||
</args>
|
||||
<headers type="BooleanField">
|
||||
<Required>Y</Required>
|
||||
</headers>
|
||||
<dollar_args_var type="TextField">
|
||||
<pattern>/^[^"]+$/</pattern>
|
||||
</dollar_args_var>
|
||||
<dollar_body_var type="TextField">
|
||||
<pattern>/^[^"]+$/</pattern>
|
||||
</dollar_body_var>
|
||||
<dollar_headers_var type="TextField">
|
||||
<pattern>/^[^"]+$/</pattern>
|
||||
</dollar_headers_var>
|
||||
<file_extension type="BooleanField">
|
||||
<Required>Y</Required>
|
||||
</file_extension>
|
||||
<raw_body type="BooleanField">
|
||||
<Required>Y</Required>
|
||||
</raw_body>
|
||||
<name type="BooleanField">
|
||||
<Required>Y</Required>
|
||||
</name>
|
||||
</naxsi_rule>
|
||||
|
||||
<http_server type="ArrayField">
|
||||
<servername type="CSVListField">
|
||||
<Required>Y</Required>
|
||||
</servername>
|
||||
<listen_http_port type="PortField">
|
||||
<Required>N</Required>
|
||||
<default>80</default>
|
||||
</listen_http_port>
|
||||
<listen_https_port type="PortField">
|
||||
<Required>N</Required>
|
||||
<default>443</default>
|
||||
</listen_https_port>
|
||||
<locations type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>location</items>
|
||||
<display>description</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected location(s) not found</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
<multiple>Y</multiple>
|
||||
</locations>
|
||||
<rewrites type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>http_rewrite</items>
|
||||
<display>description</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected rewrite(s) not found</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
<multiple>Y</multiple>
|
||||
</rewrites>
|
||||
<root type="TextField">
|
||||
<Required>N</Required>
|
||||
</root>
|
||||
<certificate type="CertificateField">
|
||||
<Type>cert</Type>
|
||||
<Required>N</Required>
|
||||
</certificate>
|
||||
<ca type="CertificateField">
|
||||
<Type>ca</Type>
|
||||
<Required>N</Required>
|
||||
</ca>
|
||||
<verify_client type="OptionField">
|
||||
<default>Off</default>
|
||||
<OptionValues>
|
||||
<off>Off</off>
|
||||
<on>On</on>
|
||||
<optional>Optional</optional>
|
||||
<optional_no_ca>Optional, don't verify</optional_no_ca>
|
||||
</OptionValues>
|
||||
<Required>Y</Required>
|
||||
</verify_client>
|
||||
<access_log_format type="OptionField">
|
||||
<default>main</default>
|
||||
<OptionValues>
|
||||
<main>Default</main>
|
||||
<anonymized>Anonymized</anonymized>
|
||||
<disabled>Disabled</disabled>
|
||||
</OptionValues>
|
||||
<Required>Y</Required>
|
||||
</access_log_format>
|
||||
<enable_acme_support type="BooleanField">
|
||||
<Required>Y</Required>
|
||||
<default>1</default>
|
||||
</enable_acme_support>
|
||||
<charset type="OptionField">
|
||||
<default>utf-8</default>
|
||||
<OptionValues>
|
||||
<utf-8>utf-8</utf-8>
|
||||
</OptionValues>
|
||||
<Required>N</Required>
|
||||
</charset>
|
||||
<https_only type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</https_only>
|
||||
<block_nonpublic_data type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</block_nonpublic_data>
|
||||
<naxsi_extensive_log type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</naxsi_extensive_log>
|
||||
<sendfile type="BooleanField">
|
||||
<default>1</default>
|
||||
<Required>Y</Required>
|
||||
</sendfile>
|
||||
</http_server>
|
||||
|
||||
<http_rewrite type="ArrayField">
|
||||
<description type="TextField">
|
||||
<Required>Y</Required>
|
||||
<mask>/^[^" \t]+$/i</mask>
|
||||
</description>
|
||||
<source type="TextField">
|
||||
<Required>Y</Required>
|
||||
</source>
|
||||
<destination type="TextField">
|
||||
<Required>Y</Required>
|
||||
<mask>/^[^" \t]+$/i</mask>
|
||||
</destination>
|
||||
<flag type="OptionField">
|
||||
<OptionValues>
|
||||
<break>Stop processing rules</break>
|
||||
<last>Stop processing rules and find location</last>
|
||||
<redirect>Redirect</redirect>
|
||||
<permanent>Permanent</permanent>
|
||||
</OptionValues>
|
||||
<Required>N</Required>
|
||||
</flag>
|
||||
</http_rewrite>
|
||||
|
||||
</items>
|
||||
</model>
|
||||
382
www/nginx/src/opnsense/mvc/app/views/OPNsense/Nginx/index.volt
Normal file
382
www/nginx/src/opnsense/mvc/app/views/OPNsense/Nginx/index.volt
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
{#
|
||||
# Copyright (C) 2017-2018 Fabian Franz
|
||||
# Copyright (C) 2014-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.
|
||||
#}
|
||||
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
|
||||
var data_get_map = {'frm_nginx':'/api/nginx/settings/get'};
|
||||
|
||||
// load initial data
|
||||
mapDataToFormUI(data_get_map).done(function(){
|
||||
formatTokenizersUI();
|
||||
$('select[data-allownew="false"]').selectpicker('refresh')
|
||||
updateServiceControlUI('nginx');
|
||||
});
|
||||
|
||||
// update history on tab state and implement navigation
|
||||
if(window.location.hash != "") {
|
||||
$('a[href="' + window.location.hash + '"]').click()
|
||||
}
|
||||
$('.nav-tabs a').on('shown.bs.tab', function (e) {
|
||||
history.pushState(null, null, e.target.hash);
|
||||
});
|
||||
$('#nginx\\.general\\.enable_redis_plugin').change(function (evt) {
|
||||
$('#missing_redis_plugin').hide();
|
||||
if (!window.redis_installed && $(this).is(':checked')) {
|
||||
$('#missing_redis_plugin').show();
|
||||
}
|
||||
});
|
||||
|
||||
$('.reload_btn').click(function() {
|
||||
$(".reloadAct_progress").addClass("fa-spin");
|
||||
ajaxCall(url="/api/nginx/service/reconfigure", sendData={}, callback=function(data,status) {
|
||||
$(".reloadAct_progress").removeClass("fa-spin");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// form save event handlers for all defined forms
|
||||
$('[id*="save_"]').each(function(){
|
||||
$(this).click(function() {
|
||||
var frm_id = $(this).closest("form").attr("id");
|
||||
var frm_title = $(this).closest("form").attr("data-title");
|
||||
// save data for General TAB
|
||||
saveFormToEndpoint(url="/api/nginx/settings/set", formid=frm_id, callback_ok=function(){
|
||||
// on correct save, perform reconfigure. set progress animation when reloading
|
||||
$("#"+frm_id+"_progress").addClass("fa fa-spinner fa-pulse");
|
||||
|
||||
ajaxCall(url="/api/nginx/service/reconfigure", sendData={}, callback=function(data,status){
|
||||
// when done, disable progress animation.
|
||||
$("#"+frm_id+"_progress").removeClass("fa fa-spinner fa-pulse");
|
||||
|
||||
if (data != undefined && (status != "success" || data['status'] != 'ok')) {
|
||||
// fix error handling
|
||||
BootstrapDialog.show({
|
||||
type:BootstrapDialog.TYPE_WARNING,
|
||||
title: frm_title,
|
||||
message: JSON.stringify(data),
|
||||
draggable: true
|
||||
});
|
||||
} else {
|
||||
updateServiceControlUI('nginx');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
['upstream',
|
||||
'upstreamserver',
|
||||
'location',
|
||||
'credential',
|
||||
'userlist',
|
||||
'httpserver',
|
||||
'httprewrite',
|
||||
'custompolicy',
|
||||
'naxsirule'].forEach(function(element) {
|
||||
$("#grid-" + element).UIBootgrid(
|
||||
{ 'search':'/api/nginx/settings/search' + element,
|
||||
'get':'/api/nginx/settings/get' + element + '/',
|
||||
'set':'/api/nginx/settings/set' + element + '/',
|
||||
'add':'/api/nginx/settings/add' + element + '/',
|
||||
'del':'/api/nginx/settings/del' + element + '/',
|
||||
'options':{selection:false, multiSelect:false}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<ul class="nav nav-tabs" role="tablist" id="maintabs">
|
||||
{{ partial("layout_partials/base_tabs_header",['formData':settings]) }}
|
||||
<li role="presentation" class="dropdown">
|
||||
<a data-toggle="dropdown" href="#" class="dropdown-toggle pull-right visible-lg-inline-block visible-md-inline-block visible-xs-inline-block visible-sm-inline-block" role="button">
|
||||
<b><span class="caret"></span></b>
|
||||
</a>
|
||||
<a data-toggle="tab" onclick="$('#subtab_item_nginx-http-location').click();" class="visible-lg-inline-block visible-md-inline-block visible-xs-inline-block visible-sm-inline-block" style="border-right:0px;"><b>{{ lang._('HTTP(S)')}}</b></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-location" href="#subtab_nginx-http-location">{{ lang._('Location')}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-credential" href="#subtab_nginx-http-credential">{{ lang._('Credential')}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-userlist" href="#subtab_nginx-http-userlist">{{ lang._('User List')}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-upstream-server" href="#subtab_nginx-http-upstream-server">{{ lang._('Upstream Server')}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-upstream" href="#subtab_nginx-http-upstream">{{ lang._('Upstream')}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-server" href="#subtab_nginx-http-httpserver">{{ lang._('HTTP Server')}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-rewrite" href="#subtab_nginx-http-rewrite">{{ lang._('URL Rewriting')}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-custompolicy" href="#subtab_nginx-http-custompolicy">{{ lang._('Naxsi WAF Policy')}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-naxsirule" href="#subtab_nginx-http-naxsirule">{{ lang._('Naxsi WAF Rule')}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="content-box tab-content">
|
||||
{{ partial("layout_partials/base_tabs_content",['formData':settings]) }}
|
||||
<div id="subtab_nginx-http-location" class="tab-pane fade">
|
||||
<table id="grid-location" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="locationdlg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="description" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="urlpattern" data-type="string" data-sortable="true" data-visible="true">{{ lang._('URL Pattern') }}</th>
|
||||
<th data-column-id="matchtype" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Match Type') }}</th>
|
||||
<th data-column-id="enable_secrules" data-type="boolean" data-sortable="true" data-visible="true">{{ lang._('WAF Enabled') }}</th>
|
||||
<th data-column-id="force_https" data-type="boolean" data-sortable="true" data-visible="true">{{ lang._('Force HTTPS') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="subtab_nginx-http-upstream-server" class="tab-pane fade">
|
||||
<table id="grid-upstreamserver" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="upstreamserverdlg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="description" data-type="string" data-sortable="false" data-visible="true">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="server" data-type="string" data-sortable="false" data-visible="true">{{ lang._('Server') }}</th>
|
||||
<th data-column-id="priority" data-type="string" data-sortable="false" data-visible="true">{{ lang._('Priority') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="subtab_nginx-http-upstream" class="tab-pane fade">
|
||||
<table id="grid-upstream" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="upstreamdlg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="description" data-type="string" data-sortable="false" data-visible="true">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="serverentries" data-type="string" data-sortable="false" data-visible="true">{{ lang._('Servers') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div id="subtab_nginx-http-credential" class="tab-pane fade">
|
||||
<table id="grid-credential" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="credentialdlg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="username" data-type="string" data-sortable="false" data-visible="true">{{ lang._('Username') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div id="subtab_nginx-http-userlist" class="tab-pane fade">
|
||||
<table id="grid-userlist" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="userlistdlg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="name" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Name') }}</th>
|
||||
<th data-column-id="users" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Users') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div id="subtab_nginx-http-httpserver" class="tab-pane fade">
|
||||
<table id="grid-httpserver" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="httpserverdlg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="servername" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Servername') }}</th>
|
||||
<th data-column-id="https_only" data-type="boolean" data-sortable="true" data-visible="true">{{ lang._('HTTPS Only') }}</th>
|
||||
<th data-column-id="certificate" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Certificate') }}</th>
|
||||
<th data-column-id="listen_http_port" data-type="string" data-sortable="true" data-visible="true">{{ lang._('HTTP Port') }}</th>
|
||||
<th data-column-id="listen_https_port" data-type="string" data-sortable="true" data-visible="true">{{ lang._('HTTPS Port') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div id="subtab_nginx-http-rewrite" class="tab-pane fade">
|
||||
<table id="grid-httprewrite" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="httprewritedlg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="description" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="source" data-type="boolean" data-sortable="true" data-visible="true">{{ lang._('Source URL') }}</th>
|
||||
<th data-column-id="destination" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Destination URL') }}</th>
|
||||
<th data-column-id="flag" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Flag') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div id="subtab_nginx-http-custompolicy" class="tab-pane fade">
|
||||
<table id="grid-custompolicy" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="custompolicydlg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="name" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Name') }}</th>
|
||||
<th data-column-id="operator" data-type="boolean" data-sortable="true" data-visible="true">{{ lang._('Operator') }}</th>
|
||||
<th data-column-id="value" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Value') }}</th>
|
||||
<th data-column-id="action" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Action') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div id="subtab_nginx-http-naxsirule" class="tab-pane fade">
|
||||
<table id="grid-naxsirule" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="naxsiruledlg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="description" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="ruletype" data-type="boolean" data-sortable="true" data-visible="true">{{ lang._('Rule Type') }}</th>
|
||||
<th data-column-id="message" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Message') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{{ partial("layout_partials/base_dialog",['fields': upstream,'id':'upstreamdlg', 'label':lang._('Edit Upstream')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': upstream_server,'id':'upstreamserverdlg', 'label':lang._('Edit Upstream')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': location,'id':'locationdlg', 'label':lang._('Edit Location')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': credential,'id':'credentialdlg', 'label':lang._('Edit Credential')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': userlist,'id':'userlistdlg', 'label':lang._('Edit User List')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': httpserver,'id':'httpserverdlg', 'label':lang._('Edit HTTP Server')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': httprewrite,'id':'httprewritedlg', 'label':lang._('Edit URL Rewrite')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': naxsi_custom_policy,'id':'custompolicydlg', 'label':lang._('Edit WAF Policy')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': naxsi_rule,'id':'naxsiruledlg', 'label':lang._('Edit Naxsi Rule')]) }}
|
||||
55
www/nginx/src/opnsense/scripts/nginx/ngx_auth.php
Normal file
55
www/nginx/src/opnsense/scripts/nginx/ngx_auth.php
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Fabian Franz
|
||||
* 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.
|
||||
*/
|
||||
|
||||
require_once("config.inc");
|
||||
require_once("auth.inc");
|
||||
require_once("util.inc");
|
||||
|
||||
$uri = $_SERVER['Original-URI'];
|
||||
$host = $_SERVER['Original-HOST'];
|
||||
$method = $_SERVER['Original-METHOD'];
|
||||
$is_https = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on';
|
||||
$server_uuid = $_SERVER['SERVER-UUID'];
|
||||
|
||||
function password_auth_test($username, $password, $auth_server) {
|
||||
$authFactory = new OPNsense\Auth\AuthenticationFactory;
|
||||
$authenticator = $authFactory->get($auth_server);
|
||||
return $authenticator->authenticate($username, $password);
|
||||
}
|
||||
|
||||
function password_auth($auth_server = 'Local Database') {
|
||||
if (!isset($_SERVER['PHP_AUTH_PW']) || !isset($_SERVER['PHP_AUTH_PW'])) return false;
|
||||
return password_auth_test($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'], $auth_server);
|
||||
}
|
||||
|
||||
if (password_auth()) {
|
||||
header("HTTP/1.1 200 OK");
|
||||
} else {
|
||||
header("HTTP/1.1 401 Authorization Required");
|
||||
header('WWW-Authenticate: Basic realm="OPNsense Protected Area - Authentication Required"');
|
||||
}
|
||||
105
www/nginx/src/opnsense/scripts/nginx/setup.php
Executable file
105
www/nginx/src/opnsense/scripts/nginx/setup.php
Executable file
|
|
@ -0,0 +1,105 @@
|
|||
#!/usr/local/bin/php
|
||||
<?php
|
||||
|
||||
require_once('config.inc');
|
||||
require_once('certs.inc');
|
||||
use \OPNsense\Nginx\Nginx;
|
||||
|
||||
function export_pem_file($filename, $data) {
|
||||
$pem_content = trim(str_replace("\n\n", "\n", str_replace(
|
||||
"\r",
|
||||
"",
|
||||
base64_decode((string)$data))
|
||||
));
|
||||
file_put_contents($filename, $pem_content);
|
||||
chmod($filename, 0600);
|
||||
}
|
||||
|
||||
function find_cert($refid) {
|
||||
global $config;
|
||||
foreach($config['cert'] as $cert_entry) {
|
||||
if ($cert_entry['refid'] == $refid) {
|
||||
return $cert_entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function find_ca($refid) {
|
||||
global $config;
|
||||
foreach($config['ca'] as $cert_entry) {
|
||||
if ($cert_entry['refid'] == $refid) {
|
||||
return $cert_entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// export certificates
|
||||
if (!isset($config['OPNsense']['Nginx'])) {
|
||||
die("nginx is not configured");
|
||||
}
|
||||
$nginx = $config['OPNsense']['Nginx'];
|
||||
if (!isset($nginx['http_server'])) {
|
||||
die("no http servers configured");
|
||||
}
|
||||
if (is_array($nginx['http_server']) && !isset($nginx['http_server']['servername'])) {
|
||||
$http_servers = $nginx['http_server'];
|
||||
} else {
|
||||
$http_servers = array($nginx['http_server']);
|
||||
}
|
||||
@mkdir('/usr/local/etc/nginx/key', 0750, true);
|
||||
@mkdir("/var/db/nginx/auth", 0750, true);
|
||||
foreach ($http_servers as $http_server) {
|
||||
if (!empty($http_server['listen_https_port']) && !empty($http_server['certificate']))
|
||||
{
|
||||
// try to find the reference
|
||||
$cert = find_cert($http_server['certificate']);
|
||||
if (!isset($cert)) {
|
||||
next;
|
||||
}
|
||||
$hostname = explode(',', $http_server['servername'])[0];
|
||||
export_pem_file(
|
||||
'/usr/local/etc/nginx/key/' . $hostname . '.pem',
|
||||
$cert['crt']
|
||||
);
|
||||
export_pem_file(
|
||||
'/usr/local/etc/nginx/key/' . $hostname . '.key',
|
||||
$cert['prv']
|
||||
);
|
||||
if (!empty($http_server['ca'])) {
|
||||
foreach ($http_server['ca'] as $caref) {
|
||||
$ca = find_ca($caref);
|
||||
if (isset($ca)) {
|
||||
export_pem_file(
|
||||
'/usr/local/etc/nginx/key/' . $hostname . '_ca.pem',
|
||||
$ca['crt']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// end export certificates
|
||||
|
||||
// export users
|
||||
$nginx = new Nginx();
|
||||
foreach ($nginx->userlist->__items as $user_list) {
|
||||
$attributes = $user_list->getAttributes();
|
||||
$uuid = $attributes['uuid'];
|
||||
$file = null;
|
||||
try {
|
||||
$file = fopen("/var/db/nginx/auth/" . $uuid, "wb");
|
||||
$users = explode(',',(string)$user_list->users);
|
||||
foreach ($users as $user) {
|
||||
$user_node = $nginx->getNodeByReference("credential." . $user);
|
||||
$username = (string)$user_node->username;
|
||||
$password = crypt((string)$user_node->password);
|
||||
fwrite($file, $username . ':' . $password . "\n");
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (isset($file)) {
|
||||
fclose($file);
|
||||
}
|
||||
unset($file);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
[start]
|
||||
command:/usr/local/opnsense/scripts/nginx/setup.php;/usr/local/etc/rc.d/php-fpm start;/usr/local/etc/rc.d/nginx start
|
||||
parameters:
|
||||
type:script
|
||||
message:starting nginx
|
||||
|
||||
[stop]
|
||||
command:/usr/local/etc/rc.d/nginx stop
|
||||
parameters:
|
||||
type:script
|
||||
message:stopping nginx
|
||||
|
||||
[restart]
|
||||
command:/usr/local/opnsense/scripts/nginx/setup.php;/usr/local/etc/rc.d/php-fpm restart;/usr/local/etc/rc.d/nginx restart
|
||||
parameters:
|
||||
type:script
|
||||
message:restarting nginx
|
||||
|
||||
[status]
|
||||
command:/usr/local/etc/rc.d/nginx status;exit 0
|
||||
parameters:
|
||||
type:script_output
|
||||
|
||||
[phpstatus]
|
||||
command:/usr/local/etc/rc.d/php-fpm status; exit 0
|
||||
parameters:
|
||||
type:script_output
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
nginx:/etc/rc.conf.d/nginx
|
||||
nginx.conf:/usr/local/etc/nginx/nginx.conf
|
||||
webgui.conf:/usr/local/etc/nginx/nginx_web.conf
|
||||
mime.types:/usr/local/etc/nginx/mime.types
|
||||
php_fpm:/etc/rc.conf.d/php_fpm
|
||||
php-www.conf:/usr/local/etc/php-fpm.d/www.conf
|
||||
php-webgui.conf:/usr/local/etc/php-fpm.d/webgui.conf
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
include mime.types;
|
||||
|
||||
{% include "OPNsense/Nginx/ruleset.conf" ignore missing with context %}
|
||||
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
log_format anonymized ':: - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
#tcp_nopush on;
|
||||
|
||||
# 200M should be big enough for file servers etc.
|
||||
client_max_body_size 200M;
|
||||
brotli_static on;
|
||||
brotli on;
|
||||
gzip_static on;
|
||||
gzip on;
|
||||
server_tokens off;
|
||||
sendfile {% if OPNsense.Nginx.http.sendfile is defined and OPNsense.Nginx.http.sendfile == '1' %}On{% else %}Off{% endif %};
|
||||
{% if OPNsense.Nginx.http.default_type is defined and OPNsense.Nginx.http.default_type != '' %}
|
||||
default_type {{ OPNsense.Nginx.http.default_type }};
|
||||
{% else %}
|
||||
default_type application/octet-stream;
|
||||
{% endif %}
|
||||
{% if OPNsense.Nginx.http.keepalive_timeout is defined and OPNsense.Nginx.http.keepalive_timeout != '' %}
|
||||
keepalive_timeout {{ OPNsense.Nginx.http.keepalive_timeout }};
|
||||
{% endif %}
|
||||
|
||||
#add_header X-Frame-Options SAMEORIGIN;
|
||||
#add_header X-Content-Type-Options nosniff;
|
||||
#add_header X-XSS-Protection "1; mode=block";
|
||||
#add_header Referrer-Policy "same-origin";
|
||||
|
||||
# TODO add when core is ready for allowing nginx to serve the web interface
|
||||
# include nginx_web.conf;
|
||||
|
||||
{% include "OPNsense/Nginx/upstream.conf" ignore missing with context %}
|
||||
|
||||
{% set listen_list = [] %}
|
||||
{% for server in helpers.toList('OPNsense.Nginx.http_server') %}
|
||||
{% set single_servername = server.servername.split(",")[0] %}
|
||||
server {
|
||||
{% if server.listen_http_port is defined %}
|
||||
listen [::]:{{ server.listen_http_port }}{% if server.listen_https_port not in listen_list%} ipv6only=off{% endif %};
|
||||
{% do listen_list.append(server.listen_http_port) %}
|
||||
{% endif %}
|
||||
{% if server.listen_https_port is defined and server.certificate is defined %}
|
||||
listen [::]:{{ server.listen_https_port }}{% if server.listen_https_port not in listen_list%} ipv6only=off{% endif %} http2 ssl;
|
||||
{% do listen_list.append(server.listen_https_port) %}
|
||||
{% if server.ca is defined %}
|
||||
ssl_client_certificate /usr/local/etc/nginx/key/{{ single_servername }}_ca.pem;
|
||||
ssl_verify_client {{ server.verify_client }};
|
||||
{% endif %}
|
||||
ssl_certificate_key /usr/local/etc/nginx/key/{{ single_servername }}.key;
|
||||
ssl_certificate /usr/local/etc/nginx/key/{{ single_servername }}.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_dhparam /usr/local/etc/dh-parameters.4096;
|
||||
ssl_ciphers 'ECDHE-ECDSA-CAMELLIA256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CAMELLIA256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CAMELLIA128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CAMELLIA128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-CAMELLIA256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-CAMELLIA256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-CAMELLIA128-SHA256:ECDHE-RSA-AES128-SHA256';
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:50m;
|
||||
ssl_session_tickets off;
|
||||
ssl_prefer_server_ciphers on;
|
||||
add_header Strict-Transport-Security max-age=15768000;
|
||||
sendfile {% if server.sendfile is defined and server.sendfile == '1' %}On{% else %}Off{% endif %};
|
||||
proxy_set_header X-TLS-Cipher $ssl_cipher;
|
||||
proxy_set_header X-TLS-Protocol $ssl_protocol;
|
||||
proxy_set_header X-TLS-SNI-Host $ssl_server_name;
|
||||
{% endif %}
|
||||
# proxy headers for backend server
|
||||
{% if server.verify_client != 'off' %}
|
||||
proxy_set_header X-Client-Dn $ssl_client_s_dn;
|
||||
proxy_set_header X-Client-Verify $ssl_client_verify;
|
||||
{% endif %}
|
||||
{% if server.verify_client == 'optional_no_ca' %}
|
||||
proxy_set_header X-Client-Certificate $ssl_client_escaped_cert;
|
||||
{% endif %}
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
server_name {{ server.servername }};
|
||||
charset {{ server.charset }};
|
||||
access_log /var/log/nginx/{{ server.servername }}.access.log {{ server.access_log_format }};
|
||||
#include tls.conf;
|
||||
error_page 404 /opnsense_error_404.html;
|
||||
error_page 500 501 502 503 504 /opnsense_server_error.html;
|
||||
# location to ban the host permanently
|
||||
set $naxsi_extensive_log {% if server.naxsi_extensive_log is defined and server.naxsi_extensive_log == '1' %}1{% else %}0{% endif %};
|
||||
location @permanentban {
|
||||
access_log /var/log/nginx/permanentban.access.log main;
|
||||
internal;
|
||||
add_header Content-Type text/plain;
|
||||
add_header Charset utf-8;
|
||||
return 403 "You got banned permanently from this server.";
|
||||
}
|
||||
error_page 418 = @permanentban;
|
||||
location /opnsense_server_error.html {
|
||||
internal;
|
||||
root /usr/local/etc/nginx/views;
|
||||
}
|
||||
location /opnsense_error_404.html {
|
||||
internal;
|
||||
root /usr/local/etc/nginx/views;
|
||||
}
|
||||
location /waf_denied.html {
|
||||
root /usr/local/etc/nginx/views;
|
||||
access_log /var/log/nginx/waf_denied.access.log main;
|
||||
}
|
||||
{% if server.enable_acme_support is defined and server.enable_acme_support == '1' %}
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
default_type "text/plain";
|
||||
root /var/etc/acme-client/challenges;
|
||||
}
|
||||
{% endif %}
|
||||
# block based on User Agents - stuff I have found over the years in my server log
|
||||
if ($http_user_agent ~* Python-urllib|Nmap|python-requests|libwww-perl|MJ12bot|Jorgee|fasthttp|libwww|Telesphoreo|A6-Indexer|ltx71|okhttp|ZmEu) {
|
||||
return 418;
|
||||
}
|
||||
if ($http_user_agent ~ "Indy\sLibrary|Morfeus Fucking Scanner")
|
||||
{
|
||||
return 418;
|
||||
}
|
||||
location /opnsense-auth-request {
|
||||
internal;
|
||||
fastcgi_pass unix:/var/run/php-webgui.socket;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param TLS-Cipher $ssl_cipher;
|
||||
fastcgi_param TLS-Protocol $ssl_protocol;
|
||||
fastcgi_param TLS-SNI-Host $ssl_server_name;
|
||||
fastcgi_param Original-URI $request_uri;
|
||||
fastcgi_param Original-HOST $host;
|
||||
{% if helpers._template_in_data['__uuid__'] is defined %}
|
||||
{% for uuid in helpers._template_in_data['__uuid__'] %}
|
||||
{% if helpers._template_in_data['__uuid__'][uuid] == server %}
|
||||
fastcgi_param SERVER-UUID "{{ uuid }}";
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
fastcgi_param SCRIPT_FILENAME /usr/local/opnsense/scripts/nginx/ngx_auth.php;
|
||||
fastcgi_intercept_errors on;
|
||||
include fastcgi_params;
|
||||
}
|
||||
{% if server.block_nonpublic_data is defined and server.block_nonpublic_data == '1' %}
|
||||
# apache htpasswd and htaccess
|
||||
location ~ /\.ht {
|
||||
return 403;
|
||||
}
|
||||
# those files may expose file system stuff
|
||||
location ~ \.DS_Store$ {
|
||||
return 403;
|
||||
}
|
||||
{% endif %}
|
||||
{% if server.https_only is defined and server.https_only == '1' %}
|
||||
if ($scheme != "https") {
|
||||
return 302 https://$host$request_uri;
|
||||
}
|
||||
{% endif %}
|
||||
{% if server.rewrites is defined %}
|
||||
{% for rewrite_uuid in server.rewrites.split(',') %}
|
||||
{% set rewrite = helpers.getUUID(rewrite_uuid) %}
|
||||
rewrite {{ rewrite.source }} {{ rewrite.destination }}{% if rewrite.flag is defined%} {{ rewrite.flag }}{% endif %};
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if server.locations is defined %}
|
||||
{% for location_uuid in server.locations.split(',') %}
|
||||
{% set location = helpers.getUUID(location_uuid) %}
|
||||
{% include "OPNsense/Nginx/location.conf" ignore missing with context %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
location {{ location.matchtype }} {{ location.urlpattern }} {
|
||||
{% if location.enable_secrules is defined and location.enable_secrules == '1' %}
|
||||
SecRulesEnabled;
|
||||
{% endif %}
|
||||
{% if location.enable_learning_mode is defined and location.enable_learning_mode == '1' %}
|
||||
LearningMode;
|
||||
{% endif %}
|
||||
{% if location.xss_block_score is defined %}
|
||||
LibInjectionXss;
|
||||
CheckRule "$LIBINJECTION_XSS >= {{ location.xss_block_score }}" BLOCK;
|
||||
{% endif %}
|
||||
{% set added_policies = [] %}
|
||||
{% if location.custom_policy is defined %}
|
||||
{% for custom_policy_uuid in location.custom_policy.split(',') %}
|
||||
{% set custom_policy = helpers.getUUID(custom_policy_uuid) %}
|
||||
{% set naxsi_ruletype = 'basic' %}
|
||||
{% include "OPNsense/Nginx/naxsirule.conf" ignore missing with context %}
|
||||
CheckRule "$policy{{ custom_policy_uuid.replace('-', '') }} {{ custom_policy.operator }} {{ custom_policy.value
|
||||
}}" {{ custom_policy.action }};
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if location.rewrites is defined %}
|
||||
{% for rewrite_uuid in location.rewrites.split(',') %}
|
||||
{% set rewrite = helpers.getUUID(rewrite_uuid) %}
|
||||
rewrite {{ rewrite.source }} {{ rewrite.destination }}{% if rewrite.flag is defined%} {{ rewrite.flag }}{% endif %};
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if location.sqli_block_score is defined %}
|
||||
LibInjectionSql;
|
||||
CheckRule "$LIBINJECTION_SQL >= {{ location.sqli_block_score }}" BLOCK;
|
||||
{% endif %}
|
||||
DeniedUrl "/waf_denied.html";
|
||||
{% if location.force_https is defined and location.force_https == '1' %}
|
||||
if ($scheme != "https") {
|
||||
return 302 https://$host$request_uri;
|
||||
}
|
||||
{% endif %}
|
||||
{% if location.root is defined %}
|
||||
root {{ location.root }};
|
||||
{% endif %}
|
||||
{% if location.index is defined %}
|
||||
index {{ location.index.replace(",", " ") }};
|
||||
{% endif %}
|
||||
{% if location.autoindex is defined and location.autoindex == '1' %}
|
||||
autoindex on;
|
||||
{% else %}
|
||||
autoindex off;
|
||||
{% endif %}
|
||||
{% if location.authbasic is defined and location.authbasicuserfile is defined %}
|
||||
auth_basic "{{location.authbasic}}";
|
||||
auth_basic_user_file /var/db/nginx/auth/{{ location.authbasicuserfile }};
|
||||
{% else %}
|
||||
{% if location.advanced_acl is defined and location.advanced_acl == '1' %}
|
||||
auth_request /opnsense-auth-request;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if location.upstream is defined %}
|
||||
proxy_pass http://upstream{{ location.upstream.replace('-','') }};
|
||||
{% endif %}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
application/font-woff woff;
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
application/gzip gz;
|
||||
application/xz xz;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg oga;
|
||||
audio/opus opus
|
||||
audio/speex spx;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
audio/flac flac;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/ogg ogv;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
{% macro naxsi_mzhelper(mz_helper_rule) -%}
|
||||
{% set mz_matches = [] %}
|
||||
{% set rx_suffix = '' %}
|
||||
{% if mz_helper_rule.regex is defined and mz_helper_rule.regex == '1' %}
|
||||
{% set rx_suffix = '_X' %}
|
||||
{% endif %}
|
||||
{% if mz_helper_rule.args == '1' %}
|
||||
{% do mz_matches.append('ARGS') %}
|
||||
{% endif %}
|
||||
{% if mz_helper_rule.headers == '1' %}
|
||||
{% do mz_matches.append('HEADERS') %}
|
||||
{% endif %}
|
||||
{% if mz_helper_rule.name == '1' %}
|
||||
{% if mz_matches|length > 0 %}
|
||||
{% do mz_matches.append('NAME') %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if mz_helper_rule.raw_body == '1' %}
|
||||
{% do mz_matches.append('RAW_BODY') %}
|
||||
{% endif %}
|
||||
{% if mz_helper_rule.file_extension == '1' %}
|
||||
{% do mz_matches.append('FILE_EXT') %}
|
||||
{% endif %}
|
||||
{% if mz_helper_rule.dollar_body_var is defined and mz_helper_rule.dollar_body_var != '' %}
|
||||
{% do mz_matches.append('$BODY_VAR' + rx_suffix + ':' + mz_helper_rule.dollar_body_var) %}
|
||||
{% endif %}
|
||||
{% if mz_helper_rule.dollar_args_var is defined and mz_helper_rule.dollar_args_var != '' %}
|
||||
{# in case of regex, we cannot use args_var -> https://github.com/nbs-system/naxsi/wiki/matchzones-bnf#match-zone #}
|
||||
{% if mz_helper_rule.url is defined and mz_helper_rule.url != '' %}
|
||||
{% do mz_matches.append('$ARGS_VAR' + rx_suffix + ':' + mz_helper_rule.dollar_args_var) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if mz_helper_rule.dollar_headers_var is defined and mz_helper_rule.dollar_headers_var != '' %}
|
||||
{% do mz_matches.append('$HEADERS_VAR' + rx_suffix +':' + mz_helper_rule.dollar_headers_var) %}
|
||||
{% endif %}
|
||||
{% if mz_helper_rule.dollar_url is defined and mz_helper_rule.dollar_url != '' %}
|
||||
{% do mz_matches.insert(0,'$URL' + rx_suffix +':' + mz_helper_rule.dollar_url) %}
|
||||
{% endif %}
|
||||
{{ mz_matches|join('|') }}
|
||||
{%- endmacro %}
|
||||
{% macro naxsi_rule(uuid, rule, ruletype) -%}
|
||||
{{ ruletype }}{% if rule.negate is defined and rule.negate == '1' %} negative{% endif
|
||||
%} {{ rule.match_type }}:{{ rule.identifier }} "{% if rule.regex == '1' %}rx{% else %}str{% endif
|
||||
%}:{{ rule.match_value }}" "msg:{{ rule.message }}" "mz:{{ naxsi_mzhelper(rule)
|
||||
}}" "s:$policy{{ uuid.replace('-', '') }}:{{ rule.score }}";
|
||||
{%- endmacro %}
|
||||
|
||||
{% if naxsi_ruletype == 'basic' %}
|
||||
{# current policy in loop is available as custom_policy, the uuid as custom_policy_uuid #}
|
||||
{% for naxsi_rule_uuid in custom_policy.naxsi_rules.split(',') %}
|
||||
{% if naxsi_rule_uuid not in added_policies %}
|
||||
{% set basic_rule = helpers.getUUID(naxsi_rule_uuid) %}
|
||||
{% if basic_rule.ruletype == 'basic' %}
|
||||
{{ naxsi_rule(custom_policy_uuid, basic_rule, "BasicRule") }}
|
||||
{% do added_policies.append(naxsi_rule_uuid) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if naxsi_ruletype == 'main' %}
|
||||
{{ naxsi_rule(custom_policy_uuid, main_rule, "MainRule") }}
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
nginx_enable="YES"
|
||||
nginx_var_script="/usr/local/opnsense/scripts/nginx/setup.php"
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
{# load naxsi WAF module #}
|
||||
load_module /usr/local/libexec/nginx/ngx_stream_module.so;
|
||||
load_module /usr/local/libexec/nginx/ngx_http_naxsi_module.so;
|
||||
load_module /usr/local/libexec/nginx/ngx_mail_module.so;
|
||||
load_module /usr/local/libexec/nginx/ngx_http_brotli_filter_module.so;
|
||||
load_module /usr/local/libexec/nginx/ngx_http_brotli_static_module.so;
|
||||
|
||||
# TODO enable root when running the web interface
|
||||
#user root wheel;
|
||||
worker_processes 1;
|
||||
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
{% if helpers.exists('OPNsense.Nginx') %}
|
||||
{# include http blocks partial #}
|
||||
{% include "OPNsense/Nginx/http.conf" ignore missing with context %}
|
||||
{% endif %}
|
||||
}
|
||||
{% if helpers.exists('OPNsense.Nginx') %}
|
||||
# mail {
|
||||
{# include http blocks partial #}
|
||||
{% include "OPNsense/Nginx/mail.conf" ignore missing with context %}
|
||||
# }
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{% raw %}
|
||||
[webgui]
|
||||
user = root
|
||||
group = wheel
|
||||
listen = /var/run/php-webgui.socket
|
||||
listen.owner = root
|
||||
listen.group = wheel
|
||||
listen.mode = 0660
|
||||
pm = dynamic
|
||||
pm.max_children = 5
|
||||
pm.start_servers = 2
|
||||
pm.min_spare_servers = 1
|
||||
pm.max_spare_servers = 3
|
||||
php_admin_value[error_log] = /var/log/fpm-php.www.log
|
||||
php_admin_flag[log_errors] = on
|
||||
{% endraw %}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{% raw %}
|
||||
[www]
|
||||
user = www
|
||||
group = www
|
||||
listen = /var/run/php-www.socket
|
||||
pm = dynamic
|
||||
pm.max_children = 5
|
||||
pm.start_servers = 2
|
||||
pm.min_spare_servers = 1
|
||||
pm.max_spare_servers = 3
|
||||
{% endraw %}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
php_fpm_enable="YES"
|
||||
command_args="-R"
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
{% set naxsi_ruletype = 'main' %}
|
||||
{% set main_policies = [] %}
|
||||
{% set main_rules = [] %}
|
||||
{# collect custom policy UUIDs from locations so we know, which ones are probably in use #}
|
||||
{% if OPNsense.Nginx.location is defined %}
|
||||
{% for location in helpers.toList('OPNsense.Nginx.location') %}
|
||||
{% if location.custom_policy is defined and location.custom_policy != ""%}
|
||||
{% for custompolicy_uuid in location.custom_policy.split(',') %}
|
||||
{% if not custompolicy_uuid in main_policies %}
|
||||
{% do main_policies.append(custompolicy_uuid) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for custom_policy_uuid in main_policies %}
|
||||
{% set custom_policy = helpers.getUUID(custom_policy_uuid) %}
|
||||
{% if custom_policy.naxsi_rules is defined %}
|
||||
{% for main_rule_uuid in custom_policy.naxsi_rules.split(',') %}
|
||||
{% if main_rule_uuid not in main_rules %}
|
||||
{% do main_rules.append(main_rule_uuid) %}
|
||||
{% set main_rule = helpers.getUUID(main_rule_uuid) %}
|
||||
{% if main_rule.ruletype == 'main' %}
|
||||
{% include "OPNsense/Nginx/naxsirule.conf" ignore missing with context %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# UPSTREAM SERVERS
|
||||
{% set upstreamlist = {} %}
|
||||
{% for location in helpers.toList('OPNsense.Nginx.location') %}
|
||||
{% if location.upstream is defined %}
|
||||
{% do upstreamlist.update({location.upstream: helpers.getUUID(location.upstream)}) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for upstream_uuid, upstream in upstreamlist.items() %}
|
||||
{% for upstream_serveruuid in upstream.serverentries.split(',') %}
|
||||
upstream upstream{{ upstream_uuid.replace('-','') }} {
|
||||
{% set upstream_server = helpers.getUUID(upstream_serveruuid) %}
|
||||
server {% if ':' in upstream_server.server %}[{% endif %}{{ upstream_server.server }}{% if ':' in upstream_server.server %}]{% endif
|
||||
%}{% if upstream_server.port is defined %}:{{ upstream_server.port }}{% endif
|
||||
%}{% if upstream_server.priority is defined %} weight={{ upstream_server.priority }}{% endif
|
||||
%}{% if upstream_server.max_conns is defined %} max_conns={{ upstream_server.max_conns }}{% endif
|
||||
%}{% if upstream_server.max_fails is defined %} max_fails={{ upstream_server.max_fails }}{% endif
|
||||
%}{% if upstream_server.fail_timeout is defined %} fail_timeout={{ upstream_server.fail_timeout }}{% endif
|
||||
%}{% if upstream_server.no_use is defined %} {{ upstream_server.no_use }}{% endif %};
|
||||
{% endfor %}
|
||||
|
||||
}
|
||||
{% endfor %}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
server {
|
||||
|
||||
keepalive_requests 15;
|
||||
keepalive_timeout 30;
|
||||
|
||||
root /usr/local/www/;
|
||||
{% if system.webgui.protocol is defined and system.webgui.protocol == 'https' %}
|
||||
if ($scheme != "https") {
|
||||
return 302 https://$host$request_uri;
|
||||
}
|
||||
listen 80 default_server; # if redirect is enabled
|
||||
listen {% if system.webgui.port is defined and system.webgui.port != '' %}{{ system.webgui.port }}{% else %}443{% endif %} ssl http2 default_server;
|
||||
## TLS configuration
|
||||
ssl_dhparam /usr/local/etc/dh-parameters.4096;
|
||||
ssl_ecdh_curve secp384r1;
|
||||
ssl_certificate /var/etc/cert.pem;
|
||||
ssl_certificate_key /var/etc/cert.pem;
|
||||
ssl_client_certificate /var/etc/ca.pem;
|
||||
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
{% if system.webgui['ssl-ciphers'] is defined and system.webgui['ssl-ciphers'] != '' %}
|
||||
ssl_ciphers {{ system.webgui['ssl-ciphers'] }}
|
||||
{% else %}
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;
|
||||
{% endif %}
|
||||
{% else %}
|
||||
listen {% if system.webgui.port is defined and system.webgui.port != '' %}{{ system.webgui.port }}{% else %}80{% endif %};
|
||||
{% endif %}
|
||||
|
||||
autoindex off;
|
||||
|
||||
# gzip compression
|
||||
gzip_static on;
|
||||
{% if system.webgui.compression is defined and system.webgui.compression != '' %}
|
||||
gzip on;
|
||||
gzip_comp_level {{ system.webgui.compression }};
|
||||
{% else %}
|
||||
gzip off;
|
||||
{% endif %}
|
||||
#compress.cache-dir = "/tmp/lighttpdcompress/"
|
||||
gzip_types text/plain text/css text/xml text/javascript;
|
||||
|
||||
#server.upload-dirs = ( "/root/", "/tmp/", "/var/" )
|
||||
# server.max-request-size = 2097152
|
||||
|
||||
expires 50h;
|
||||
|
||||
# Maximum idle time with nothing being written (php downloading)
|
||||
#fastcgi_read_timeout = 999
|
||||
|
||||
## where to send error/access-messages to
|
||||
access_log syslog:server=127.0.0.1,facility=daemon;
|
||||
access_log /var/log/nginx/webgui.access.log;
|
||||
error_log syslog:server=127.0.0.1,facility=daemon;
|
||||
error_log /var/log/nginx/webgui.error.log debug;
|
||||
|
||||
index index.php index.html index.htm default.htm;
|
||||
|
||||
# mimetype mapping
|
||||
types {
|
||||
application/x-ns-proxy-autoconfig pad.dat;
|
||||
application/pdf pdf;
|
||||
application/pgp-signature sig;
|
||||
application/futuresplash spl;
|
||||
application/octet-stream class;
|
||||
application/postscript ps;
|
||||
application/x-bittorrent torrent;
|
||||
application/x-dvi dvi;
|
||||
application/x-gzip gz;
|
||||
application/x-ns-proxy-autoconfig pac;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-tgz tar.gz tgz;
|
||||
application/x-tar tar;
|
||||
application/zip zip;
|
||||
audio/mpeg mp3;
|
||||
audio/x-mpegurl m3u;
|
||||
audio/x-ms-wma wma;
|
||||
audio/x-ms-wax wax;
|
||||
audio/x-wav ogg;
|
||||
audio/x-wav wav;
|
||||
image/gif gif;
|
||||
image/jpeg jpg jpeg;
|
||||
image/png png;
|
||||
image/svg+xml svg;
|
||||
image/x-xbitmap xbm;
|
||||
image/x-xpixmap xpm;
|
||||
image/x-xwindowdump xwd;
|
||||
text/css css;
|
||||
text/html html htm;
|
||||
text/javascript js;
|
||||
text/plain asc;
|
||||
text/plain c;
|
||||
text/plain conf;
|
||||
text/plain text txt;
|
||||
text/xml dtd;
|
||||
text/xml xml;
|
||||
video/mpeg mpeg;
|
||||
video/mpeg mpg;
|
||||
video/quicktime mov qt;
|
||||
video/x-msvideo avi;
|
||||
video/x-ms-asf asf asx;
|
||||
video/x-ms-wmv wmv;
|
||||
application/x-bzip bz2;
|
||||
application/x-bzip-compressed-tar tbz tar.bz2;
|
||||
}
|
||||
|
||||
# Use the "Content-Type" extended attribute to obtain mime type if possible
|
||||
#mimetypes.use-xattr = "enable"
|
||||
|
||||
## deny access the file-extensions
|
||||
#
|
||||
# ~ is for backupfiles from vi, emacs, joe, ...
|
||||
# .inc is often used for code includes which should in general not be part
|
||||
# of the document-root
|
||||
location ~* "(~|.inc)$" {
|
||||
return 403;
|
||||
}
|
||||
|
||||
{% if helpers.exists('OPNsense.Nginx.webgui.limitnetworks') and OPNsense.Nginx.webgui.limitnetworks == '1' %}
|
||||
# whitelist only directly connected networks to prevent attacks over the internet to the web interface
|
||||
# we cannot block everything except RFC 1918 because this does not work with IPv6
|
||||
{% set whitelisted_networks = [] %}
|
||||
{% for interface_name in interfaces %}
|
||||
{% set interface = interfaces[interface_name] %}
|
||||
{% if interface.ipaddr is defined and interface.ipaddr != '' and '.' in interface.ipaddr %}
|
||||
{% if interface.subnet is defined and interface.subnet != '' %}
|
||||
{% set cidr = interface.ipaddr + '/' + interface.subnet %}
|
||||
{% else %}
|
||||
{% set cidr = interface.ipaddr %}
|
||||
{% endif %}
|
||||
{% if cidr not in whitelisted_networks %}
|
||||
{% do whitelisted_networks.append(cidr) %}
|
||||
allow {{ cidr }};
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if interface.ipaddrv6 is defined and interface.ipaddrv6 != '' and ':' in interface.ipaddrv6 %}
|
||||
{% if interface.subnetv6 is defined and interface.subnetv6 != '' %}
|
||||
{% set cidr = interface.ipaddrv6 + '/' + interface.subnetv6 %}
|
||||
{% else %}
|
||||
{% set cidr = interface.ipaddrv6 %}
|
||||
{% endif %}
|
||||
{% if cidr not in whitelisted_networks %}
|
||||
{% do whitelisted_networks.append(cidr) %}
|
||||
allow {{ cidr }};
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if helpers.exists('virtualip') %}
|
||||
{% for intf_item in helpers.toList('virtualip.vip') %}
|
||||
{% if intf_item.type == 'single' %}
|
||||
{% set cidr = intf_item.subnet + '/' + intf_item.subnet_bits %}
|
||||
{% if cidr not in whitelisted_networks %}
|
||||
allow {{ cidr }};
|
||||
{% do whitelisted_networks.append(cidr) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
deny all;
|
||||
{% endif %}
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass unix:/var/run/php-webgui.socket;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param TLS-Cipher $ssl_cipher;
|
||||
fastcgi_param TLS-Protocol $ssl_protocol;
|
||||
fastcgi_param TLS-SNI-Host $ssl_server_name;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_intercept_errors on;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# Phalcon ui and api routing
|
||||
|
||||
location @apirequest {
|
||||
root /usr/local/opnsense/www;
|
||||
include fastcgi_params;
|
||||
fastcgi_param QUERY_STRING &$query_string;
|
||||
fastcgi_param SCRIPT_FILENAME /usr/local/opnsense/www/api.php;
|
||||
fastcgi_param TLS-Cipher $ssl_cipher;
|
||||
fastcgi_param TLS-Protocol $ssl_protocol;
|
||||
fastcgi_param TLS-SNI-Host $ssl_server_name;
|
||||
fastcgi_intercept_errors off;
|
||||
fastcgi_pass unix:/var/run/php-webgui.socket;
|
||||
}
|
||||
location @guirequest {
|
||||
root /usr/local/opnsense/www;
|
||||
include fastcgi_params;
|
||||
fastcgi_param QUERY_STRING $query_string;
|
||||
fastcgi_param SCRIPT_FILENAME /usr/local/opnsense/www/index.php;
|
||||
fastcgi_param TLS-Cipher $ssl_cipher;
|
||||
fastcgi_param TLS-Protocol $ssl_protocol;
|
||||
fastcgi_param TLS-SNI-Host $ssl_server_name;
|
||||
fastcgi_intercept_errors off;
|
||||
fastcgi_pass unix:/var/run/php-webgui.socket;
|
||||
}
|
||||
location ~ ^/ui/(?<path>[^\?]+)(?<query>\?(.*))? {
|
||||
root /usr/local/opnsense/www;
|
||||
try_files /$path @guirequest;
|
||||
}
|
||||
location ~ ^/api/(?<path>[^\?]+)(?<query>\?(.*))?{
|
||||
root /usr/local/opnsense/www;
|
||||
try_files /$path @apirequest;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue