38 Commits

Author SHA1 Message Date
bunkerity
07be626842 hotfix - fix API in autoconf swarm mode 2021-04-28 17:40:54 +02:00
bunkerity
3bb164395e hotfix - move API_WHITELIST_IP edit to lua.sh 2021-04-28 17:00:50 +02:00
bunkerity
bc2568a172 v1.2.4 - nginx 1.20.0 support 2021-04-27 17:43:38 +02:00
Bunkerity
5ec74880d8 update README for v1.2.4 2021-04-27 17:40:33 +02:00
bunkerity
f84fd7c9a2 fix permissions issues for autoconf and fix volume for ghost example 2021-04-27 16:49:45 +02:00
bunkerity
6521d7a27a fix client cache so it works in combination with reverse proxy and examples update 2021-04-27 15:31:56 +02:00
bunkerity
813607fbc3 improve crowdsec example and disable modsec logging when not necessary 2021-04-27 11:21:30 +02:00
bunkerity
843644f806 log - replace some WARN tags from LUA logs with NOTICE to avoid confusion 2021-04-27 09:57:07 +02:00
bunkerity
19fa0eb25f log - print modsec_audit.log to make debugging easier 2021-04-27 09:46:40 +02:00
bunkerity
b4df287228 log - send logs to remote syslog server 2021-04-27 09:30:10 +02:00
florian
5ce41edc03 api - whitelist IP/network for API 2021-04-26 22:22:34 +02:00
florian
a3cfb50b4d example - fix certbot wildcard 2021-04-26 21:34:18 +02:00
bunkerity
25494acace example - wildcard certificate with certbot 2021-04-26 17:44:48 +02:00
bunkerity
a98dae1fb6 fix CVE-2021-20205 and examples update 2021-04-26 17:00:23 +02:00
bunkerity
1a7abab570 nginx 1.20.0 support 2021-04-26 14:59:12 +02:00
florian
42b7a57f01 fix autoconf bug when removing config with multiple server name and increase default LIMIT_CONN_MAX for average website with HTTP2 2021-04-26 11:39:12 +02:00
bunkerity
02f9fbe5fc autoconf - fix certbot bug when multiple server_name for one service 2021-04-20 11:46:53 +02:00
bunkerity
69fe066777 autoconf - fix bug when multiple server_name for one service 2021-04-20 10:00:25 +02:00
bunkerity
74417abc9c fixing bugs - run as GID 101 instead of 0, different permissions checks in swarm mode and disable including server confs in swarm mode 2021-04-16 16:56:45 +02:00
bunkerity
ba7524a419 fixed LUA bug 2021-04-13 17:27:52 +02:00
bunkerity
b55aafb997 finding the LUA bug 2021-04-13 17:01:27 +02:00
Bunkerity
deeb7a76a2 Merge pull request #117 from thelittlefireman/patch-9
Fix lua mistake
2021-04-13 16:49:45 +02:00
thelittlefireman
ee8aaa4e7e fix lua crash 2 2021-04-11 15:45:46 +02:00
thelittlefireman
605d59a45c Fix lua mistake
#116
2021-04-11 15:33:31 +02:00
bunkerity
b85c991b6e bug fixes - /usr/local/lib/lua rights and syntax error in site-config 2021-04-09 17:40:19 +02:00
bunkerity
0d3658adf0 REVERSE_PROXY_HEADERS - use proxy_set_header instead of more_set_headers 2021-04-09 17:27:22 +02:00
bunkerity
0b22209c96 documentation - userns remap feature 2021-04-09 16:22:31 +02:00
bunkerity
e44a1f3e14 added the uri to limit_req_zone key to limit bruteforce attack on a specific resource instead of the whole service 2021-04-09 15:54:26 +02:00
bunkerity
aa614f82f9 print error when permissions are wrong on common volumes 2021-04-09 14:54:15 +02:00
bunkerity
c03d410b0a refactored whitelisting of user-agents 2021-04-09 14:23:52 +02:00
bunkerity
e190167bfc CIDR support with whitelist/blacklist IP 2021-04-09 14:10:17 +02:00
bunkerity
31e72dce1c fix /usr/local/lib/lua rights and multiple server_name support with autoconf 2021-04-09 11:37:13 +02:00
bunkerity
b8105fc558 feature - whitelist URI 2021-04-09 10:31:00 +02:00
bunkerity
e73c10fd80 crowdsec - fix permissions on /usr/local/lib/lua and on /var/log files 2021-04-09 10:01:23 +02:00
bunkerity
a122a259c0 minor fix on AutoConf logs and auto disable etag with reverse proxy 2021-04-09 09:51:17 +02:00
bunkerity
7c4894d3b8 autoconf - fix remove event, generate config from nginx vars, more logs 2021-03-26 15:18:35 +01:00
bunkerity
533c2a1034 fix sed script when writing site env 2021-03-22 09:38:36 +01:00
bunkerity
5611d544d6 remove reference to USE_PHP 2021-03-19 09:38:44 +01:00
78 changed files with 747 additions and 230 deletions

View File

@@ -1,4 +1,4 @@
FROM nginx:stable-alpine FROM nginx:1.20.0-alpine
COPY nginx-keys/ /tmp/nginx-keys COPY nginx-keys/ /tmp/nginx-keys
COPY compile.sh /tmp/compile.sh COPY compile.sh /tmp/compile.sh
@@ -16,10 +16,13 @@ COPY lua/ /opt/lua
COPY prepare.sh /tmp/prepare.sh COPY prepare.sh /tmp/prepare.sh
RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh
# fix CVE-2021-20205
RUN apk add "libjpeg-turbo>=2.1.0-r0"
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge
EXPOSE 8080/tcp 8443/tcp EXPOSE 8080/tcp 8443/tcp
USER nginx USER nginx:nginx
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"] ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]

View File

@@ -1,4 +1,4 @@
FROM amd64/nginx:stable-alpine FROM amd64/nginx:1.20.0-alpine
COPY nginx-keys/ /tmp/nginx-keys COPY nginx-keys/ /tmp/nginx-keys
COPY compile.sh /tmp/compile.sh COPY compile.sh /tmp/compile.sh
@@ -16,10 +16,13 @@ COPY lua/ /opt/lua
COPY prepare.sh /tmp/prepare.sh COPY prepare.sh /tmp/prepare.sh
RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh
# fix CVE-2021-20205
RUN apk add "libjpeg-turbo>=2.1.0-r0"
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge
EXPOSE 8080/tcp 8443/tcp EXPOSE 8080/tcp 8443/tcp
USER nginx USER nginx:nginx
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"] ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]

View File

@@ -3,7 +3,7 @@ FROM alpine AS builder
ENV QEMU_URL https://github.com/balena-io/qemu/releases/download/v4.0.0%2Bbalena2/qemu-4.0.0.balena2-arm.tar.gz ENV QEMU_URL https://github.com/balena-io/qemu/releases/download/v4.0.0%2Bbalena2/qemu-4.0.0.balena2-arm.tar.gz
RUN apk add curl && curl -L ${QEMU_URL} | tar zxvf - -C . --strip-components 1 RUN apk add curl && curl -L ${QEMU_URL} | tar zxvf - -C . --strip-components 1
FROM arm32v7/nginx:stable-alpine FROM arm32v7/nginx:1.20.0-alpine
COPY --from=builder qemu-arm-static /usr/bin COPY --from=builder qemu-arm-static /usr/bin
@@ -23,10 +23,13 @@ COPY lua/ /opt/lua
COPY prepare.sh /tmp/prepare.sh COPY prepare.sh /tmp/prepare.sh
RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh
# fix CVE-2021-20205
RUN apk add "libjpeg-turbo>=2.1.0-r0"
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge
EXPOSE 8080/tcp 8443/tcp EXPOSE 8080/tcp 8443/tcp
USER nginx USER nginx:nginx
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"] ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]

View File

@@ -3,7 +3,7 @@ FROM alpine AS builder
ENV QEMU_URL https://github.com/balena-io/qemu/releases/download/v4.0.0%2Bbalena2/qemu-4.0.0.balena2-aarch64.tar.gz ENV QEMU_URL https://github.com/balena-io/qemu/releases/download/v4.0.0%2Bbalena2/qemu-4.0.0.balena2-aarch64.tar.gz
RUN apk add curl && curl -L ${QEMU_URL} | tar zxvf - -C . --strip-components 1 RUN apk add curl && curl -L ${QEMU_URL} | tar zxvf - -C . --strip-components 1
FROM arm64v8/nginx:stable-alpine FROM arm64v8/nginx:1.20.0-alpine
COPY --from=builder qemu-aarch64-static /usr/bin COPY --from=builder qemu-aarch64-static /usr/bin
@@ -23,10 +23,13 @@ COPY lua/ /opt/lua
COPY prepare.sh /tmp/prepare.sh COPY prepare.sh /tmp/prepare.sh
RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh
# fix CVE-2021-20205
RUN apk add "libjpeg-turbo>=2.1.0-r0"
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge
EXPOSE 8080/tcp 8443/tcp EXPOSE 8080/tcp 8443/tcp
USER nginx USER nginx:nginx
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"] ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]

View File

@@ -1,4 +1,4 @@
FROM i386/nginx:stable-alpine FROM i386/nginx:1.20.0-alpine
COPY nginx-keys/ /tmp/nginx-keys COPY nginx-keys/ /tmp/nginx-keys
COPY compile.sh /tmp/compile.sh COPY compile.sh /tmp/compile.sh
@@ -16,10 +16,13 @@ COPY lua/ /opt/lua
COPY prepare.sh /tmp/prepare.sh COPY prepare.sh /tmp/prepare.sh
RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh
# fix CVE-2021-20205
RUN apk add "libjpeg-turbo>=2.1.0-r0"
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge
EXPOSE 8080/tcp 8443/tcp EXPOSE 8080/tcp 8443/tcp
USER nginx USER nginx:nginx
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"] ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]

View File

@@ -3,12 +3,16 @@
</p> </p>
<p align="center"> <p align="center">
<img src="https://img.shields.io/badge/bunkerized--nginx-1.2.3-blue" /> <img src="https://img.shields.io/badge/bunkerized--nginx-1.2.4-blue" />
<img src="https://img.shields.io/badge/nginx-1.18.0-blue" /> <img src="https://img.shields.io/badge/nginx-1.20.0-blue" />
<img src="https://img.shields.io/github/last-commit/bunkerity/bunkerized-nginx" /> <img src="https://img.shields.io/github/last-commit/bunkerity/bunkerized-nginx" />
<a href="https://matrix.to/#/#bunkerized-nginx:matrix.org"><img src="https://img.shields.io/badge/matrix%20chat-%23bunkerized--nginx%3Amatrix.org-blue" /></a>
<img src="https://img.shields.io/github/workflow/status/bunkerity/bunkerized-nginx/Automatic%20test?label=automatic%20test" /> <img src="https://img.shields.io/github/workflow/status/bunkerity/bunkerized-nginx/Automatic%20test?label=automatic%20test" />
<img src="https://img.shields.io/docker/cloud/build/bunkerity/bunkerized-nginx" /> <img src="https://img.shields.io/docker/cloud/build/bunkerity/bunkerized-nginx" />
</p>
<p align="center">
<a href="https://matrix.to/#/#bunkerized-nginx:matrix.org"><img src="https://img.shields.io/badge/matrix%20chat-%23bunkerized--nginx%3Amatrix.org-blue" /></a>
<a href="https://www.bunkerity.com"><img src="https://img.shields.io/badge/website-www.bunkerity.com-blue" /></a>
<a href="https://twitter.com/bunkerity"><img src="https://img.shields.io/twitter/follow/bunkerity?style=social" /></a> <a href="https://twitter.com/bunkerity"><img src="https://img.shields.io/twitter/follow/bunkerity?style=social" /></a>
</p> </p>
@@ -34,9 +38,13 @@ Fooling automated tools/scanners :
<img src="https://github.com/bunkerity/bunkerized-nginx/blob/master/demo.gif?raw=true" /> <img src="https://github.com/bunkerity/bunkerized-nginx/blob/master/demo.gif?raw=true" />
You can find a live demo at https://demo-nginx.bunkerity.com, feel free to do some security tests.
# Table of contents # Table of contents
<details>
<summary>Click to show</summary>
- [Table of contents](#table-of-contents) - [Table of contents](#table-of-contents)
- [Live demo](#live-demo)
- [Quickstart guide](#quickstart-guide) - [Quickstart guide](#quickstart-guide)
* [Run HTTP server with default settings](#run-http-server-with-default-settings) * [Run HTTP server with default settings](#run-http-server-with-default-settings)
* [In combination with PHP](#in-combination-with-php) * [In combination with PHP](#in-combination-with-php)
@@ -85,9 +93,7 @@ Fooling automated tools/scanners :
* [Logrotate](#logrotate) * [Logrotate](#logrotate)
* [Cron jobs](#cron-jobs) * [Cron jobs](#cron-jobs)
* [Misc](#misc-2) * [Misc](#misc-2)
</details>
# Live demo
You can find a live demo at https://demo-nginx.bunkerity.com.
# Quickstart guide # Quickstart guide
@@ -440,15 +446,32 @@ When `USE_ANTIBOT` is set to *captcha*, every users visiting your website must c
## Hardening ## Hardening
### Drop capabilities
By default, *bunkerized-nginx* runs as non-root user inside the container and should not use any of the default [capabilities](https://docs.docker.com/engine/security/#linux-kernel-capabilities) allowed by Docker. You can safely remove all capabilities to harden the container : By default, *bunkerized-nginx* runs as non-root user inside the container and should not use any of the default [capabilities](https://docs.docker.com/engine/security/#linux-kernel-capabilities) allowed by Docker. You can safely remove all capabilities to harden the container :
```shell ```shell
docker run ... --drop-cap=all ... bunkerity/bunkerized-nginx docker run ... --drop-cap=all ... bunkerity/bunkerized-nginx
``` ```
### User namespace remap
Another hardening trick is [user namespace remapping](https://docs.docker.com/engine/security/userns-remap/) : it allows you to map the UID/GID of users inside a container to another UID/GID on the host. For example, you can map the user nginx with UID/GID 101 inside the container to a non-existent user with UID/GID 100101 on the host.
Let's assume you have the /etc/subuid and /etc/subgid files like this :
```
user:100000:65536
```
It means that everything done inside the container will be remapped to UID/GID 100101 (100000 + 101) on the host.
Please note that you must set the rights on the volumes (e.g. : /etc/letsencrypt, /www, ...) according to the remapped UID/GID :
```shell
$ chown root:100101 /path/to/letsencrypt
$ chmod 770 /path/to/letsencrypt
$ docker run ... -v /path/to/letsencrypt:/etc/letsencrypt ... bunkerity/bunkerized-nginx
```
# Tutorials and examples # Tutorials and examples
You will find some docker-compose examples in the [examples directory](https://github.com/bunkerity/bunkerized-nginx/tree/master/examples). You will find some docker-compose examples in the [examples directory](https://github.com/bunkerity/bunkerized-nginx/tree/master/examples) and tutorials on our [blog](https://www.bunkerity.com/blog).
# Include custom configurations # Include custom configurations
Custom configurations files (ending with .conf suffix) can be added in some directory inside the container : Custom configurations files (ending with .conf suffix) can be added in some directory inside the container :
@@ -648,11 +671,10 @@ Only valid when `USE_REVERSE_PROXY` is set to *yes*. Set it to *yes* when the co
You can set multiple url/host by adding a suffix number to the variable name like this : `REVERSE_PROXY_WS_1`, `REVERSE_PROXY_WS_2`, `REVERSE_PROXY_WS_3`, ... You can set multiple url/host by adding a suffix number to the variable name like this : `REVERSE_PROXY_WS_1`, `REVERSE_PROXY_WS_2`, `REVERSE_PROXY_WS_3`, ...
`REVERSE_PROXY_HEADERS` `REVERSE_PROXY_HEADERS`
Values : *\<list of custom headers separated with a semicolon\>* Values : *\<list of custom headers separated with a semicolon like this : header1 value1;header2 value2...\>*
Examples : Access-Control-Allow-Origin 'https://mydomain.dev'; Custom_Api_Header 'test'; Default value :
Default value : ""
Context : *global*, *multisite* Context : *global*, *multisite*
Only valid when `USE_REVERSE_PROXY` is set to *yes*. Set it to *yes* when the corresponding `REVERSE_PROXY_HOST` is a WebSocket server. Only valid when `USE_REVERSE_PROXY` is set to *yes*.
You can set multiple url/host by adding a suffix number to the variable name like this : `REVERSE_PROXY_HEADERS_1`, `REVERSE_PROXY_HEADERS_2`, `REVERSE_PROXY_HEADERS_3`, ... You can set multiple url/host by adding a suffix number to the variable name like this : `REVERSE_PROXY_HEADERS_1`, `REVERSE_PROXY_HEADERS_2`, `REVERSE_PROXY_HEADERS_3`, ...
`PROXY_REAL_IP` `PROXY_REAL_IP`
@@ -876,19 +898,19 @@ If set to yes, nginx will redirect all HTTP requests to HTTPS.
`USE_CUSTOM_HTTPS` `USE_CUSTOM_HTTPS`
Values : *yes* | *no* Values : *yes* | *no*
Default value : *no* Default value : *no*
Context : *global* Context : *global*, *multisite*
If set to yes, HTTPS will be enabled with certificate/key of your choice. If set to yes, HTTPS will be enabled with certificate/key of your choice.
`CUSTOM_HTTPS_CERT` `CUSTOM_HTTPS_CERT`
Values : *\<any valid path inside the container\>* Values : *\<any valid path inside the container\>*
Default value : Default value :
Context : *global* Context : *global*, *multisite*
Full path of the certificate file to use when `USE_CUSTOM_HTTPS` is set to yes. Full path of the certificate file to use when `USE_CUSTOM_HTTPS` is set to yes.
`CUSTOM_HTTPS_KEY` `CUSTOM_HTTPS_KEY`
Values : *\<any valid path inside the container\>* Values : *\<any valid path inside the container\>*
Default value : Default value :
Context : *global* Context : *global*, *multisite*
Full path of the key file to use when `USE_CUSTOM_HTTPS` is set to yes. Full path of the key file to use when `USE_CUSTOM_HTTPS` is set to yes.
### Self-signed certificate ### Self-signed certificate
@@ -1173,10 +1195,10 @@ Context : *global*, *multisite*
If set to *yes*, lets you define custom IP addresses to be whitelisted through the `WHITELIST_IP_LIST` environment variable. If set to *yes*, lets you define custom IP addresses to be whitelisted through the `WHITELIST_IP_LIST` environment variable.
`WHITELIST_IP_LIST` `WHITELIST_IP_LIST`
Values : *\<list of IP addresses separated with spaces\>* Values : *\<list of IP addresses and/or network CIDR blocks separated with spaces\>*
Default value : *23.21.227.69 40.88.21.235 50.16.241.113 50.16.241.114 50.16.241.117 50.16.247.234 52.204.97.54 52.5.190.19 54.197.234.188 54.208.100.253 54.208.102.37 107.21.1.8* Default value : *23.21.227.69 40.88.21.235 50.16.241.113 50.16.241.114 50.16.241.117 50.16.247.234 52.204.97.54 52.5.190.19 54.197.234.188 54.208.100.253 54.208.102.37 107.21.1.8*
Context : *global* Context : *global*
The list of IP addresses to whitelist when `USE_WHITELIST_IP` is set to *yes*. The default list contains IP addresses of the [DuckDuckGo crawler](https://help.duckduckgo.com/duckduckgo-help-pages/results/duckduckbot/). The list of IP addresses and/or network CIDR blocks to whitelist when `USE_WHITELIST_IP` is set to *yes*. The default list contains IP addresses of the [DuckDuckGo crawler](https://help.duckduckgo.com/duckduckgo-help-pages/results/duckduckbot/).
`USE_WHITELIST_REVERSE` `USE_WHITELIST_REVERSE`
Values : *yes* | *no* Values : *yes* | *no*
@@ -1196,6 +1218,12 @@ Default value :
Context : *global*, *multisite* Context : *global*, *multisite*
Whitelist user agent from being blocked by `BLOCK_USER_AGENT`. Whitelist user agent from being blocked by `BLOCK_USER_AGENT`.
`WHITELIST_URI`
Values : *\<list of URI separated with spaces\>*
Default value :
Context : *global*, *multisite*
URI listed here have security checks like bad user-agents, bad IP, ... disabled. Useful when using callbacks for example.
### Custom blacklisting ### Custom blacklisting
`USE_BLACKLIST_IP` `USE_BLACKLIST_IP`
@@ -1205,10 +1233,10 @@ Context : *global*, *multisite*
If set to *yes*, lets you define custom IP addresses to be blacklisted through the `BLACKLIST_IP_LIST` environment variable. If set to *yes*, lets you define custom IP addresses to be blacklisted through the `BLACKLIST_IP_LIST` environment variable.
`BLACKLIST_IP_LIST` `BLACKLIST_IP_LIST`
Values : *\<list of IP addresses separated with spaces\>* Values : *\<list of IP addresses and/or network CIDR blocks separated with spaces\>*
Default value : Default value :
Context : *global* Context : *global*
The list of IP addresses to blacklist when `USE_BLACKLIST_IP` is set to *yes*. The list of IP addresses and/or network CIDR blocks to blacklist when `USE_BLACKLIST_IP` is set to *yes*.
`USE_BLACKLIST_REVERSE` `USE_BLACKLIST_REVERSE`
Values : *yes* | *no* Values : *yes* | *no*
@@ -1228,18 +1256,18 @@ The list of reverse DNS suffixes to blacklist when `USE_BLACKLIST_REVERSE` is se
Values : *yes* | *no* Values : *yes* | *no*
Default value : *yes* Default value : *yes*
Context : *global*, *multisite* Context : *global*, *multisite*
If set to yes, the amount of HTTP requests made by a user will be limited during a period of time. If set to yes, the amount of HTTP requests made by a user for a given resource will be limited during a period of time.
More info rate limiting [here](https://www.nginx.com/blog/rate-limiting-nginx/). More info rate limiting [here](https://www.nginx.com/blog/rate-limiting-nginx/) (the key used is $binary_remote_addr$uri).
`LIMIT_REQ_RATE` `LIMIT_REQ_RATE`
Values : *Xr/s* | *Xr/m* Values : *Xr/s* | *Xr/m*
Default value : *20r/s* Default value : *1r/s*
Context : *global*, *multisite* Context : *global*, *multisite*
The rate limit to apply when `USE_LIMIT_REQ` is set to *yes*. Default is 10 requests per second. The rate limit to apply when `USE_LIMIT_REQ` is set to *yes*. Default is 1 request to the same URI and from the same IP per second.
`LIMIT_REQ_BURST` `LIMIT_REQ_BURST`
Values : *<any valid integer\>* Values : *<any valid integer\>*
Default value : *40* Default value : *2*
Context : *global*, *multisite* Context : *global*, *multisite*
The number of requests to put in queue before rejecting requests. The number of requests to put in queue before rejecting requests.
@@ -1255,12 +1283,12 @@ The size of the cache to store information about request limiting.
Values : *yes* | *no* Values : *yes* | *no*
Default value : *yes* Default value : *yes*
Context : *global*, *multisite* Context : *global*, *multisite*
If set to yes, the number of connections made by an ip will be limited during a period of time. (ie. Very small/weak ddos protection) If set to yes, the number of connections made by an ip will be limited during a period of time. (ie. very small/weak ddos protection)
More info connections limiting [here](http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html). More info connections limiting [here](http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html).
`LIMIT_CONN_MAX` `LIMIT_CONN_MAX`
Values : *<any valid integer\>* Values : *<any valid integer\>*
Default value : *40* Default value : *50*
Context : *global*, *multisite* Context : *global*, *multisite*
The maximum number of connections per ip to put in queue before rejecting requests. The maximum number of connections per ip to put in queue before rejecting requests.
@@ -1290,7 +1318,7 @@ Only allow specific countries accessing your website. Use 2 letters country code
Values : *\<any valid IP/hostname\>* Values : *\<any valid IP/hostname\>*
Default value : Default value :
Context : *global*, *multisite* Context : *global*, *multisite*
Set the IP/hostname address of a remote PHP-FPM to execute .php files. See `USE_PHP` if you want to run a PHP-FPM instance on the same container as bunkerized-nginx. Set the IP/hostname address of a remote PHP-FPM to execute .php files.
`REMOTE_PHP_PATH` `REMOTE_PHP_PATH`
Values : *\<any valid absolute path\>* Values : *\<any valid absolute path\>*
@@ -1358,6 +1386,14 @@ Default value : *yes*
Context : *global* Context : *global*
If set to yes, ClamAV will automatically remove the detected files. If set to yes, ClamAV will automatically remove the detected files.
## Syslog
`REMOTE_SYSLOG`
Values : *\<any IP/hostname\>*
Default value :
Context : *global*
When defined, rsyslog will send logs (access.log and error.log) to the corresponding IP/hostname using syslog UDP protocol.
## Logrotate ## Logrotate
`LOGROTATE_MINSIZE` `LOGROTATE_MINSIZE`
@@ -1453,3 +1489,9 @@ Values : *random* | *\<any valid URI path\>*
Default value : *random* Default value : *random*
Context : *global* Context : *global*
Set it to a random path when you use *bunkerized-nginx* with *autoconf* feature in swarm mode. More info [here](#swarm-mode). Set it to a random path when you use *bunkerized-nginx* with *autoconf* feature in swarm mode. More info [here](#swarm-mode).
`API_WHITELIST_IP`
Values : *\<list of IP/CIDR separated with space\>*
Default value : *192.168.0.0/16 172.16.0.0/12 10.0.0.0/8*
Context : *global*
List of IP/CIDR block allowed to send API order using the `API_URI` uri.

View File

@@ -1 +1 @@
1.2.3 1.2.4

View File

@@ -11,6 +11,11 @@ class AutoConf :
self.__sites = {} self.__sites = {}
self.__config = Config(self.__swarm, api) self.__config = Config(self.__swarm, api)
def get_server(self, id) :
if id in self.__servers :
return self.__servers[id]
return False
def reload(self) : def reload(self) :
return self.__config.reload(self.__instances) return self.__config.reload(self.__instances)
@@ -60,9 +65,9 @@ class AutoConf :
self.__instances[id] = instance self.__instances[id] = instance
if self.__swarm and len(self.__instances) == 1 : if self.__swarm and len(self.__instances) == 1 :
if self.__config.initconf(self.__instances) : if self.__config.initconf(self.__instances) :
utils.log("[*] initial config succeeded") utils.log("[*] Initial config succeeded")
else : else :
utils.log("[!] initial config failed") utils.log("[!] Initial config failed")
utils.log("[*] bunkerized-nginx instance created : " + name + " / " + id) utils.log("[*] bunkerized-nginx instance created : " + name + " / " + id)
elif event == "start" : elif event == "start" :
self.__instances[id].reload() self.__instances[id].reload()
@@ -82,10 +87,12 @@ class AutoConf :
def __process_server(self, instance, event, id, name, labels) : def __process_server(self, instance, event, id, name, labels) :
vars = { k.replace("bunkerized-nginx.", "", 1) : v for k, v in labels.items() if k.startswith("bunkerized-nginx.")} vars = { k.replace("bunkerized-nginx.", "", 1) : v for k, v in labels.items() if k.startswith("bunkerized-nginx.")}
if event == "create" : if event == "create" :
utils.log("[*] Generating config for " + vars["SERVER_NAME"] + " ...")
if self.__config.generate(self.__instances, vars) : if self.__config.generate(self.__instances, vars) :
utils.log("[*] Generated config for " + vars["SERVER_NAME"]) utils.log("[*] Generated config for " + vars["SERVER_NAME"])
self.__servers[id] = instance self.__servers[id] = instance
if self.__swarm : if self.__swarm :
utils.log("[*] Activating config for " + vars["SERVER_NAME"] + " ...")
if self.__config.activate(self.__instances, vars) : if self.__config.activate(self.__instances, vars) :
utils.log("[*] Activated config for " + vars["SERVER_NAME"]) utils.log("[*] Activated config for " + vars["SERVER_NAME"])
else : else :
@@ -95,6 +102,7 @@ class AutoConf :
elif event == "start" : elif event == "start" :
if id in self.__servers : if id in self.__servers :
self.__servers[id].reload() self.__servers[id].reload()
utils.log("[*] Activating config for " + vars["SERVER_NAME"] + " ...")
if self.__config.activate(self.__instances, vars) : if self.__config.activate(self.__instances, vars) :
utils.log("[*] Activated config for " + vars["SERVER_NAME"]) utils.log("[*] Activated config for " + vars["SERVER_NAME"])
else : else :
@@ -102,6 +110,7 @@ class AutoConf :
elif event == "die" : elif event == "die" :
if id in self.__servers : if id in self.__servers :
self.__servers[id].reload() self.__servers[id].reload()
utils.log("[*] Deactivating config for " + vars["SERVER_NAME"])
if self.__config.deactivate(self.__instances, vars) : if self.__config.deactivate(self.__instances, vars) :
utils.log("[*] Deactivated config for " + vars["SERVER_NAME"]) utils.log("[*] Deactivated config for " + vars["SERVER_NAME"])
else : else :
@@ -109,11 +118,13 @@ class AutoConf :
elif event == "destroy" or event == "remove" : elif event == "destroy" or event == "remove" :
if id in self.__servers : if id in self.__servers :
if self.__swarm : if self.__swarm :
utils.log("[*] Deactivating config for " + vars["SERVER_NAME"])
if self.__config.deactivate(self.__instances, vars) : if self.__config.deactivate(self.__instances, vars) :
utils.log("[*] Deactivated config for " + vars["SERVER_NAME"]) utils.log("[*] Deactivated config for " + vars["SERVER_NAME"])
else : else :
utils.log("[!] Can't deactivate config for " + vars["SERVER_NAME"]) utils.log("[!] Can't deactivate config for " + vars["SERVER_NAME"])
del self.__servers[id] del self.__servers[id]
utils.log("[*] Removing config for " + vars["SERVER_NAME"])
if self.__config.remove(vars) : if self.__config.remove(vars) :
utils.log("[*] Removed config for " + vars["SERVER_NAME"]) utils.log("[*] Removed config for " + vars["SERVER_NAME"])
else : else :

View File

@@ -20,25 +20,42 @@ class Config :
var = var_value.split("=")[0] var = var_value.split("=")[0]
value = var_value.replace(var + "=", "", 1) value = var_value.replace(var + "=", "", 1)
vars[var] = value vars[var] = value
if self.globalconf(instances) :
i = 0 utils.log("[*] Generating global config ...")
if not self.globalconf(instances) :
utils.log("[!] Can't generate global config")
return False
utils.log("[*] Generated global config")
if "SERVER_NAME" in vars and vars["SERVER_NAME"] != "" :
for server in vars["SERVER_NAME"].split(" ") :
vars_site = vars.copy()
vars_site["SERVER_NAME"] = server
utils.log("[*] Generating config for " + vars["SERVER_NAME"] + " ...")
if not self.generate(instances, vars_site) or not self.activate(instances, vars_site, reload=False) :
utils.log("[!] Can't generate/activate site config for " + server)
return False
utils.log("[*] Generated config for " + vars["SERVER_NAME"])
with open("/etc/nginx/autoconf", "w") as f :
f.write("ok")
utils.log("[*] Waiting for bunkerized-nginx tasks ...")
i = 1
started = False started = False
while i < 10 : while i <= 10 :
time.sleep(i)
if self.__ping(instances) : if self.__ping(instances) :
started = True started = True
break break
i = i + 1 i = i + 1
utils.log("[!] Waiting " + str(i) + " seconds before retrying to contact nginx instances") utils.log("[!] Waiting " + str(i) + " seconds before retrying to contact bunkerized-nginx tasks")
time.sleep(i)
if started : if started :
utils.log("[*] bunkerized-nginx tasks started")
proc = subprocess.run(["/bin/su", "-s", "/opt/entrypoint/jobs.sh", "nginx"], env=vars, capture_output=True) proc = subprocess.run(["/bin/su", "-s", "/opt/entrypoint/jobs.sh", "nginx"], env=vars, capture_output=True)
return proc.returncode == 0 return proc.returncode == 0
else : else :
utils.log("[!] bunkerized-nginx instances are not started") utils.log("[!] bunkerized-nginx tasks are not started")
else :
utils.log("[!] Can't generate global conf")
except Exception as e : except Exception as e :
traceback.print_exc()
utils.log("[!] Error while initializing config : " + str(e)) utils.log("[!] Error while initializing config : " + str(e))
return False return False
@@ -54,12 +71,11 @@ class Config :
vars[var] = value vars[var] = value
proc = subprocess.run(["/bin/su", "-s", "/opt/entrypoint/global-config.sh", "nginx"], env=vars, capture_output=True) proc = subprocess.run(["/bin/su", "-s", "/opt/entrypoint/global-config.sh", "nginx"], env=vars, capture_output=True)
if proc.returncode == 0 : if proc.returncode == 0 :
with open("/etc/nginx/autoconf", "w") as f :
f.write("ok")
return True return True
else :
utils.log("[*] Error while generating global config : return code = " + str(proc.returncode))
except Exception as e : except Exception as e :
traceback.print_exc() utils.log("[!] Exception while generating global config : " + str(e))
utils.log("[!] Error while generating global config : " + str(e))
return False return False
def generate(self, instances, vars) : def generate(self, instances, vars) :
@@ -79,61 +95,76 @@ class Config :
vars_defaults.update(vars_instances) vars_defaults.update(vars_instances)
vars_defaults.update(vars) vars_defaults.update(vars)
# Call site-config.sh to generate the config # Call site-config.sh to generate the config
proc = subprocess.run(["/bin/su", "-s", "/bin/sh", "-c", "/opt/entrypoint/site-config.sh" + " " + vars["SERVER_NAME"], "nginx"], env=vars_defaults, capture_output=True) proc = subprocess.run(["/bin/su", "-s", "/bin/sh", "-c", "/opt/entrypoint/site-config.sh" + " \"" + vars["SERVER_NAME"] + "\"", "nginx"], env=vars_defaults, capture_output=True)
if proc.returncode == 0 and vars_defaults["MULTISITE"] == "yes" and self.__swarm : if proc.returncode == 0 and vars_defaults["MULTISITE"] == "yes" and self.__swarm :
proc = subprocess.run(["/bin/su", "-s", "/opt/entrypoint/multisite-config.sh", "nginx"], env=vars_defaults, capture_output=True) proc = subprocess.run(["/bin/su", "-s", "/opt/entrypoint/multisite-config.sh", "nginx"], env=vars_defaults, capture_output=True)
return proc.returncode == 0 if proc.returncode == 0 :
return proc.returncode == 0 return True
utils.log("[!] Error while generating site config for " + vars["SERVER_NAME"] + " : return code = " + str(proc.returncode))
except Exception as e : except Exception as e :
traceback.print_exc() utils.log("[!] Exception while generating site config : " + str(e))
utils.log("[!] Error while generating site config : " + str(e))
return False return False
def activate(self, instances, vars) : def activate(self, instances, vars, reload=True) :
try : try :
# Get first server name
first_server_name = vars["SERVER_NAME"].split(" ")[0]
# Check if file exists # Check if file exists
if not os.path.isfile("/etc/nginx/" + vars["SERVER_NAME"] + "/server.conf") : if not os.path.isfile("/etc/nginx/" + first_server_name + "/server.conf") :
utils.log("[!] /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf doesn't exist") utils.log("[!] /etc/nginx/" + first_server_name + "/server.conf doesn't exist")
return False return False
# Include the server conf # Include the server conf
utils.replace_in_file("/etc/nginx/nginx.conf", "}", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n}") utils.replace_in_file("/etc/nginx/nginx.conf", "}", "include /etc/nginx/" + first_server_name + "/server.conf;\n}")
# Reload
if not reload or self.reload(instances) :
return True
return self.reload(instances)
except Exception as e : except Exception as e :
traceback.print_exc() utils.log("[!] Exception while activating config : " + str(e))
utils.log("[!] Error while activating config : " + str(e))
return False return False
def deactivate(self, instances, vars) : def deactivate(self, instances, vars) :
try : try :
# Get first server name
first_server_name = vars["SERVER_NAME"].split(" ")[0]
# Check if file exists # Check if file exists
if not os.path.isfile("/etc/nginx/" + vars["SERVER_NAME"] + "/server.conf") : if not os.path.isfile("/etc/nginx/" + first_server_name + "/server.conf") :
utils.log("[!] /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf doesn't exist") utils.log("[!] /etc/nginx/" + first_server_name + "/server.conf doesn't exist")
return False return False
# Remove the include # Remove the include
utils.replace_in_file("/etc/nginx/nginx.conf", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n", "") utils.replace_in_file("/etc/nginx/nginx.conf", "include /etc/nginx/" + first_server_name + "/server.conf;\n", "")
return self.reload(instances) # Reload
if self.reload(instances) :
return True
except Exception as e : except Exception as e :
traceback.print_exc() utils.log("[!] Exception while deactivating config : " + str(e))
utils.log("[!] Error while deactivating config : " + str(e))
return False return False
def remove(self, instances, vars) : def remove(self, vars) :
try : try :
# Get first server name
first_server_name = vars["SERVER_NAME"].split(" ")[0]
# Check if file exists # Check if file exists
if not os.path.isfile("/etc/nginx/" + vars["SERVER_NAME"] + "/server.conf") : if not os.path.isfile("/etc/nginx/" + first_server_name + "/server.conf") :
utils.log("[!] /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf doesn't exist") utils.log("[!] /etc/nginx/" + first_server_name + "/server.conf doesn't exist")
return False return False
# Remove the folder # Remove the folder
shutil.rmtree("/etc/nginx/" + vars["SERVER_NAME"]) shutil.rmtree("/etc/nginx/" + first_server_name)
return True return True
except Exception as e : except Exception as e :
utils.log("[!] Error while deactivating config : " + str(e)) utils.log("[!] Error while deactivating config : " + str(e))
return False return False
def reload(self, instances) : def reload(self, instances) :
@@ -149,7 +180,7 @@ class Config :
instance.reload() instance.reload()
# Reload via API # Reload via API
if self.__swarm : if self.__swarm :
# Send POST request on http://serviceName.NodeID.TaskID:8000/reload # Send POST request on http://serviceName.NodeID.TaskID:8000/action
name = instance.name name = instance.name
for task in instance.tasks() : for task in instance.tasks() :
if task["Status"]["State"] != "running" : if task["Status"]["State"] != "running" :

View File

@@ -12,6 +12,9 @@ RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
mkdir /opt/scripts && \ mkdir /opt/scripts && \
addgroup -g 101 nginx && \ addgroup -g 101 nginx && \
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \ adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
mkdir /etc/letsencrypt && \
chown root:nginx /etc/letsencrypt && \
chmod 770 /etc/letsencrypt && \
mkdir /var/log/letsencrypt && \ mkdir /var/log/letsencrypt && \
chown root:nginx /var/log/letsencrypt && \ chown root:nginx /var/log/letsencrypt && \
chmod 770 /var/log/letsencrypt && \ chmod 770 /var/log/letsencrypt && \
@@ -25,7 +28,11 @@ RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
chown root:nginx /var/log/jobs.log && \ chown root:nginx /var/log/jobs.log && \
chmod 770 /var/log/jobs.log && \ chmod 770 /var/log/jobs.log && \
chown -R root:nginx /opt/confs/nginx && \ chown -R root:nginx /opt/confs/nginx && \
chmod -R 770 /opt/confs/nginx chmod -R 770 /opt/confs/nginx && \
mkdir /acme-challenge && \
chown root:nginx /acme-challenge && \
chmod 770 /acme-challenge
COPY autoconf/misc/logrotate.conf /etc/logrotate.conf COPY autoconf/misc/logrotate.conf /etc/logrotate.conf
COPY scripts/* /opt/scripts/ COPY scripts/* /opt/scripts/

View File

@@ -9,8 +9,12 @@ RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
mkdir /opt/entrypoint && \ mkdir /opt/entrypoint && \
mkdir -p /opt/confs/site && \ mkdir -p /opt/confs/site && \
mkdir -p /opt/confs/global && \ mkdir -p /opt/confs/global && \
mkdir /opt/scripts && \
addgroup -g 101 nginx && \ addgroup -g 101 nginx && \
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \ adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
mkdir /etc/letsencrypt && \
chown root:nginx /etc/letsencrypt && \
chmod 770 /etc/letsencrypt && \
mkdir /var/log/letsencrypt && \ mkdir /var/log/letsencrypt && \
chown root:nginx /var/log/letsencrypt && \ chown root:nginx /var/log/letsencrypt && \
chmod 770 /var/log/letsencrypt && \ chmod 770 /var/log/letsencrypt && \
@@ -24,7 +28,10 @@ RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
chown root:nginx /var/log/jobs.log && \ chown root:nginx /var/log/jobs.log && \
chmod 770 /var/log/jobs.log && \ chmod 770 /var/log/jobs.log && \
chown -R root:nginx /opt/confs/nginx && \ chown -R root:nginx /opt/confs/nginx && \
chmod -R 770 /opt/confs/nginx chmod -R 770 /opt/confs/nginx && \
mkdir /acme-challenge && \
chown root:nginx /acme-challenge && \
chmod 770 /acme-challenge
COPY autoconf/misc/logrotate.conf /etc/logrotate.conf COPY autoconf/misc/logrotate.conf /etc/logrotate.conf
COPY scripts/* /opt/scripts/ COPY scripts/* /opt/scripts/

View File

@@ -15,8 +15,12 @@ RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
mkdir /opt/entrypoint && \ mkdir /opt/entrypoint && \
mkdir -p /opt/confs/site && \ mkdir -p /opt/confs/site && \
mkdir -p /opt/confs/global && \ mkdir -p /opt/confs/global && \
mkdir /opt/scripts && \
addgroup -g 101 nginx && \ addgroup -g 101 nginx && \
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \ adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
mkdir /etc/letsencrypt && \
chown root:nginx /etc/letsencrypt && \
chmod 770 /etc/letsencrypt && \
mkdir /var/log/letsencrypt && \ mkdir /var/log/letsencrypt && \
chown root:nginx /var/log/letsencrypt && \ chown root:nginx /var/log/letsencrypt && \
chmod 770 /var/log/letsencrypt && \ chmod 770 /var/log/letsencrypt && \
@@ -30,7 +34,10 @@ RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
chown root:nginx /var/log/jobs.log && \ chown root:nginx /var/log/jobs.log && \
chmod 770 /var/log/jobs.log && \ chmod 770 /var/log/jobs.log && \
chown -R root:nginx /opt/confs/nginx && \ chown -R root:nginx /opt/confs/nginx && \
chmod -R 770 /opt/confs/nginx chmod -R 770 /opt/confs/nginx && \
mkdir /acme-challenge && \
chown root:nginx /acme-challenge && \
chmod 770 /acme-challenge
COPY autoconf/misc/logrotate.conf /etc/logrotate.conf COPY autoconf/misc/logrotate.conf /etc/logrotate.conf
COPY scripts/* /opt/scripts/ COPY scripts/* /opt/scripts/

View File

@@ -15,8 +15,12 @@ RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
mkdir /opt/entrypoint && \ mkdir /opt/entrypoint && \
mkdir -p /opt/confs/site && \ mkdir -p /opt/confs/site && \
mkdir -p /opt/confs/global && \ mkdir -p /opt/confs/global && \
mkdir /opt/scripts && \
addgroup -g 101 nginx && \ addgroup -g 101 nginx && \
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \ adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
mkdir /etc/letsencrypt && \
chown root:nginx /etc/letsencrypt && \
chmod 770 /etc/letsencrypt && \
mkdir /var/log/letsencrypt && \ mkdir /var/log/letsencrypt && \
chown root:nginx /var/log/letsencrypt && \ chown root:nginx /var/log/letsencrypt && \
chmod 770 /var/log/letsencrypt && \ chmod 770 /var/log/letsencrypt && \
@@ -30,7 +34,10 @@ RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
chown root:nginx /var/log/jobs.log && \ chown root:nginx /var/log/jobs.log && \
chmod 770 /var/log/jobs.log && \ chmod 770 /var/log/jobs.log && \
chown -R root:nginx /opt/confs/nginx && \ chown -R root:nginx /opt/confs/nginx && \
chmod -R 770 /opt/confs/nginx chmod -R 770 /opt/confs/nginx && \
mkdir /acme-challenge && \
chown root:nginx /acme-challenge && \
chmod 770 /acme-challenge
COPY autoconf/misc/logrotate.conf /etc/logrotate.conf COPY autoconf/misc/logrotate.conf /etc/logrotate.conf
COPY scripts/* /opt/scripts/ COPY scripts/* /opt/scripts/

View File

@@ -9,8 +9,12 @@ RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
mkdir /opt/entrypoint && \ mkdir /opt/entrypoint && \
mkdir -p /opt/confs/site && \ mkdir -p /opt/confs/site && \
mkdir -p /opt/confs/global && \ mkdir -p /opt/confs/global && \
mkdir /opt/scripts && \
addgroup -g 101 nginx && \ addgroup -g 101 nginx && \
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \ adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
mkdir /etc/letsencrypt && \
chown root:nginx /etc/letsencrypt && \
chmod 770 /etc/letsencrypt && \
mkdir /var/log/letsencrypt && \ mkdir /var/log/letsencrypt && \
chown root:nginx /var/log/letsencrypt && \ chown root:nginx /var/log/letsencrypt && \
chmod 770 /var/log/letsencrypt && \ chmod 770 /var/log/letsencrypt && \
@@ -24,7 +28,10 @@ RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
chown root:nginx /var/log/jobs.log && \ chown root:nginx /var/log/jobs.log && \
chmod 770 /var/log/jobs.log && \ chmod 770 /var/log/jobs.log && \
chown -R root:nginx /opt/confs/nginx && \ chown -R root:nginx /opt/confs/nginx && \
chmod -R 770 /opt/confs/nginx chmod -R 770 /opt/confs/nginx && \
mkdir /acme-challenge && \
chown root:nginx /acme-challenge && \
chmod 770 /acme-challenge
COPY autoconf/misc/logrotate.conf /etc/logrotate.conf COPY autoconf/misc/logrotate.conf /etc/logrotate.conf
COPY scripts/* /opt/scripts/ COPY scripts/* /opt/scripts/

View File

@@ -44,6 +44,7 @@ with lock :
# Process events received from Docker # Process events received from Docker
try : try :
utils.log("[*] Listening for Docker events ...")
for event in client.events(decode=True) : for event in client.events(decode=True) :
# Process only container/service events # Process only container/service events
@@ -53,10 +54,14 @@ try :
# Get Container/Service object # Get Container/Service object
try : try :
if swarm : if swarm :
server = client.services.get(service_id=event["Actor"]["ID"]) id = service_id=event["Actor"]["ID"]
server = client.services.get(service_id=id)
else : else :
server = client.containers.get(event["id"]) id = event["id"]
server = client.containers.get(id)
except docker.errors.NotFound as e : except docker.errors.NotFound as e :
server = autoconf.get_server(id)
if not server :
continue continue
# Process the event # Process the event

View File

@@ -2,6 +2,12 @@
echo "[*] Starting autoconf ..." echo "[*] Starting autoconf ..."
# check permissions
su -s "/opt/entrypoint/permissions.sh" nginx
if [ "$?" -ne 0 ] ; then
exit 1
fi
if [ "$SWARM_MODE" = "yes" ] ; then if [ "$SWARM_MODE" = "yes" ] ; then
cp -r /opt/confs/nginx/* /etc/nginx cp -r /opt/confs/nginx/* /etc/nginx
chown -R root:nginx /etc/nginx chown -R root:nginx /etc/nginx

View File

@@ -136,6 +136,10 @@ sed -i 's/^API_KEY=.*/API_KEY=%CROWDSEC_KEY%/' /usr/local/lib/lua/crowdsec/crowd
sed -i 's/require "lrucache"/require "resty.lrucache"/' /usr/local/lib/lua/crowdsec/CrowdSec.lua sed -i 's/require "lrucache"/require "resty.lrucache"/' /usr/local/lib/lua/crowdsec/CrowdSec.lua
sed -i 's/require "config"/require "crowdsec.config"/' /usr/local/lib/lua/crowdsec/CrowdSec.lua sed -i 's/require "config"/require "crowdsec.config"/' /usr/local/lib/lua/crowdsec/CrowdSec.lua
cd /tmp cd /tmp
git_secure_clone https://github.com/hamishforbes/lua-resty-iputils.git 3151d6485e830421266eee5c0f386c32c835dba4
cd lua-resty-iputils
make LUA_LIB_DIR=/usr/local/lib/lua install
cd /tmp
git_secure_clone https://github.com/openresty/lua-nginx-module.git 2d23bc4f0a29ed79aaaa754c11bffb1080aa44ba git_secure_clone https://github.com/openresty/lua-nginx-module.git 2d23bc4f0a29ed79aaaa754c11bffb1080aa44ba
export LUAJIT_LIB=/usr/local/lib export LUAJIT_LIB=/usr/local/lib
export LUAJIT_INC=/usr/local/include/luajit-2.1 export LUAJIT_INC=/usr/local/include/luajit-2.1
@@ -153,7 +157,7 @@ fi
tar -xvzf nginx-${NGINX_VERSION}.tar.gz tar -xvzf nginx-${NGINX_VERSION}.tar.gz
cd nginx-$NGINX_VERSION cd nginx-$NGINX_VERSION
CONFARGS=$(nginx -V 2>&1 | sed -n -e 's/^.*arguments: //p') CONFARGS=$(nginx -V 2>&1 | sed -n -e 's/^.*arguments: //p')
CONFARGS=${CONFARGS/-Os -fomit-frame-pointer/-Os} CONFARGS=${CONFARGS/-Os -fomit-frame-pointer -g/-Os}
./configure $CONFARGS --add-dynamic-module=/tmp/ModSecurity-nginx --add-dynamic-module=/tmp/headers-more-nginx-module --add-dynamic-module=/tmp/ngx_http_geoip2_module --add-dynamic-module=/tmp/nginx_cookie_flag_module --add-dynamic-module=/tmp/lua-nginx-module --add-dynamic-module=/tmp/ngx_brotli ./configure $CONFARGS --add-dynamic-module=/tmp/ModSecurity-nginx --add-dynamic-module=/tmp/headers-more-nginx-module --add-dynamic-module=/tmp/ngx_http_geoip2_module --add-dynamic-module=/tmp/nginx_cookie_flag_module --add-dynamic-module=/tmp/lua-nginx-module --add-dynamic-module=/tmp/ngx_brotli
make -j $NTASK modules make -j $NTASK modules
cp ./objs/*.so /usr/lib/nginx/modules cp ./objs/*.so /usr/lib/nginx/modules

View File

@@ -13,7 +13,7 @@ rewrite_by_lua_block {
if api.is_api_call(api_uri) then if api.is_api_call(api_uri) then
ngx.header.content_type = 'text/plain' ngx.header.content_type = 'text/plain'
if api.do_api_call(api_uri) then if api.do_api_call(api_uri) then
ngx.log(ngx.WARN, "[API] API call " .. ngx.var.request_uri .. " successfull from " .. ngx.var.remote_addr) ngx.log(ngx.NOTICE, "[API] API call " .. ngx.var.request_uri .. " successfull from " .. ngx.var.remote_addr)
ngx.say("ok") ngx.say("ok")
else else
ngx.log(ngx.WARN, "[API] API call " .. ngx.var.request_uri .. " failed from " .. ngx.var.remote_addr) ngx.log(ngx.WARN, "[API] API call " .. ngx.var.request_uri .. " failed from " .. ngx.var.remote_addr)

View File

@@ -6,7 +6,7 @@ rewrite_by_lua_block {
if api.is_api_call(api_uri) then if api.is_api_call(api_uri) then
ngx.header.content_type = 'text/plain' ngx.header.content_type = 'text/plain'
if api.do_api_call(api_uri) then if api.do_api_call(api_uri) then
ngx.log(ngx.WARN, "[API] API call " .. ngx.var.request_uri .. " successfull from " .. ngx.var.remote_addr) ngx.log(ngx.NOTICE, "[API] API call " .. ngx.var.request_uri .. " successfull from " .. ngx.var.remote_addr)
ngx.say("ok") ngx.say("ok")
else else
ngx.log(ngx.WARN, "[API] API call " .. ngx.var.request_uri .. " failed from " .. ngx.var.remote_addr) ngx.log(ngx.WARN, "[API] API call " .. ngx.var.request_uri .. " failed from " .. ngx.var.remote_addr)

View File

@@ -5,5 +5,5 @@ init_by_lua_block {
ngx.log(ngx.ERR, "[Crowdsec] " .. err) ngx.log(ngx.ERR, "[Crowdsec] " .. err)
error() error()
end end
ngx.log(ngx.ERR, "[Crowdsec] Initialisation done") ngx.log(ngx.NOTICE, "[Crowdsec] Initialisation done")
} }

View File

@@ -50,7 +50,7 @@ http {
# write logs to local syslog # write logs to local syslog
log_format logf '%LOG_FORMAT%'; log_format logf '%LOG_FORMAT%';
access_log syslog:server=unix:/tmp/log,nohostname,facility=local0,severity=notice logf; access_log syslog:server=unix:/tmp/log,nohostname,facility=local0,severity=notice logf;
error_log syslog:server=unix:/tmp/log,nohostname,facility=local0 warn; error_log syslog:server=unix:/tmp/log,nohostname,facility=local0 notice;
# temp paths # temp paths
proxy_temp_path /tmp/proxy_temp; proxy_temp_path /tmp/proxy_temp;

View File

@@ -7,7 +7,7 @@ location = %ANTIBOT_URI% {
local cookie = require "cookie" local cookie = require "cookie"
local captcha = require "captcha" local captcha = require "captcha"
if not cookie.is_set("uri") then if not cookie.is_set("uri") then
ngx.log(ngx.WARN, "[ANTIBOT] captcha fail (1) for " .. ngx.var.remote_addr) ngx.log(ngx.NOTICE, "[ANTIBOT] captcha fail (1) for " .. ngx.var.remote_addr)
return ngx.exit(ngx.HTTP_FORBIDDEN) return ngx.exit(ngx.HTTP_FORBIDDEN)
end end
local img, res = captcha.get_challenge() local img, res = captcha.get_challenge()
@@ -22,19 +22,19 @@ location = %ANTIBOT_URI% {
local cookie = require "cookie" local cookie = require "cookie"
local captcha = require "captcha" local captcha = require "captcha"
if not cookie.is_set("captchares") then if not cookie.is_set("captchares") then
ngx.log(ngx.WARN, "[ANTIBOT] captcha fail (2) for " .. ngx.var.remote_addr) ngx.log(ngx.NOTICE, "[ANTIBOT] captcha fail (2) for " .. ngx.var.remote_addr)
return ngx.exit(ngx.HTTP_FORBIDDEN) return ngx.exit(ngx.HTTP_FORBIDDEN)
end end
ngx.req.read_body() ngx.req.read_body()
local args, err = ngx.req.get_post_args(1) local args, err = ngx.req.get_post_args(1)
if err == "truncated" or not args or not args["captcha"] then if err == "truncated" or not args or not args["captcha"] then
ngx.log(ngx.WARN, "[ANTIBOT] captcha fail (3) for " .. ngx.var.remote_addr) ngx.log(ngx.NOTICE, "[ANTIBOT] captcha fail (3) for " .. ngx.var.remote_addr)
return ngx.exit(ngx.HTTP_FORBIDDEN) return ngx.exit(ngx.HTTP_FORBIDDEN)
end end
local captcha_user = args["captcha"] local captcha_user = args["captcha"]
local check = captcha.check(captcha_user, cookie.get("captchares")) local check = captcha.check(captcha_user, cookie.get("captchares"))
if not check then if not check then
ngx.log(ngx.WARN, "[ANTIBOT] captcha fail (4) for " .. ngx.var.remote_addr) ngx.log(ngx.NOTICE, "[ANTIBOT] captcha fail (4) for " .. ngx.var.remote_addr)
return ngx.redirect("%ANTIBOT_URI%") return ngx.redirect("%ANTIBOT_URI%")
end end
cookie.set({captcha = "ok"}) cookie.set({captcha = "ok"})

View File

@@ -7,7 +7,7 @@ location = %ANTIBOT_URI% {
local cookie = require "cookie" local cookie = require "cookie"
local recaptcha = require "recaptcha" local recaptcha = require "recaptcha"
if not cookie.is_set("uri") then if not cookie.is_set("uri") then
ngx.log(ngx.WARN, "[ANTIBOT] recaptcha fail (1) for " .. ngx.var.remote_addr) ngx.log(ngx.NOTICE, "[ANTIBOT] recaptcha fail (1) for " .. ngx.var.remote_addr)
return ngx.exit(ngx.HTTP_FORBIDDEN) return ngx.exit(ngx.HTTP_FORBIDDEN)
end end
local code = recaptcha.get_code("%ANTIBOT_URI%", "%ANTIBOT_RECAPTCHA_SITEKEY%") local code = recaptcha.get_code("%ANTIBOT_URI%", "%ANTIBOT_RECAPTCHA_SITEKEY%")
@@ -20,19 +20,19 @@ location = %ANTIBOT_URI% {
local cookie = require "cookie" local cookie = require "cookie"
local recaptcha = require "recaptcha" local recaptcha = require "recaptcha"
if not cookie.is_set("uri") then if not cookie.is_set("uri") then
ngx.log(ngx.WARN, "[ANTIBOT] recaptcha fail (2) for " .. ngx.var.remote_addr) ngx.log(ngx.NOTICE, "[ANTIBOT] recaptcha fail (2) for " .. ngx.var.remote_addr)
return ngx.exit(ngx.HTTP_FORBIDDEN) return ngx.exit(ngx.HTTP_FORBIDDEN)
end end
ngx.req.read_body() ngx.req.read_body()
local args, err = ngx.req.get_post_args(1) local args, err = ngx.req.get_post_args(1)
if err == "truncated" or not args or not args["token"] then if err == "truncated" or not args or not args["token"] then
ngx.log(ngx.WARN, "[ANTIBOT] recaptcha fail (3) for " .. ngx.var.remote_addr) ngx.log(ngx.NOTICE, "[ANTIBOT] recaptcha fail (3) for " .. ngx.var.remote_addr)
return ngx.exit(ngx.HTTP_FORBIDDEN) return ngx.exit(ngx.HTTP_FORBIDDEN)
end end
local token = args["token"] local token = args["token"]
local check = recaptcha.check(token, "%ANTIBOT_RECAPTCHA_SECRET%") local check = recaptcha.check(token, "%ANTIBOT_RECAPTCHA_SECRET%")
if check < %ANTIBOT_RECAPTCHA_SCORE% then if check < %ANTIBOT_RECAPTCHA_SCORE% then
ngx.log(ngx.WARN, "[ANTIBOT] recaptcha fail (4) for " .. ngx.var.remote_addr .. " (score = " .. tostring(check) .. ")") ngx.log(ngx.NOTICE, "[ANTIBOT] recaptcha fail (4) for " .. ngx.var.remote_addr .. " (score = " .. tostring(check) .. ")")
return ngx.exit(ngx.HTTP_FORBIDDEN) return ngx.exit(ngx.HTTP_FORBIDDEN)
end end
cookie.set({recaptcha = "ok"}) cookie.set({recaptcha = "ok"})

View File

@@ -1,4 +1,6 @@
location ~* \.(%CLIENT_CACHE_EXTENSIONS%)$ {
etag %CLIENT_CACHE_ETAG%; etag %CLIENT_CACHE_ETAG%;
add_header Cache-Control "%CLIENT_CACHE_CONTROL%"; set $cache "";
if ($uri ~* \.(%CLIENT_CACHE_EXTENSIONS%)$) {
set $cache "%CLIENT_CACHE_CONTROL%";
} }
add_header Cache-Control $cache;

View File

@@ -19,7 +19,6 @@ local use_antibot_captcha = %USE_ANTIBOT_CAPTCHA%
local use_antibot_recaptcha = %USE_ANTIBOT_RECAPTCHA% local use_antibot_recaptcha = %USE_ANTIBOT_RECAPTCHA%
-- include LUA code -- include LUA code
local whitelist = require "whitelist" local whitelist = require "whitelist"
local blacklist = require "blacklist" local blacklist = require "blacklist"
local dnsbl = require "dnsbl" local dnsbl = require "dnsbl"
@@ -31,11 +30,7 @@ local recaptcha = require "recaptcha"
-- user variables -- user variables
local antibot_uri = "%ANTIBOT_URI%" local antibot_uri = "%ANTIBOT_URI%"
local whitelist_user_agent = {%WHITELIST_USER_AGENT%} local whitelist_user_agent = {%WHITELIST_USER_AGENT%}
local whitelist_uri = {%WHITELIST_URI%}
-- check if it's let's encrypt bot
if use_lets_encrypt and string.match(ngx.var.request_uri, "^/.well-known/acme-challenge/") then
ngx.exit(ngx.OK)
end
-- check if already in whitelist cache -- check if already in whitelist cache
if use_whitelist_ip and whitelist.ip_cached_ok() then if use_whitelist_ip and whitelist.ip_cached_ok() then
@@ -72,6 +67,19 @@ if use_whitelist_reverse and not whitelist.reverse_cached() then
end end
end end
-- check if URI is whitelisted
for k, v in pairs(whitelist_uri) do
if ngx.var.request_uri == v then
ngx.log(ngx.NOTICE, "[WHITELIST] URI " .. v .. " is whitelisted")
ngx.exit(ngx.OK)
end
end
-- check if it's certbot
if use_lets_encrypt and string.match(ngx.var.request_uri, "^/.well-known/acme-challenge/") then
ngx.exit(ngx.OK)
end
-- check if IP is blacklisted (only if not in cache) -- check if IP is blacklisted (only if not in cache)
if use_blacklist_ip and not blacklist.ip_cached() then if use_blacklist_ip and not blacklist.ip_cached() then
if blacklist.check_ip() then if blacklist.check_ip() then
@@ -88,32 +96,29 @@ end
-- check if user-agent is allowed -- check if user-agent is allowed
if use_user_agent and ngx.var.bad_user_agent == "yes" then if use_user_agent and ngx.var.bad_user_agent == "yes" then
local headers = ngx.req.get_headers() local block = false
local ua = headers["User-Agent"] for k, v in pairs(whitelist_user_agent) do
if not whitelist_user_agent ~= "" then if string.match(ngx.var.http_user_agent, v) then
local k_ua_white, v_ua_white = next(whitelist_user_agent, nil) ngx.log(ngx.NOTICE, "[ALLOW] User-Agent " .. ngx.var.http_user_agent .. " is whitelisted")
while v_ua_white do block = false
local rst_whitelist = string.match(ua, v_ua_white) break
if rst_whitelist ~= nil and rst_whitelist ~= "" then
ngx.log(ngx.WARN, "[ALLOW] User-Agent " .. ngx.var.http_user_agent .. " is whitelisted")
ngx.exit(ngx.OK)
end
k_ua_white, v_ua_white = next(whitelist_user_agent, k_ua_white)
end end
end end
ngx.log(ngx.WARN, "[BLOCK] User-Agent " .. ngx.var.http_user_agent .. " is blacklisted") if block then
ngx.log(ngx.NOTICE, "[BLOCK] User-Agent " .. ngx.var.http_user_agent .. " is blacklisted")
ngx.exit(ngx.HTTP_FORBIDDEN) ngx.exit(ngx.HTTP_FORBIDDEN)
end end
end
-- check if referrer is allowed -- check if referrer is allowed
if use_referrer and ngx.var.bad_referrer == "yes" then if use_referrer and ngx.var.bad_referrer == "yes" then
ngx.log(ngx.WARN, "[BLOCK] Referrer " .. ngx.var.http_referer .. " is blacklisted") ngx.log(ngx.NOTICE, "[BLOCK] Referrer " .. ngx.var.http_referer .. " is blacklisted")
ngx.exit(ngx.HTTP_FORBIDDEN) ngx.exit(ngx.HTTP_FORBIDDEN)
end end
-- check if country is allowed -- check if country is allowed
if use_country and ngx.var.allowed_country == "no" then if use_country and ngx.var.allowed_country == "no" then
ngx.log(ngx.WARN, "[BLOCK] Country of " .. ngx.var.remote_addr .. " is blacklisted") ngx.log(ngx.NOTICE, "[BLOCK] Country of " .. ngx.var.remote_addr .. " is blacklisted")
ngx.exit(ngx.HTTP_FORBIDDEN) ngx.exit(ngx.HTTP_FORBIDDEN)
end end
@@ -131,7 +136,7 @@ if use_crowdsec then
ngx.log(ngx.ERR, "[Crowdsec] " .. err) ngx.log(ngx.ERR, "[Crowdsec] " .. err)
end end
if not ok then if not ok then
ngx.log(ngx.ERR, "[Crowdsec] denied '" .. ngx.var.remote_addr .. "'") ngx.log(ngx.NOTICE, "[Crowdsec] denied '" .. ngx.var.remote_addr .. "'")
ngx.exit(ngx.HTTP_FORBIDDEN) ngx.exit(ngx.HTTP_FORBIDDEN)
end end
end end
@@ -143,7 +148,7 @@ if use_antibot_cookie then
cookie.set({uri = ngx.var.request_uri}) cookie.set({uri = ngx.var.request_uri})
return ngx.redirect(antibot_uri) return ngx.redirect(antibot_uri)
end end
ngx.log(ngx.WARN, "[ANTIBOT] cookie fail for " .. ngx.var.remote_addr) ngx.log(ngx.NOTICE, "[ANTIBOT] cookie fail for " .. ngx.var.remote_addr)
return ngx.exit(ngx.HTTP_FORBIDDEN) return ngx.exit(ngx.HTTP_FORBIDDEN)
else else
if ngx.var.request_uri == antibot_uri then if ngx.var.request_uri == antibot_uri then

View File

@@ -50,7 +50,6 @@ SecResponseBodyLimitAction ProcessPartial
# log usefull stuff # log usefull stuff
SecAuditEngine RelevantOnly SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogType Serial SecAuditLogType Serial
SecAuditLog /var/log/nginx/modsec_audit.log SecAuditLog /var/log/nginx/modsec_audit.log

View File

@@ -1,4 +1,5 @@
location %REVERSE_PROXY_URL% { location %REVERSE_PROXY_URL% {
etag off;
proxy_pass %REVERSE_PROXY_HOST%; proxy_pass %REVERSE_PROXY_HOST%;
%REVERSE_PROXY_HEADERS% %REVERSE_PROXY_HEADERS%
%REVERSE_PROXY_WS% %REVERSE_PROXY_WS%

View File

@@ -102,11 +102,11 @@ BLACKLIST_REVERSE_LIST="${BLACKLIST_REVERSE_LIST-.shodan.io}"
USE_DNSBL="${USE_DNSBL-yes}" USE_DNSBL="${USE_DNSBL-yes}"
DNSBL_LIST="${DNSBL_LIST-bl.blocklist.de problems.dnsbl.sorbs.net sbl.spamhaus.org xbl.spamhaus.org}" DNSBL_LIST="${DNSBL_LIST-bl.blocklist.de problems.dnsbl.sorbs.net sbl.spamhaus.org xbl.spamhaus.org}"
USE_LIMIT_REQ="${USE_LIMIT_REQ-yes}" USE_LIMIT_REQ="${USE_LIMIT_REQ-yes}"
LIMIT_REQ_RATE="${LIMIT_REQ_RATE-20r/s}" LIMIT_REQ_RATE="${LIMIT_REQ_RATE-1r/s}"
LIMIT_REQ_BURST="${LIMIT_REQ_BURST-40}" LIMIT_REQ_BURST="${LIMIT_REQ_BURST-2}"
LIMIT_REQ_CACHE="${LIMIT_REQ_CACHE-10m}" LIMIT_REQ_CACHE="${LIMIT_REQ_CACHE-10m}"
USE_LIMIT_CONN="${USE_LIMIT_CONN-yes}" USE_LIMIT_CONN="${USE_LIMIT_CONN-yes}"
LIMIT_CONN_MAX="${LIMIT_CONN_MAX-40}" LIMIT_CONN_MAX="${LIMIT_CONN_MAX-50}"
LIMIT_CONN_CACHE="${LIMIT_CONN_CACHE-10m}" LIMIT_CONN_CACHE="${LIMIT_CONN_CACHE-10m}"
PROXY_REAL_IP="${PROXY_REAL_IP-no}" PROXY_REAL_IP="${PROXY_REAL_IP-no}"
PROXY_REAL_IP_FROM="${PROXY_REAL_IP_FROM-192.168.0.0/16 172.16.0.0/12 10.0.0.0/8}" PROXY_REAL_IP_FROM="${PROXY_REAL_IP_FROM-192.168.0.0/16 172.16.0.0/12 10.0.0.0/8}"
@@ -128,4 +128,5 @@ ANTIBOT_SESSION_SECRET="${ANTIBOT_SESSION_SECRET-random}"
USE_CROWDSEC="${USE_CROWDSEC-no}" USE_CROWDSEC="${USE_CROWDSEC-no}"
USE_API="${USE_API-no}" USE_API="${USE_API-no}"
API_URI="${API_URI-random}" API_URI="${API_URI-random}"
API_WHITELIST_IP="${API_WHITELIST_IP-192.168.0.0/16 172.16.0.0/12 10.0.0.0/8}"
SWARM_MODE="${SWARM_MODE-no}" SWARM_MODE="${SWARM_MODE-no}"

View File

@@ -52,6 +52,16 @@ if [ ! -f "/opt/installed" ] ; then
echo "[*] Configuring bunkerized-nginx ..." echo "[*] Configuring bunkerized-nginx ..."
# check permissions
if [ "$SWARM_MODE" = "no" ] ; then
/opt/entrypoint/permissions.sh
else
/opt/entrypoint/permissions-swarm.sh
fi
if [ "$?" -ne 0 ] ; then
exit 1
fi
# logs config # logs config
/opt/entrypoint/logs.sh /opt/entrypoint/logs.sh
@@ -122,7 +132,7 @@ else
fi fi
# list of log files to display # list of log files to display
LOGS="/var/log/access.log /var/log/error.log /var/log/jobs.log" LOGS="/var/log/access.log /var/log/error.log /var/log/jobs.log /var/log/nginx/modsec_audit.log"
# start fail2ban # start fail2ban
if [ "$USE_FAIL2BAN" = "yes" ] ; then if [ "$USE_FAIL2BAN" = "yes" ] ; then

View File

@@ -10,6 +10,7 @@
cp /opt/confs/global/* /etc/nginx/ cp /opt/confs/global/* /etc/nginx/
# include server block(s) # include server block(s)
if [ "$SWARM_MODE" = "no" ] ; then
if [ "$MULTISITE" = "yes" ] ; then if [ "$MULTISITE" = "yes" ] ; then
includes="" includes=""
for server in $SERVER_NAME ; do for server in $SERVER_NAME ; do
@@ -19,6 +20,9 @@ if [ "$MULTISITE" = "yes" ] ; then
else else
replace_in_file "/etc/nginx/nginx.conf" "%INCLUDE_SERVER%" "include /etc/nginx/server.conf;" replace_in_file "/etc/nginx/nginx.conf" "%INCLUDE_SERVER%" "include /etc/nginx/server.conf;"
fi fi
else
replace_in_file "/etc/nginx/nginx.conf" "%INCLUDE_SERVER%" ""
fi
# setup default server block if multisite # setup default server block if multisite
if [ "$MULTISITE" = "yes" ] ; then if [ "$MULTISITE" = "yes" ] ; then
@@ -171,7 +175,7 @@ fi
# request limiting # request limiting
if [ "$(has_value USE_LIMIT_REQ yes)" != "" ] ; then if [ "$(has_value USE_LIMIT_REQ yes)" != "" ] ; then
replace_in_file "/etc/nginx/nginx.conf" "%LIMIT_REQ_ZONE%" "limit_req_zone \$binary_remote_addr zone=limit:${LIMIT_REQ_CACHE} rate=${LIMIT_REQ_RATE};" replace_in_file "/etc/nginx/nginx.conf" "%LIMIT_REQ_ZONE%" "limit_req_zone \$binary_remote_addr\$uri zone=limit:${LIMIT_REQ_CACHE} rate=${LIMIT_REQ_RATE};"
else else
replace_in_file "/etc/nginx/nginx.conf" "%LIMIT_REQ_ZONE%" "" replace_in_file "/etc/nginx/nginx.conf" "%LIMIT_REQ_ZONE%" ""
fi fi

View File

@@ -19,3 +19,10 @@ touch /var/log/jobs.log
replace_in_file "/etc/logrotate.conf" "%LOGROTATE_MAXAGE%" "$LOGROTATE_MAXAGE" replace_in_file "/etc/logrotate.conf" "%LOGROTATE_MAXAGE%" "$LOGROTATE_MAXAGE"
replace_in_file "/etc/logrotate.conf" "%LOGROTATE_MINSIZE%" "$LOGROTATE_MINSIZE" replace_in_file "/etc/logrotate.conf" "%LOGROTATE_MINSIZE%" "$LOGROTATE_MINSIZE"
echo "$LOGROTATE_CRON /opt/scripts/logrotate.sh > /dev/null 2>&1" >> /etc/crontabs/nginx echo "$LOGROTATE_CRON /opt/scripts/logrotate.sh > /dev/null 2>&1" >> /etc/crontabs/nginx
# setup rsyslog
if [ "$REMOTE_SYSLOG" != "" ] ; then
replace_in_file "/etc/rsyslog.conf" "%REMOTE_SYSLOG%" "local0.* @${REMOTE_SYSLOG};rawFormat"
else
replace_in_file "/etc/rsyslog.conf" "%REMOTE_SYSLOG%" ""
fi

View File

@@ -38,3 +38,9 @@ if [ "$(has_value USE_CROWDSEC yes)" != "" ] ; then
replace_in_file "/usr/local/lib/lua/crowdsec/crowdsec.conf" "%CROWDSEC_HOST%" "$CROWDSEC_HOST" replace_in_file "/usr/local/lib/lua/crowdsec/crowdsec.conf" "%CROWDSEC_HOST%" "$CROWDSEC_HOST"
replace_in_file "/usr/local/lib/lua/crowdsec/crowdsec.conf" "%CROWDSEC_KEY%" "$CROWDSEC_KEY" replace_in_file "/usr/local/lib/lua/crowdsec/crowdsec.conf" "%CROWDSEC_KEY%" "$CROWDSEC_KEY"
fi fi
# Whitelist IP for API
if [ "$USE_API" = "yes" ] ; then
list=$(spaces_to_lua "$API_WHITELIST_IP")
replace_in_file "/usr/local/lib/lua/api.lua" "%API_WHITELIST_IP%" "$list"
fi

View File

@@ -14,7 +14,8 @@ if [ "$MULTISITE" = "yes" ] ; then
fi fi
SERVER_PREFIX="/etc/nginx/${server}/" SERVER_PREFIX="/etc/nginx/${server}/"
if grep "/etc/letsencrypt/live" ${SERVER_PREFIX}https.conf > /dev/null && [ ! -f /etc/letsencrypt/live/${server}/fullchain.pem ] ; then if grep "/etc/letsencrypt/live" ${SERVER_PREFIX}https.conf > /dev/null && [ ! -f /etc/letsencrypt/live/${server}/fullchain.pem ] ; then
/opt/scripts/certbot-new.sh "$server" "$(cat ${SERVER_PREFIX}email-lets-encrypt.txt)" domains=$(cat ${SERVER_PREFIX}server.conf | sed -nE 's/^.*server_name (.*);$/\1/p' | sed "s/ /,/g")
/opt/scripts/certbot-new.sh "$domains" "$(cat ${SERVER_PREFIX}email-lets-encrypt.txt)"
fi fi
if grep "modsecurity.conf" ${SERVER_PREFIX}server.conf > /dev/null ; then if grep "modsecurity.conf" ${SERVER_PREFIX}server.conf > /dev/null ; then
modsec_custom="" modsec_custom=""

View File

@@ -0,0 +1,25 @@
#!/bin/bash
# /etc/letsencrypt
if [ ! -r "/etc/letsencrypt" ] || [ ! -x "/etc/letsencrypt" ] ; then
echo "[!] WARNING - wrong permissions on /etc/letsencrypt"
exit 1
fi
# /www
if [ ! -r "/www" ] || [ ! -x "/www" ] ; then
echo "[!] ERROR - wrong permissions on /www"
exit 2
fi
# /etc/nginx
if [ ! -r "/etc/nginx" ] || [ ! -x "/etc/nginx" ] ; then
echo "[!] ERROR - wrong permissions on /etc/nginx"
exit 3
fi
# /acme-challenge
if [ ! -r "/acme-challenge" ] || [ ! -x "/acme-challenge" ] ; then
echo "[!] ERROR - wrong permissions on /acme-challenge"
exit 4
fi

29
entrypoint/permissions.sh Normal file
View File

@@ -0,0 +1,29 @@
#!/bin/bash
# /etc/letsencrypt
if [ ! -w "/etc/letsencrypt" ] || [ ! -r "/etc/letsencrypt" ] || [ ! -x "/etc/letsencrypt" ] ; then
echo "[!] WARNING - wrong permissions on /etc/letsencrypt"
exit 1
fi
if [ -f "/usr/sbin/nginx" ] ; then
# /www
if [ ! -r "/www" ] || [ ! -x "/www" ] ; then
echo "[!] ERROR - wrong permissions on /www"
exit 2
fi
fi
# /acme-challenge
if [ ! -w "/acme-challenge" ] || [ ! -r "/acme-challenge" ] || [ ! -x "/acme-challenge" ] ; then
echo "[!] ERROR - wrong permissions on /acme-challenge"
exit 3
fi
# /etc/nginx
if [ ! -w "/etc/nginx" ] || [ ! -r "/etc/nginx" ] || [ ! -x "/etc/nginx" ] ; then
echo "[!] ERROR - wrong permissions on /etc/nginx"
exit 4
fi

View File

@@ -9,16 +9,14 @@
# get nginx path and override multisite variables # get nginx path and override multisite variables
NGINX_PREFIX="/etc/nginx/" NGINX_PREFIX="/etc/nginx/"
if [ "$MULTISITE" = "yes" ] ; then if [ "$MULTISITE" = "yes" ] ; then
NGINX_PREFIX="${NGINX_PREFIX}${1}/" first_server=$(echo "$1" | cut -d ' ' -f 1)
NGINX_PREFIX="${NGINX_PREFIX}${first_server}/"
if [ ! -d "$NGINX_PREFIX" ] ; then if [ ! -d "$NGINX_PREFIX" ] ; then
mkdir "$NGINX_PREFIX" mkdir "$NGINX_PREFIX"
fi fi
ROOT_FOLDER="${ROOT_FOLDER}/$1" ROOT_FOLDER="${ROOT_FOLDER}/$first_server"
fi for var in $(env | cut -d '=' -f 1 | grep -E "^${first_server}_") ; do
repl_name=$(echo "$var" | sed "s~${first_server}_~~")
if [ "$MULTISITE" = "yes" ] ; then
for var in $(env | cut -d '=' -f 1 | grep -E "^${1}_") ; do
repl_name=$(echo "$var" | sed "s~${1}_~~")
repl_value=$(env | grep -E "^${var}=" | sed "s~^${var}=~~") repl_value=$(env | grep -E "^${var}=" | sed "s~^${var}=~~")
read -r "$repl_name" <<< $repl_value read -r "$repl_name" <<< $repl_value
done done
@@ -27,9 +25,9 @@ fi
set | grep -E -v "^(HOSTNAME|PWD|PKG_RELEASE|NJS_VERSION|SHLVL|PATH|_|NGINX_VERSION|HOME)=" > "${NGINX_PREFIX}nginx.env" set | grep -E -v "^(HOSTNAME|PWD|PKG_RELEASE|NJS_VERSION|SHLVL|PATH|_|NGINX_VERSION|HOME)=" > "${NGINX_PREFIX}nginx.env"
if [ "$MULTISITE" = "yes" ] ; then if [ "$MULTISITE" = "yes" ] ; then
for server in $SERVER_NAME ; do for server in $SERVER_NAME ; do
sed -i "~^${server}_.*=.*~d" "${NGINX_PREFIX}nginx.env" sed -i "/^${server}_.*=.*/d" "${NGINX_PREFIX}nginx.env"
done done
sed -i "~^SERVER_NAME=.*~SERVER_NAME=${1}~" "${NGINX_PREFIX}nginx.env" sed -i "s~^SERVER_NAME=.*~SERVER_NAME=${1}~" "${NGINX_PREFIX}nginx.env"
fi fi
# copy stub confs # copy stub confs
@@ -38,8 +36,8 @@ cp /opt/confs/site/* "$NGINX_PREFIX"
# replace paths # replace paths
replace_in_file "${NGINX_PREFIX}server.conf" "%MAIN_LUA%" "include ${NGINX_PREFIX}main-lua.conf;" replace_in_file "${NGINX_PREFIX}server.conf" "%MAIN_LUA%" "include ${NGINX_PREFIX}main-lua.conf;"
if [ "$MULTISITE" = "yes" ] ; then if [ "$MULTISITE" = "yes" ] ; then
replace_in_file "${NGINX_PREFIX}server.conf" "%SERVER_CONF%" "include /server-confs/*.conf;\ninclude /server-confs/${1}/*.conf;" replace_in_file "${NGINX_PREFIX}server.conf" "%SERVER_CONF%" "include /server-confs/*.conf;\ninclude /server-confs/${first_server}/*.conf;"
replace_in_file "${NGINX_PREFIX}server.conf" "%PRE_SERVER_CONF%" "include /pre-server-confs/*.conf;\ninclude /pre-server-confs/${1}/*.conf;" replace_in_file "${NGINX_PREFIX}server.conf" "%PRE_SERVER_CONF%" "include /pre-server-confs/*.conf;\ninclude /pre-server-confs/${first_server}/*.conf;"
else else
replace_in_file "${NGINX_PREFIX}server.conf" "%SERVER_CONF%" "include /server-confs/*.conf;" replace_in_file "${NGINX_PREFIX}server.conf" "%SERVER_CONF%" "include /server-confs/*.conf;"
replace_in_file "${NGINX_PREFIX}server.conf" "%PRE_SERVER_CONF%" "include /pre-server-confs/*.conf;" replace_in_file "${NGINX_PREFIX}server.conf" "%PRE_SERVER_CONF%" "include /pre-server-confs/*.conf;"
@@ -69,8 +67,8 @@ if [ "$USE_REVERSE_PROXY" = "yes" ] ; then
if [ "$custom_headers_value" != "" ] ; then if [ "$custom_headers_value" != "" ] ; then
IFS_=$IFS IFS_=$IFS
IFS=';' IFS=';'
for header_value in $(echo "$custom_headers_value") ; do for header_value in $(echo $custom_headers_value) ; do
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_CUSTOM_HEADERS%" "more_set_headers $header_value;\n%REVERSE_PROXY_CUSTOM_HEADERS%" replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_CUSTOM_HEADERS%" "proxy_set_header $header_value;\n%REVERSE_PROXY_CUSTOM_HEADERS%"
done done
IFS=$IFS_ IFS=$IFS_
fi fi
@@ -288,6 +286,14 @@ else
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%WHITELIST_USER_AGENT%" "" replace_in_file "${NGINX_PREFIX}main-lua.conf" "%WHITELIST_USER_AGENT%" ""
fi fi
# whitelist URI
if [ "$WHITELIST_URI" != "" ] ; then
list=$(spaces_to_lua "$WHITELIST_URI")
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%WHITELIST_URI%" "$list"
else
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%WHITELIST_URI%" ""
fi
# block bad referrer # block bad referrer
if [ "$BLOCK_REFERRER" = "yes" ] ; then if [ "$BLOCK_REFERRER" = "yes" ] ; then
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_REFERRER%" "true" replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_REFERRER%" "true"
@@ -343,8 +349,8 @@ if [ "$AUTO_LETS_ENCRYPT" = "yes" ] || [ "$USE_CUSTOM_HTTPS" = "yes" ] || [ "$GE
if [ "$MULTISITE" = "no" ] ; then if [ "$MULTISITE" = "no" ] ; then
FIRST_SERVER_NAME=$(echo "$SERVER_NAME" | cut -d " " -f 1) FIRST_SERVER_NAME=$(echo "$SERVER_NAME" | cut -d " " -f 1)
else else
FIRST_SERVER_NAME="$1" FIRST_SERVER_NAME="$first_server"
EMAIL_LETS_ENCRYPT="${EMAIL_LETS_ENCRYPT-contact@$1}" EMAIL_LETS_ENCRYPT="${EMAIL_LETS_ENCRYPT-contact@$first_server}"
echo -n "$EMAIL_LETS_ENCRYPT" > ${NGINX_PREFIX}email-lets-encrypt.txt echo -n "$EMAIL_LETS_ENCRYPT" > ${NGINX_PREFIX}email-lets-encrypt.txt
fi fi
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_CERT%" "/etc/letsencrypt/live/${FIRST_SERVER_NAME}/fullchain.pem" replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_CERT%" "/etc/letsencrypt/live/${FIRST_SERVER_NAME}/fullchain.pem"

View File

@@ -20,7 +20,6 @@ services:
- DISABLE_DEFAULT_SERVER=yes - DISABLE_DEFAULT_SERVER=yes
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
labels: labels:
- "bunkerized-nginx.AUTOCONF" - "bunkerized-nginx.AUTOCONF"

View File

@@ -18,8 +18,8 @@ services:
- REDIRECT_HTTP_TO_HTTPS=yes - REDIRECT_HTTP_TO_HTTPS=yes
- DISABLE_DEFAULT_SERVER=yes - DISABLE_DEFAULT_SERVER=yes
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_PROXY_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- USE_REVERSE_PROXY=yes - USE_REVERSE_PROXY=yes
labels: labels:
- "bunkerized-nginx.AUTOCONF" - "bunkerized-nginx.AUTOCONF"

View File

@@ -18,7 +18,6 @@ services:
- DISABLE_DEFAULT_SERVER=yes - DISABLE_DEFAULT_SERVER=yes
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- REMOTE_PHP=myphp - REMOTE_PHP=myphp
- REMOTE_PHP_PATH=/app - REMOTE_PHP_PATH=/app

View File

@@ -23,7 +23,6 @@ services:
- PROXY_REAL_IP=yes - PROXY_REAL_IP=yes
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- REMOTE_PHP=myphp1 - REMOTE_PHP=myphp1
- REMOTE_PHP_PATH=/app - REMOTE_PHP_PATH=/app
labels: labels:
@@ -41,7 +40,6 @@ services:
- PROXY_REAL_IP=yes - PROXY_REAL_IP=yes
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- REMOTE_PHP=myphp2 - REMOTE_PHP=myphp2
- REMOTE_PHP_PATH=/app - REMOTE_PHP_PATH=/app
labels: labels:

View File

@@ -0,0 +1,26 @@
#!/bin/sh
# you need to run it before starting bunkerized-nginx
# since it's manual there is no auto renew, you need to run it again before it expires
DOMAIN="*.website.com"
SERVICE="mywww"
# ask for wildcard certificate
# it's interactive and you will need to add a DNS entry
docker run --rm -it -v "${PWD}/letsencrypt:/etc/letsencrypt" certbot/certbot certonly --manual -d $DOMAIN --agree-tos
if [ $? -ne 0 ] ; then
echo "error while getting certificate for $DOMAIN"
exit 1
fi
# fix permissions
chown -R 101:101 "${PWD}/letsencrypt"
# reload nginx if it's already running (in case of a "renew")
if [ -z `docker-compose ps -q $SERVICE` ] || [ -z `docker ps -q --no-trunc | grep $(docker-compose ps -q $SERVICE)` ]; then
echo "bunkerized-nginx is not running, skipping nginx reload"
else
echo "bunkerized-nginx is running, sending reload order"
docker-compose exec $SERVICE nginx -s reload
fi

View File

@@ -0,0 +1,39 @@
version: '3'
services:
mywww:
image: bunkerity/bunkerized-nginx
restart: always
ports:
- 80:8080
- 443:8443
volumes:
- ./web-files:/www:ro
- ./letsencrypt:/letsencrypt:ro
environment:
- SERVER_NAME=app1.website.com app2.website.com # replace with your domains
- MULTISITE=yes
- USE_CUSTOM_HTTPS=yes
- CUSTOM_HTTPS_CERT=/letsencrypt/live/website.com/fullchain.pem
- CUSTOM_HTTPS_KEY=/letsencrypt/live/website.com/privkey.pem
- REDIRECT_HTTP_TO_HTTPS=yes
- DISABLE_DEFAULT_SERVER=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes
- app1.website.com_REMOTE_PHP=myapp1
- app1.website.com_REMOTE_PHP_PATH=/app
- app2.website.com_REMOTE_PHP=myapp2
- app2.website.com_REMOTE_PHP_PATH=/app
myapp1:
image: php:fpm
restart: always
volumes:
- ./web-files/app1.website.com:/app
myapp2:
image: php:fpm
restart: always
volumes:
- ./web-files/app2.website.com:/app

View File

@@ -0,0 +1,5 @@
<?php
echo "hello from app1 !";
?>

View File

@@ -0,0 +1,5 @@
<?php
echo "hello from app2 !";
?>

View File

@@ -1,3 +1,23 @@
#!/bin/sh #!/bin/sh
# first, you need to run the crowdsec service
echo "running crowdsec service ..."
docker-compose up -d mycrowdsec
# wait a little until it's up
sleep 10
# get the bouncer key
docker-compose exec mycrowdsec cscli bouncers add MyBouncer docker-compose exec mycrowdsec cscli bouncers add MyBouncer
# enter the key into the CROWDSEC_KEY environment variable
read -p -s "edit CROWDSEC_KEY env var in docker-compose.yml file and press enter"
# start all services
docker-compose up -d
# wait a little until it's up
sleep 10
# restart crowdsec so it reads the log files
docker-compose restart mycrowdsec

View File

@@ -20,7 +20,6 @@ services:
- DISABLE_DEFAULT_SERVER=yes - DISABLE_DEFAULT_SERVER=yes
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- USE_CROWDSEC=yes - USE_CROWDSEC=yes
- CROWDSEC_HOST=http://mycrowdsec:8080 - CROWDSEC_HOST=http://mycrowdsec:8080
- CROWDSEC_KEY= # you need to generate it (see bouncer_key.sh) - CROWDSEC_KEY= # you need to generate it (see bouncer_key.sh)
@@ -34,7 +33,7 @@ services:
- net2 - net2
mycrowdsec: mycrowdsec:
image: crowdsecurity/crowdsec:v1.0.2 image: crowdsecurity/crowdsec:v1.0.13
restart: always restart: always
volumes: volumes:
- ./acquis.yaml:/etc/crowdsec/acquis.yaml - ./acquis.yaml:/etc/crowdsec/acquis.yaml

View File

@@ -0,0 +1,30 @@
version: '3'
services:
myreverse:
image: bunkerity/bunkerized-nginx
restart: always
ports:
- 80:8080
- 443:8443
volumes:
- ./letsencrypt:/etc/letsencrypt
environment:
- SERVER_NAME=www.website.com # replace with your domain
- SERVE_FILES=no
- DISABLE_DEFAULT_SERVER=yes
- REDIRECT_HTTP_TO_HTTPS=yes
- AUTO_LETS_ENCRYPT=yes
- USE_PROXY_CACHE=yes
- USE_GZIP=yes
- USE_REVERSE_PROXY=yes
- REVERSE_PROXY_URL=/
- REVERSE_PROXY_HOST=http://myghost:2368/
myghost:
image: ghost:alpine
volumes:
- ./data-ghost:/var/lib/ghost/content
environment:
- url=https://www.website.com # replace with your domain

View File

@@ -0,0 +1,30 @@
version: '3'
services:
myreverse:
image: bunkerity/bunkerized-nginx
restart: always
ports:
- 80:8080
- 443:8443
volumes:
- ./letsencrypt:/etc/letsencrypt
- ./modsec-crs-confs:/modsec-crs-confs:ro # fix FP with CRS
environment:
- SERVER_NAME=www.website.com # replace with your domain
- SERVE_FILES=no
- DISABLE_DEFAULT_SERVER=yes
- REDIRECT_HTTP_TO_HTTPS=yes
- AUTO_LETS_ENCRYPT=yes
- USE_PROXY_CACHE=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes
- USE_REVERSE_PROXY=yes
- REVERSE_PROXY_URL=/
- REVERSE_PROXY_HOST=http://mygogs:3000/
mygogs:
image: gogs/gogs
volumes:
- ./data-gogs:/data

View File

@@ -0,0 +1,7 @@
SecAction \
"id:900220,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |multipart/related| |text/xml| |application/xml| |application/soap+xml| |application/x-amf| |application/json| |application/cloudevents+json| |application/cloudevents-batch+json| |application/octet-stream| |application/csp-report| |application/xss-auditor-report| |text/plain| |application/x-git-upload-pack-request| |application/x-git-receive-pack-request|'"

View File

@@ -0,0 +1,45 @@
version: '3'
services:
mywww:
image: bunkerity/bunkerized-nginx
restart: always
ports:
- 80:8080
- 443:8443
volumes:
- ./joomla-files:/www:ro
- ./letsencrypt:/etc/letsencrypt
environment:
- SERVER_NAME=www.website.com # replace with your domain
- AUTO_LETS_ENCRYPT=yes
- REDIRECT_HTTP_TO_HTTPS=yes
- DISABLE_DEFAULT_SERVER=yes
- MAX_CLIENT_SIZE=50m
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes
- REMOTE_PHP=myjoomla
- REMOTE_PHP_PATH=/var/www/html
myjoomla:
image: joomla:fpm-alpine
restart: always
volumes:
- ./joomla-files:/var/www/html
environment:
- JOOMLA_DB_HOST=mydb
- JOOMLA_DB_NAME=joomladb
- JOOMLA_DB_USER=user
- JOOMLA_DB_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD)
mydb:
image: mariadb
restart: always
volumes:
- ./db-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password
- MYSQL_DATABASE=joomladb
- MYSQL_USER=user
- MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match JOOMLA_DB_PASSWORD)

View File

@@ -18,8 +18,8 @@ services:
- REDIRECT_HTTP_TO_HTTPS=yes - REDIRECT_HTTP_TO_HTTPS=yes
- AUTO_LETS_ENCRYPT=yes - AUTO_LETS_ENCRYPT=yes
- USE_PROXY_CACHE=yes - USE_PROXY_CACHE=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- USE_REVERSE_PROXY=yes - USE_REVERSE_PROXY=yes
- REVERSE_PROXY_URL=/ - REVERSE_PROXY_URL=/
- REVERSE_PROXY_HOST=http://app - REVERSE_PROXY_HOST=http://app

View File

@@ -18,8 +18,8 @@ services:
- MAX_CLIENT_SIZE=50m - MAX_CLIENT_SIZE=50m
- SERVE_FILES=no - SERVE_FILES=no
- USE_PROXY_CACHE=yes - USE_PROXY_CACHE=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- USE_REVERSE_PROXY=yes - USE_REVERSE_PROXY=yes
- REVERSE_PROXY_URL=/ - REVERSE_PROXY_URL=/
- REVERSE_PROXY_HOST=https://mymoodle:8443 - REVERSE_PROXY_HOST=https://mymoodle:8443

View File

@@ -19,13 +19,11 @@ services:
- DISABLE_DEFAULT_SERVER=yes - DISABLE_DEFAULT_SERVER=yes
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- app1.website.com_REMOTE_PHP=myapp1 - app1.website.com_REMOTE_PHP=myapp1
- app1.website.com_REMOTE_PHP_PATH=/app - app1.website.com_REMOTE_PHP_PATH=/app
- app2.website.com_REMOTE_PHP=myapp2 - app2.website.com_REMOTE_PHP=myapp2
- app2.website.com_REMOTE_PHP_PATH=/app - app2.website.com_REMOTE_PHP_PATH=/app
- app3.website.com_SERVE_FILES=no - app3.website.com_SERVE_FILES=no
- app3.website.com_USE_CLIENT_CACHE=no
- app3.website.com_USE_PROXY_CACHE=yes - app3.website.com_USE_PROXY_CACHE=yes
- app3.website.com_USE_REVERSE_PROXY=yes - app3.website.com_USE_REVERSE_PROXY=yes
- app3.website.com_REVERSE_PROXY_URL=/ - app3.website.com_REVERSE_PROXY_URL=/

View File

@@ -22,14 +22,13 @@ services:
- DISABLE_DEFAULT_SERVER=yes - DISABLE_DEFAULT_SERVER=yes
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- wp.website.com_REMOTE_PHP=mywp - wp.website.com_REMOTE_PHP=mywp
- wp.website.com_REMOTE_PHP_PATH=/var/www/html - wp.website.com_REMOTE_PHP_PATH=/var/www/html
- nc.website.com_REMOTE_PHP=mync - nc.website.com_REMOTE_PHP=mync
- nc.website.com_REMOTE_PHP_PATH=/var/www/html - nc.website.com_REMOTE_PHP_PATH=/var/www/html
- nc.website.com_LIMIT_REQ_RATE=40r/s - nc.website.com_LIMIT_REQ_RATE=5r/s
- nc.website.com_LIMIT_REQ_BURST=60 - nc.website.com_LIMIT_REQ_BURST=10
- nc.website.com_ALLOWED_METHODS=GET|POST|HEAD|PROPFIND|DELETE|PUT|MKCOL|MOVE|COPY|PROPPATCH|REPORT - nc.website.com_ALLOWED_METHODS=GET|POST|HEAD|COPY|DELETE|LOCK|MKCOL|MOVE|PROPFIND|PROPPATCH|PUT|UNLOCK|OPTIONS
- nc.website.com_X_FRAME_OPTIONS=SAMEORIGIN - nc.website.com_X_FRAME_OPTIONS=SAMEORIGIN
- nc.website.com_FAIL2BAN_STATUS_CODE=400|401|403|405|444 - nc.website.com_FAIL2BAN_STATUS_CODE=400|401|403|405|444
networks: networks:

View File

@@ -1 +1,2 @@
SecRuleRemoveById 921110 SecRuleRemoveById 921110
SecRule REQUEST_FILENAME "@contains /remote.php/webdav" "id:1,ctl:ruleRemoveByTag=OWASP_CRS"

View File

@@ -1 +1,4 @@
SecRule REQUEST_FILENAME "/wp-admin/admin-ajax.php" "id:1,ctl:ruleRemoveByTag=attack-xss,ctl:ruleRemoveByTag=attack-rce"
SecRule REQUEST_FILENAME "/wp-admin/options.php" "id:2,ctl:ruleRemoveByTag=attack-xss"
SecRule REQUEST_FILENAME "^/wp-json/yoast" "id:3,ctl:ruleRemoveById=930120"
SecRuleRemoveById 953120 SecRuleRemoveById 953120

View File

@@ -12,4 +12,4 @@ SecAction \
nolog,\ nolog,\
pass,\ pass,\
t:none,\ t:none,\
setvar:'tx.allowed_methods=GET HEAD POST PROPFIND DELETE PUT MKCOL MOVE COPY PROPPATCH REPORT'" setvar:'tx.allowed_methods=GET POST HEAD COPY DELETE LOCK MKCOL MOVE PROPFIND PROPPATCH PUT UNLOCK OPTIONS'"

View File

@@ -23,16 +23,15 @@ services:
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- REMOTE_PHP=mync - REMOTE_PHP=mync
- REMOTE_PHP_PATH=/var/www/html - REMOTE_PHP_PATH=/var/www/html
- LIMIT_REQ_RATE=40r/s - LIMIT_REQ_RATE=5r/s
- LIMIT_REQ_BURST=60 - LIMIT_REQ_BURST=10
- ALLOWED_METHODS=GET|POST|HEAD|PROPFIND|DELETE|PUT|MKCOL|MOVE|COPY|PROPPATCH|REPORT - ALLOWED_METHODS=GET|POST|HEAD|COPY|DELETE|LOCK|MKCOL|MOVE|PROPFIND|PROPPATCH|PUT|UNLOCK|OPTIONS
- X_FRAME_OPTIONS=SAMEORIGIN - X_FRAME_OPTIONS=SAMEORIGIN
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- FAIL2BAN_STATUS_CODE=400|401|403|405|444 - FAIL2BAN_STATUS_CODE=400|401|403|405|444
mync: mync:
image: nextcloud:20-fpm image: nextcloud:21-fpm
restart: always restart: always
volumes: volumes:
- ./nc-files:/var/www/html - ./nc-files:/var/www/html

View File

@@ -1 +1,2 @@
SecRuleRemoveById 921110 SecRuleRemoveById 921110
SecRule REQUEST_FILENAME "@contains /remote.php/webdav" "id:1,ctl:ruleRemoveByTag=OWASP_CRS"

View File

@@ -12,4 +12,4 @@ SecAction \
nolog,\ nolog,\
pass,\ pass,\
t:none,\ t:none,\
setvar:'tx.allowed_methods=GET HEAD POST PROPFIND DELETE PUT MKCOL MOVE COPY PROPPATCH REPORT'" setvar:'tx.allowed_methods=GET POST HEAD COPY DELETE LOCK MKCOL MOVE PROPFIND PROPPATCH PUT UNLOCK OPTIONS'"

View File

@@ -20,8 +20,8 @@ services:
- ALLOWED_METHODS=GET|POST|HEAD|PUT|DELETE - ALLOWED_METHODS=GET|POST|HEAD|PUT|DELETE
- SERVE_FILES=no - SERVE_FILES=no
- USE_PROXY_CACHE=yes - USE_PROXY_CACHE=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- USE_REVERSE_PROXY=yes - USE_REVERSE_PROXY=yes
- REVERSE_PROXY_URL=/ - REVERSE_PROXY_URL=/
- REVERSE_PROXY_HOST=https://mypassbolt - REVERSE_PROXY_HOST=https://mypassbolt

View File

@@ -20,9 +20,10 @@ services:
- MAX_CLIENT_SIZE=50m - MAX_CLIENT_SIZE=50m
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- REMOTE_PHP=myprestashop - REMOTE_PHP=myprestashop
- REMOTE_PHP_PATH=/var/www/html - REMOTE_PHP_PATH=/var/www/html
- LIMIT_REQ_RATE=5r/s
- LIMIT_REQ_BURST=10
myprestashop: myprestashop:
image: prestashop/prestashop:1.7-fpm image: prestashop/prestashop:1.7-fpm

View File

@@ -0,0 +1,46 @@
version: '3'
services:
myreverse:
image: bunkerity/bunkerized-nginx
restart: always
ports:
- 80:8080
- 443:8443
volumes:
- ./letsencrypt:/etc/letsencrypt
environment:
- SERVER_NAME=www.website.com # replace with your domain
- SERVE_FILES=no
- DISABLE_DEFAULT_SERVER=yes
- REDIRECT_HTTP_TO_HTTPS=yes
- AUTO_LETS_ENCRYPT=yes
- USE_PROXY_CACHE=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes
- USE_REVERSE_PROXY=yes
- REVERSE_PROXY_URL=/
- REVERSE_PROXY_HOST=http://myredmine:3000/
myredmine:
image: redmine
restart: always
volumes:
- ./redmine-data:/usr/src/redmine/files
environment:
- REDMINE_DB_MYSQL=mydb
- REDMINE_DB_DATABASE=redminedb
- REDMINE_DB_USERNAME=user
- REDMINE_DB_PASSWORD=db-user-pwd # replace with a stronger password (must match MYSQL_PASSWORD)
mydb:
image: mariadb
restart: always
volumes:
- ./db-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=db-root-pwd # replace with a stronger password
- MYSQL_DATABASE=redminedb
- MYSQL_USER=user
- MYSQL_PASSWORD=db-user-pwd # replace with a stronger password (must match REDMINE_DB_PASSWORD)

View File

@@ -18,8 +18,8 @@ services:
- REDIRECT_HTTP_TO_HTTPS=yes - REDIRECT_HTTP_TO_HTTPS=yes
- AUTO_LETS_ENCRYPT=yes - AUTO_LETS_ENCRYPT=yes
- USE_PROXY_CACHE=yes - USE_PROXY_CACHE=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- USE_REVERSE_PROXY=yes - USE_REVERSE_PROXY=yes
- app1.website.com_REVERSE_PROXY_URL=/ - app1.website.com_REVERSE_PROXY_URL=/
- app1.website.com_REVERSE_PROXY_HOST=http://app1:3000 - app1.website.com_REVERSE_PROXY_HOST=http://app1:3000

View File

@@ -18,8 +18,8 @@ services:
- REDIRECT_HTTP_TO_HTTPS=yes - REDIRECT_HTTP_TO_HTTPS=yes
- AUTO_LETS_ENCRYPT=yes - AUTO_LETS_ENCRYPT=yes
- USE_PROXY_CACHE=yes - USE_PROXY_CACHE=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- USE_REVERSE_PROXY=yes - USE_REVERSE_PROXY=yes
- REVERSE_PROXY_URL_1=/app1/ - REVERSE_PROXY_URL_1=/app1/
- REVERSE_PROXY_HOST_1=http://app1:3000/ - REVERSE_PROXY_HOST_1=http://app1:3000/

View File

@@ -17,8 +17,8 @@ services:
- REDIRECT_HTTP_TO_HTTPS=yes - REDIRECT_HTTP_TO_HTTPS=yes
- AUTO_LETS_ENCRYPT=yes - AUTO_LETS_ENCRYPT=yes
- USE_PROXY_CACHE=yes - USE_PROXY_CACHE=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- USE_REVERSE_PROXY=yes - USE_REVERSE_PROXY=yes
- REVERSE_PROXY_URL=/ws/ - REVERSE_PROXY_URL=/ws/
- REVERSE_PROXY_HOST=http://myws:8010/ - REVERSE_PROXY_HOST=http://myws:8010/

View File

@@ -32,7 +32,7 @@ services:
mode: host mode: host
protocol: tcp protocol: tcp
volumes: volumes:
- /shared/confs:/etc/nginx:ro - /shared/confs:/etc/nginx
- /shared/letsencrypt:/etc/letsencrypt:ro - /shared/letsencrypt:/etc/letsencrypt:ro
- /shared/acme-challenge:/acme-challenge:ro - /shared/acme-challenge:/acme-challenge:ro
- /shared/www:/www:ro - /shared/www:/www:ro
@@ -45,6 +45,7 @@ services:
- AUTO_LETS_ENCRYPT=yes - AUTO_LETS_ENCRYPT=yes
- REDIRECT_HTTP_TO_HTTPS=yes - REDIRECT_HTTP_TO_HTTPS=yes
- DISABLE_DEFAULT_SERVER=yes - DISABLE_DEFAULT_SERVER=yes
- USE_CLIENT_CACHE=yes
networks: networks:
- net_config - net_config
- net_services - net_services
@@ -86,6 +87,7 @@ services:
- "node.role==worker" - "node.role==worker"
labels: labels:
- "bunkerized-nginx.SERVER_NAME=app2.website.com" - "bunkerized-nginx.SERVER_NAME=app2.website.com"
- "bunkerized-nginx.USE_PROXY_CACHE=yes"
- "bunkerized-nginx.USE_REVERSE_PROXY=yes" - "bunkerized-nginx.USE_REVERSE_PROXY=yes"
- "bunkerized-nginx.REVERSE_PROXY_URL=/" - "bunkerized-nginx.REVERSE_PROXY_URL=/"
- "bunkerized-nginx.REVERSE_PROXY_HOST=http://app2" - "bunkerized-nginx.REVERSE_PROXY_HOST=http://app2"

View File

@@ -17,8 +17,8 @@ services:
- REDIRECT_HTTP_TO_HTTPS=yes - REDIRECT_HTTP_TO_HTTPS=yes
- AUTO_LETS_ENCRYPT=yes - AUTO_LETS_ENCRYPT=yes
- USE_PROXY_CACHE=yes - USE_PROXY_CACHE=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- USE_REVERSE_PROXY=yes - USE_REVERSE_PROXY=yes
- REVERSE_PROXY_URL=/ - REVERSE_PROXY_URL=/
- REVERSE_PROXY_HOST=http://mytomcat:8080/sample/ - REVERSE_PROXY_HOST=http://mytomcat:8080/sample/

View File

@@ -29,7 +29,6 @@ services:
- USE_ANTIBOT=captcha - USE_ANTIBOT=captcha
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- REMOTE_PHP=myphp - REMOTE_PHP=myphp
- REMOTE_PHP_PATH=/app - REMOTE_PHP_PATH=/app

View File

@@ -18,8 +18,8 @@ services:
- AUTO_LETS_ENCRYPT=yes - AUTO_LETS_ENCRYPT=yes
- REDIRECT_HTTP_TO_HTTPS=yes - REDIRECT_HTTP_TO_HTTPS=yes
- DISABLE_DEFAULT_SERVER=yes - DISABLE_DEFAULT_SERVER=yes
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- admin.website.com_SERVE_FILES=no - admin.website.com_SERVE_FILES=no
- admin.website.com_USE_AUTH_BASIC=yes - admin.website.com_USE_AUTH_BASIC=yes
- admin.website.com_AUTH_BASIC_USER=admin # change it to something hard to guess - admin.website.com_AUTH_BASIC_USER=admin # change it to something hard to guess

View File

@@ -13,6 +13,7 @@ services:
- ./letsencrypt:/etc/letsencrypt - ./letsencrypt:/etc/letsencrypt
- ./server-confs:/server-confs:ro # custom confs at server context for permalinks - ./server-confs:/server-confs:ro # custom confs at server context for permalinks
- ./modsec-crs-confs:/modsec-crs-confs:ro # custom Core Rule Set confs to add Wordpress exclusions - ./modsec-crs-confs:/modsec-crs-confs:ro # custom Core Rule Set confs to add Wordpress exclusions
- ./modsec-confs:/modsec-confs:ro # avoid some FP with CRS
environment: environment:
- SERVER_NAME=www.website.com # replace with your domain - SERVER_NAME=www.website.com # replace with your domain
- AUTO_LETS_ENCRYPT=yes - AUTO_LETS_ENCRYPT=yes
@@ -21,7 +22,6 @@ services:
- MAX_CLIENT_SIZE=50m - MAX_CLIENT_SIZE=50m
- USE_CLIENT_CACHE=yes - USE_CLIENT_CACHE=yes
- USE_GZIP=yes - USE_GZIP=yes
- USE_BROTLI=yes
- REMOTE_PHP=mywp - REMOTE_PHP=mywp
- REMOTE_PHP_PATH=/var/www/html - REMOTE_PHP_PATH=/var/www/html

View File

@@ -0,0 +1,4 @@
SecRule REQUEST_FILENAME "/wp-admin/admin-ajax.php" "id:1,ctl:ruleRemoveByTag=attack-xss,ctl:ruleRemoveByTag=attack-rce"
SecRule REQUEST_FILENAME "/wp-admin/options.php" "id:2,ctl:ruleRemoveByTag=attack-xss"
SecRule REQUEST_FILENAME "^/wp-json/yoast" "id:3,ctl:ruleRemoveById=930120"
SecRuleRemoveById 953120

View File

@@ -25,3 +25,5 @@ module(load="imuxsock" SysSock.Name="/tmp/log")
$template rawFormat,"%msg:2:2048%\n" $template rawFormat,"%msg:2:2048%\n"
local0.=notice /var/log/access.log;rawFormat local0.=notice /var/log/access.log;rawFormat
local0.*;local0.!=notice /var/log/error.log;rawFormat local0.*;local0.!=notice /var/log/error.log;rawFormat
%REMOTE_SYSLOG%

View File

@@ -1,5 +1,8 @@
local M = {} local M = {}
local api_list = {} local api_list = {}
local api_whitelist_ip = {%API_WHITELIST_IP%}
local iputils = require "resty.iputils"
local whitelist = iputils.parse_cidrs(api_whitelist_ip)
api_list["^/ping$"] = function () api_list["^/ping$"] = function ()
return true return true
@@ -10,7 +13,7 @@ api_list["^/reload$"] = function ()
end end
function M.is_api_call (api_uri) function M.is_api_call (api_uri)
if ngx.var.request_uri:sub(1, #api_uri) .. "/" == api_uri .. "/" then if iputils.ip_in_cidrs(ngx.var.remote_addr, whitelist) and ngx.var.request_uri:sub(1, #api_uri) .. "/" == api_uri .. "/" then
for uri, code in pairs(api_list) do for uri, code in pairs(api_list) do
if string.match(ngx.var.request_uri:sub(#api_uri + 1), uri) then if string.match(ngx.var.request_uri:sub(#api_uri + 1), uri) then
return true return true

View File

@@ -1,6 +1,8 @@
local M = {} local M = {}
local dns = require "dns" local dns = require "dns"
local iputils = require "resty.iputils"
local ip_list = {%BLACKLIST_IP_LIST%} local ip_list = {%BLACKLIST_IP_LIST%}
local blacklist = iputils.parse_cidrs(ip_list)
local reverse_list = {%BLACKLIST_REVERSE_LIST%} local reverse_list = {%BLACKLIST_REVERSE_LIST%}
local ip = ngx.var.remote_addr local ip = ngx.var.remote_addr
@@ -21,10 +23,10 @@ function M.reverse_cached ()
end end
function M.check_ip () function M.check_ip ()
for k, v in ipairs(ip_list) do if #ip_list > 0 then
if v == ip then if iputils.ip_in_cidrs(ip, blacklist) then
ngx.shared.blacklist_ip_cache:set(ip, "ko", 86400) ngx.shared.blacklist_ip_cache:set(ip, "ko", 86400)
ngx.log(ngx.WARN, "ip " .. ip .. " is in blacklist") ngx.log(ngx.NOTICE, "ip " .. ip .. " is in blacklist")
return true return true
end end
end end
@@ -33,16 +35,18 @@ function M.check_ip ()
end end
function M.check_reverse () function M.check_reverse ()
if #reverse_list > 0 then
local rdns = dns.get_reverse() local rdns = dns.get_reverse()
if rdns ~= "" then if rdns ~= "" then
for k, v in ipairs(reverse_list) do for k, v in ipairs(reverse_list) do
if rdns:sub(-#v) == v then if rdns:sub(-#v) == v then
ngx.shared.blacklist_reverse_cache:set(ip, "ko", 86400) ngx.shared.blacklist_reverse_cache:set(ip, "ko", 86400)
ngx.log(ngx.WARN, "reverse " .. rdns .. " is in blacklist") ngx.log(ngx.NOTICE, "reverse " .. rdns .. " is in blacklist")
return true return true
end end
end end
end end
end
ngx.shared.blacklist_reverse_cache:set(ip, "ok", 86400) ngx.shared.blacklist_reverse_cache:set(ip, "ok", 86400)
return false return false
end end

View File

@@ -20,7 +20,7 @@ function M.check ()
local a,b,c,d = v2:match("([%d]+).([%d]+).([%d]+).([%d]+)") local a,b,c,d = v2:match("([%d]+).([%d]+).([%d]+).([%d]+)")
if a == "127" then if a == "127" then
ngx.shared.dnsbl_cache:set(ip, "ko", 86400) ngx.shared.dnsbl_cache:set(ip, "ko", 86400)
ngx.log(ngx.WARN, "ip " .. ip .. " is in DNSBL " .. v) ngx.log(ngx.NOTICE, "ip " .. ip .. " is in DNSBL " .. v)
return true return true
end end
end end

View File

@@ -1,7 +1,9 @@
local M = {} local M = {}
local dns = require "dns" local dns = require "dns"
local iputils = require "resty.iputils"
local ip_list = {%WHITELIST_IP_LIST%} local ip_list = {%WHITELIST_IP_LIST%}
local reverse_list = {%WHITELIST_REVERSE_LIST%} local reverse_list = {%WHITELIST_REVERSE_LIST%}
local whitelist = iputils.parse_cidrs(ip_list)
local ip = ngx.var.remote_addr local ip = ngx.var.remote_addr
function M.ip_cached_ok () function M.ip_cached_ok ()
@@ -21,10 +23,10 @@ function M.reverse_cached ()
end end
function M.check_ip () function M.check_ip ()
for k, v in ipairs(ip_list) do if #ip_list > 0 then
if v == ip then if iputils.ip_in_cidrs(ip, whitelist) then
ngx.shared.whitelist_ip_cache:set(ip, "ok", 86400) ngx.shared.whitelist_ip_cache:set(ip, "ok", 86400)
ngx.log(ngx.WARN, "ip " .. ip .. " is in whitelist") ngx.log(ngx.NOTICE, "ip " .. ip .. " is in whitelist")
return true return true
end end
end end
@@ -33,6 +35,7 @@ function M.check_ip ()
end end
function M.check_reverse () function M.check_reverse ()
if #reverse_list > 0 then
local rdns = dns.get_reverse() local rdns = dns.get_reverse()
if rdns ~= "" then if rdns ~= "" then
local whitelisted = false local whitelisted = false
@@ -47,12 +50,13 @@ function M.check_reverse ()
for k, v in ipairs(ips) do for k, v in ipairs(ips) do
if v == ip then if v == ip then
ngx.shared.whitelist_reverse_cache:set(ip, "ok", 86400) ngx.shared.whitelist_reverse_cache:set(ip, "ok", 86400)
ngx.log(ngx.WARN, "reverse " .. rdns .. " is in whitelist") ngx.log(ngx.NOTICE, "reverse " .. rdns .. " is in whitelist")
return true return true
end end
end end
end end
end end
end
ngx.shared.whitelist_reverse_cache:set(ip, "ko", 86400) ngx.shared.whitelist_reverse_cache:set(ip, "ko", 86400)
return false return false
end end

View File

@@ -40,6 +40,7 @@ chmod 770 /var/log/letsencrypt
touch /var/log/clamav.log touch /var/log/clamav.log
chown root:nginx /var/log/clamav.log chown root:nginx /var/log/clamav.log
chmod 770 /var/log/clamav.log chmod 770 /var/log/clamav.log
find /var/log -type f -exec chmod 0774 {} \;
# prepare /acme-challenge # prepare /acme-challenge
mkdir /acme-challenge mkdir /acme-challenge
@@ -67,8 +68,11 @@ chown -R root:nginx /var/run/fail2ban /var/lib/fail2ban
chmod -R 770 /var/run/fail2ban /var/lib/fail2ban chmod -R 770 /var/run/fail2ban /var/lib/fail2ban
# prepare /usr/local/lib/lua # prepare /usr/local/lib/lua
chown root:nginx /usr/local/lib/lua chown -R root:nginx /usr/local/lib/lua
chmod 770 /usr/local/lib/lua chmod 770 /usr/local/lib/lua
find /usr/local/lib/lua -type f -name "*.conf" -exec chmod 0760 {} \;
find /usr/local/lib/lua -type f -name "*.lua" -exec chmod 0760 {} \;
find /usr/local/lib/lua -type d -exec chmod 0770 {} \;
# prepare /cache # prepare /cache
mkdir /cache mkdir /cache