Compare commits
104 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
397182f18d | ||
|
|
c5c5fb17b5 | ||
|
|
017a7780fb | ||
|
|
34d9db7a8b | ||
|
|
361c66ca61 | ||
|
|
afc6678855 | ||
|
|
c40fb33175 | ||
|
|
93ad3c0b51 | ||
|
|
ceed904882 | ||
|
|
b8027d2bac | ||
|
|
8d03a14a6a | ||
|
|
d16f4517a4 | ||
|
|
89ca91b3ff | ||
|
|
6a714e2ece | ||
|
|
0d3da03534 | ||
|
|
33163f65b3 | ||
|
|
a2543384cd | ||
|
|
3591715f21 | ||
|
|
95f7ca5b2d | ||
|
|
816fa47cbb | ||
|
|
7756c2df3c | ||
|
|
7509ec2f2c | ||
|
|
6e93575e16 | ||
|
|
ba4c977550 | ||
|
|
781e4c8cbb | ||
|
|
e04c783d1e | ||
|
|
e12b656bd5 | ||
|
|
cae05447d3 | ||
|
|
4b58e22657 | ||
|
|
6b56e21a09 | ||
|
|
544a09e8da | ||
|
|
8386dd4a2a | ||
|
|
f052a25168 | ||
|
|
43750f5536 | ||
|
|
9142afdb54 | ||
|
|
66c4fed791 | ||
|
|
f41846e9d6 | ||
|
|
92cc705b92 | ||
|
|
47fb3a05b3 | ||
|
|
5940f402c7 | ||
|
|
d9ca275d53 | ||
|
|
8353bd9c85 | ||
|
|
d902e2f297 | ||
|
|
1a8b8043c8 | ||
|
|
65120a7e97 | ||
|
|
b093a47554 | ||
|
|
73dbf03c9a | ||
|
|
6ee746236a | ||
|
|
fa935eb6e3 | ||
|
|
cf231e13cb | ||
|
|
d5d699252c | ||
|
|
50f95420b5 | ||
|
|
dc382c3e04 | ||
|
|
0026328f25 | ||
|
|
9023ab5aed | ||
|
|
124474ad66 | ||
|
|
eac9c8f513 | ||
|
|
1ee490de6d | ||
|
|
825e6a747e | ||
|
|
09a984c86b | ||
|
|
fd7afa17b3 | ||
|
|
b9b7fdfcc4 | ||
|
|
58e1d66bc7 | ||
|
|
7026643f8a | ||
|
|
06f688fe97 | ||
|
|
c65b78b1cc | ||
|
|
f9b9b9546f | ||
|
|
b5fe6335c7 | ||
|
|
951f3957fd | ||
|
|
0f520b8914 | ||
|
|
569ad75c42 | ||
|
|
bd7b6af668 | ||
|
|
459bb8ea1c | ||
|
|
208b5acb30 | ||
|
|
59b2fed416 | ||
|
|
a4871a915e | ||
|
|
026783f018 | ||
|
|
8115853453 | ||
|
|
c5f283b00e | ||
|
|
03ce7a6483 | ||
|
|
3f7e2c54b3 | ||
|
|
bb0f46d8af | ||
|
|
c5b32dfc4c | ||
|
|
9a4f96ad18 | ||
|
|
f258426f55 | ||
|
|
119e963612 | ||
|
|
373988670a | ||
|
|
2a956f2cd3 | ||
|
|
15a37a8682 | ||
|
|
3a3d527907 | ||
|
|
e6b5f460c9 | ||
|
|
002e3ed2ba | ||
|
|
7b55acbe8b | ||
|
|
559b7835d4 | ||
|
|
4ea01bd93f | ||
|
|
a73891a3b8 | ||
|
|
26199f52c8 | ||
|
|
5c3f94a84f | ||
|
|
043fcdc136 | ||
|
|
b86ded3d1c | ||
|
|
92569679b6 | ||
|
|
15e74e4860 | ||
|
|
fd0a6412d0 | ||
|
|
419fdfc86e |
26
.github/workflows/autotest-bunkerized-nginx-autoconf.yml
vendored
Normal file
26
.github/workflows/autotest-bunkerized-nginx-autoconf.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: Automatic test on autoconf
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [dev, master]
|
||||||
|
pull_request:
|
||||||
|
branches: [dev, master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Build the image
|
||||||
|
run: docker build -t autotest-autoconf -f autoconf/Dockerfile .
|
||||||
|
- name: Run Trivy security scanner
|
||||||
|
uses: aquasecurity/trivy-action@master
|
||||||
|
with:
|
||||||
|
image-ref: 'autotest-autoconf'
|
||||||
|
format: 'table'
|
||||||
|
exit-code: '1'
|
||||||
|
ignore-unfixed: true
|
||||||
|
severity: 'UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL'
|
||||||
|
|
||||||
|
|
||||||
26
.github/workflows/autotest-bunkerized-nginx-ui.yml
vendored
Normal file
26
.github/workflows/autotest-bunkerized-nginx-ui.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: Automatic test on ui
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [dev, master]
|
||||||
|
pull_request:
|
||||||
|
branches: [dev, master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Build the image
|
||||||
|
run: docker build -t autotest-ui -f ui/Dockerfile .
|
||||||
|
- name: Run Trivy security scanner
|
||||||
|
uses: aquasecurity/trivy-action@master
|
||||||
|
with:
|
||||||
|
image-ref: 'autotest-ui'
|
||||||
|
format: 'table'
|
||||||
|
exit-code: '1'
|
||||||
|
ignore-unfixed: true
|
||||||
|
severity: 'UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL'
|
||||||
|
|
||||||
|
|
||||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.idea/
|
||||||
28
Dockerfile
28
Dockerfile
@@ -6,38 +6,20 @@ RUN chmod +x /tmp/compile.sh && \
|
|||||||
/tmp/compile.sh && \
|
/tmp/compile.sh && \
|
||||||
rm -rf /tmp/*
|
rm -rf /tmp/*
|
||||||
|
|
||||||
COPY crowdsec/install.sh /tmp/install.sh
|
|
||||||
RUN chmod +x /tmp/install.sh && \
|
|
||||||
/tmp/install.sh && \
|
|
||||||
rm -rf /tmp/*
|
|
||||||
|
|
||||||
COPY entrypoint/ /opt/entrypoint
|
COPY entrypoint/ /opt/entrypoint
|
||||||
COPY confs/ /opt/confs
|
COPY confs/ /opt/confs
|
||||||
COPY scripts/ /opt/scripts
|
COPY scripts/ /opt/scripts
|
||||||
COPY fail2ban/ /opt/fail2ban
|
COPY fail2ban/ /opt/fail2ban
|
||||||
COPY logs/ /opt/logs
|
COPY logs/ /opt/logs
|
||||||
COPY lua/ /opt/lua
|
COPY lua/ /opt/lua
|
||||||
COPY crowdsec/ /opt/crowdsec
|
|
||||||
COPY autoconf/ /opt/autoconf
|
|
||||||
|
|
||||||
RUN apk --no-cache add certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua libgd go jq mariadb-connector-c bash brotli py3-pip && \
|
COPY prepare.sh /tmp/prepare.sh
|
||||||
pip3 install docker && \
|
RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh
|
||||||
chmod +x /opt/entrypoint/* /opt/scripts/* /opt/autoconf/autoconf.py && \
|
|
||||||
mkdir /opt/entrypoint.d && \
|
|
||||||
rm -f /var/log/nginx/* && \
|
|
||||||
chown root:nginx /var/log/nginx && \
|
|
||||||
chmod 750 /var/log/nginx && \
|
|
||||||
touch /var/log/nginx/error.log /var/log/nginx/modsec_audit.log && \
|
|
||||||
chown nginx:nginx /var/log/nginx/*.log && \
|
|
||||||
mkdir /acme-challenge && \
|
|
||||||
chown root:nginx /acme-challenge && \
|
|
||||||
chmod 750 /acme-challenge
|
|
||||||
|
|
||||||
# Fix CVE-2020-28928
|
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge
|
||||||
RUN apk --no-cache add "musl-utils>1.1.24-r2"
|
|
||||||
|
|
||||||
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache
|
|
||||||
|
|
||||||
EXPOSE 8080/tcp 8443/tcp
|
EXPOSE 8080/tcp 8443/tcp
|
||||||
|
|
||||||
|
USER nginx
|
||||||
|
|
||||||
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
||||||
|
|||||||
@@ -6,38 +6,20 @@ RUN chmod +x /tmp/compile.sh && \
|
|||||||
/tmp/compile.sh && \
|
/tmp/compile.sh && \
|
||||||
rm -rf /tmp/*
|
rm -rf /tmp/*
|
||||||
|
|
||||||
COPY crowdsec/install.sh /tmp/install.sh
|
|
||||||
RUN chmod +x /tmp/install.sh && \
|
|
||||||
/tmp/install.sh && \
|
|
||||||
rm -rf /tmp/*
|
|
||||||
|
|
||||||
COPY entrypoint/ /opt/entrypoint
|
COPY entrypoint/ /opt/entrypoint
|
||||||
COPY confs/ /opt/confs
|
COPY confs/ /opt/confs
|
||||||
COPY scripts/ /opt/scripts
|
COPY scripts/ /opt/scripts
|
||||||
COPY fail2ban/ /opt/fail2ban
|
COPY fail2ban/ /opt/fail2ban
|
||||||
COPY logs/ /opt/logs
|
COPY logs/ /opt/logs
|
||||||
COPY lua/ /opt/lua
|
COPY lua/ /opt/lua
|
||||||
COPY crowdsec/ /opt/crowdsec
|
|
||||||
COPY autoconf/ /opt/autoconf
|
|
||||||
|
|
||||||
RUN apk --no-cache add certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua libgd go jq mariadb-connector-c bash brotli py3-pip && \
|
COPY prepare.sh /tmp/prepare.sh
|
||||||
pip3 install docker && \
|
RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh
|
||||||
chmod +x /opt/entrypoint/* /opt/scripts/* /opt/autoconf/autoconf.py && \
|
|
||||||
mkdir /opt/entrypoint.d && \
|
|
||||||
rm -f /var/log/nginx/* && \
|
|
||||||
chown root:nginx /var/log/nginx && \
|
|
||||||
chmod 750 /var/log/nginx && \
|
|
||||||
touch /var/log/nginx/error.log /var/log/nginx/modsec_audit.log && \
|
|
||||||
chown nginx:nginx /var/log/nginx/*.log && \
|
|
||||||
mkdir /acme-challenge && \
|
|
||||||
chown root:nginx /acme-challenge && \
|
|
||||||
chmod 750 /acme-challenge
|
|
||||||
|
|
||||||
# Fix CVE-2020-28928
|
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge
|
||||||
RUN apk --no-cache add "musl-utils>1.1.24-r2"
|
|
||||||
|
|
||||||
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache
|
|
||||||
|
|
||||||
EXPOSE 8080/tcp 8443/tcp
|
EXPOSE 8080/tcp 8443/tcp
|
||||||
|
|
||||||
|
USER nginx
|
||||||
|
|
||||||
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
||||||
|
|||||||
@@ -13,38 +13,20 @@ RUN chmod +x /tmp/compile.sh && \
|
|||||||
/tmp/compile.sh && \
|
/tmp/compile.sh && \
|
||||||
rm -rf /tmp/*
|
rm -rf /tmp/*
|
||||||
|
|
||||||
COPY crowdsec/install.sh /tmp/install.sh
|
|
||||||
RUN chmod +x /tmp/install.sh && \
|
|
||||||
/tmp/install.sh && \
|
|
||||||
rm -rf /tmp/*
|
|
||||||
|
|
||||||
COPY entrypoint/ /opt/entrypoint
|
COPY entrypoint/ /opt/entrypoint
|
||||||
COPY confs/ /opt/confs
|
COPY confs/ /opt/confs
|
||||||
COPY scripts/ /opt/scripts
|
COPY scripts/ /opt/scripts
|
||||||
COPY fail2ban/ /opt/fail2ban
|
COPY fail2ban/ /opt/fail2ban
|
||||||
COPY logs/ /opt/logs
|
COPY logs/ /opt/logs
|
||||||
COPY lua/ /opt/lua
|
COPY lua/ /opt/lua
|
||||||
COPY crowdsec/ /opt/crowdsec
|
|
||||||
COPY autoconf/ /opt/autoconf
|
|
||||||
|
|
||||||
RUN apk --no-cache add certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua libgd go jq mariadb-connector-c bash brotli py3-pip && \
|
COPY prepare.sh /tmp/prepare.sh
|
||||||
pip3 install docker && \
|
RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh
|
||||||
chmod +x /opt/entrypoint/* /opt/scripts/* /opt/autoconf/autoconf.py && \
|
|
||||||
mkdir /opt/entrypoint.d && \
|
|
||||||
rm -f /var/log/nginx/* && \
|
|
||||||
chown root:nginx /var/log/nginx && \
|
|
||||||
chmod 750 /var/log/nginx && \
|
|
||||||
touch /var/log/nginx/error.log /var/log/nginx/modsec_audit.log && \
|
|
||||||
chown nginx:nginx /var/log/nginx/*.log && \
|
|
||||||
mkdir /acme-challenge && \
|
|
||||||
chown root:nginx /acme-challenge && \
|
|
||||||
chmod 750 /acme-challenge
|
|
||||||
|
|
||||||
# Fix CVE-2020-28928
|
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge
|
||||||
RUN apk --no-cache add "musl-utils>1.1.24-r2"
|
|
||||||
|
|
||||||
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache
|
|
||||||
|
|
||||||
EXPOSE 8080/tcp 8443/tcp
|
EXPOSE 8080/tcp 8443/tcp
|
||||||
|
|
||||||
|
USER nginx
|
||||||
|
|
||||||
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
||||||
|
|||||||
@@ -13,38 +13,20 @@ RUN chmod +x /tmp/compile.sh && \
|
|||||||
/tmp/compile.sh && \
|
/tmp/compile.sh && \
|
||||||
rm -rf /tmp/*
|
rm -rf /tmp/*
|
||||||
|
|
||||||
COPY crowdsec/install.sh /tmp/install.sh
|
|
||||||
RUN chmod +x /tmp/install.sh && \
|
|
||||||
/tmp/install.sh && \
|
|
||||||
rm -rf /tmp/*
|
|
||||||
|
|
||||||
COPY entrypoint/ /opt/entrypoint
|
COPY entrypoint/ /opt/entrypoint
|
||||||
COPY confs/ /opt/confs
|
COPY confs/ /opt/confs
|
||||||
COPY scripts/ /opt/scripts
|
COPY scripts/ /opt/scripts
|
||||||
COPY fail2ban/ /opt/fail2ban
|
COPY fail2ban/ /opt/fail2ban
|
||||||
COPY logs/ /opt/logs
|
COPY logs/ /opt/logs
|
||||||
COPY lua/ /opt/lua
|
COPY lua/ /opt/lua
|
||||||
COPY crowdsec/ /opt/crowdsec
|
|
||||||
COPY autoconf/ /opt/autoconf
|
|
||||||
|
|
||||||
RUN apk --no-cache add certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua libgd go jq mariadb-connector-c bash brotli py3-pip && \
|
COPY prepare.sh /tmp/prepare.sh
|
||||||
pip3 install docker && \
|
RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh
|
||||||
chmod +x /opt/entrypoint/* /opt/scripts/* /opt/autoconf/autoconf.py && \
|
|
||||||
mkdir /opt/entrypoint.d && \
|
|
||||||
rm -f /var/log/nginx/* && \
|
|
||||||
chown root:nginx /var/log/nginx && \
|
|
||||||
chmod 750 /var/log/nginx && \
|
|
||||||
touch /var/log/nginx/error.log /var/log/nginx/modsec_audit.log && \
|
|
||||||
chown nginx:nginx /var/log/nginx/*.log && \
|
|
||||||
mkdir /acme-challenge && \
|
|
||||||
chown root:nginx /acme-challenge && \
|
|
||||||
chmod 750 /acme-challenge
|
|
||||||
|
|
||||||
# Fix CVE-2020-28928
|
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge
|
||||||
RUN apk --no-cache add "musl-utils>1.1.24-r2"
|
|
||||||
|
|
||||||
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache
|
|
||||||
|
|
||||||
EXPOSE 8080/tcp 8443/tcp
|
EXPOSE 8080/tcp 8443/tcp
|
||||||
|
|
||||||
|
USER nginx
|
||||||
|
|
||||||
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
||||||
|
|||||||
@@ -6,38 +6,20 @@ RUN chmod +x /tmp/compile.sh && \
|
|||||||
/tmp/compile.sh && \
|
/tmp/compile.sh && \
|
||||||
rm -rf /tmp/*
|
rm -rf /tmp/*
|
||||||
|
|
||||||
COPY crowdsec/install.sh /tmp/install.sh
|
|
||||||
RUN chmod +x /tmp/install.sh && \
|
|
||||||
/tmp/install.sh && \
|
|
||||||
rm -rf /tmp/*
|
|
||||||
|
|
||||||
COPY entrypoint/ /opt/entrypoint
|
COPY entrypoint/ /opt/entrypoint
|
||||||
COPY confs/ /opt/confs
|
COPY confs/ /opt/confs
|
||||||
COPY scripts/ /opt/scripts
|
COPY scripts/ /opt/scripts
|
||||||
COPY fail2ban/ /opt/fail2ban
|
COPY fail2ban/ /opt/fail2ban
|
||||||
COPY logs/ /opt/logs
|
COPY logs/ /opt/logs
|
||||||
COPY lua/ /opt/lua
|
COPY lua/ /opt/lua
|
||||||
COPY crowdsec/ /opt/crowdsec
|
|
||||||
COPY autoconf/ /opt/autoconf
|
|
||||||
|
|
||||||
RUN apk --no-cache add certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua libgd go jq mariadb-connector-c bash brotli py3-pip && \
|
COPY prepare.sh /tmp/prepare.sh
|
||||||
pip3 install docker && \
|
RUN chmod +x /tmp/prepare.sh && /tmp/prepare.sh && rm -f /tmp/prepare.sh
|
||||||
chmod +x /opt/entrypoint/* /opt/scripts/* /opt/autoconf/autoconf.py && \
|
|
||||||
mkdir /opt/entrypoint.d && \
|
|
||||||
rm -f /var/log/nginx/* && \
|
|
||||||
chown root:nginx /var/log/nginx && \
|
|
||||||
chmod 750 /var/log/nginx && \
|
|
||||||
touch /var/log/nginx/error.log /var/log/nginx/modsec_audit.log && \
|
|
||||||
chown nginx:nginx /var/log/nginx/*.log && \
|
|
||||||
mkdir /acme-challenge && \
|
|
||||||
chown root:nginx /acme-challenge && \
|
|
||||||
chmod 750 /acme-challenge
|
|
||||||
|
|
||||||
# Fix CVE-2020-28928
|
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache /pre-server-confs /acme-challenge
|
||||||
RUN apk --no-cache add "musl-utils>1.1.24-r2"
|
|
||||||
|
|
||||||
VOLUME /www /http-confs /server-confs /modsec-confs /modsec-crs-confs /cache
|
|
||||||
|
|
||||||
EXPOSE 8080/tcp 8443/tcp
|
EXPOSE 8080/tcp 8443/tcp
|
||||||
|
|
||||||
|
USER nginx
|
||||||
|
|
||||||
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
||||||
|
|||||||
446
README.md
446
README.md
@@ -1,8 +1,16 @@
|
|||||||
# bunkerized-nginx
|
<p align="center">
|
||||||
|
<img src="https://github.com/bunkerity/bunkerized-nginx/blob/master/logo.png?raw=true" width="425" />
|
||||||
|
</p>
|
||||||
|
|
||||||
<img src="https://github.com/bunkerity/bunkerized-nginx/blob/master/logo.png?raw=true" width="425" />
|
<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.0-blue" /> <img src="https://img.shields.io/badge/nginx-1.18.0-blue" /> <img src="https://img.shields.io/github/last-commit/bunkerity/bunkerized-nginx" /> <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/badge/nginx-1.18.0-blue" />
|
||||||
|
<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/docker/cloud/build/bunkerity/bunkerized-nginx" />
|
||||||
|
<a href="https://twitter.com/bunkerity"><img src="https://img.shields.io/twitter/follow/bunkerity?style=social" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
nginx Docker image secure by default.
|
nginx Docker image secure by default.
|
||||||
|
|
||||||
@@ -18,15 +26,15 @@ Non-exhaustive list of features :
|
|||||||
- Block known bad IP with DNSBL and CrowdSec
|
- Block known bad IP with DNSBL and CrowdSec
|
||||||
- Prevent bruteforce attacks with rate limiting
|
- Prevent bruteforce attacks with rate limiting
|
||||||
- Detect bad files with ClamAV
|
- Detect bad files with ClamAV
|
||||||
- Easy to configure with environment variables
|
- Easy to configure with environment variables or web UI
|
||||||
- Automatic configuration with container labels
|
- Automatic configuration with container labels
|
||||||
|
- Docker Swarm support
|
||||||
|
|
||||||
Fooling automated tools/scanners :
|
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" />
|
||||||
|
|
||||||
# Table of contents
|
# Table of contents
|
||||||
- [bunkerized-nginx](#bunkerized-nginx)
|
|
||||||
- [Table of contents](#table-of-contents)
|
- [Table of contents](#table-of-contents)
|
||||||
- [Live demo](#live-demo)
|
- [Live demo](#live-demo)
|
||||||
- [Quickstart guide](#quickstart-guide)
|
- [Quickstart guide](#quickstart-guide)
|
||||||
@@ -37,8 +45,13 @@ Fooling automated tools/scanners :
|
|||||||
* [Behind a reverse proxy](#behind-a-reverse-proxy)
|
* [Behind a reverse proxy](#behind-a-reverse-proxy)
|
||||||
* [Multisite](#multisite)
|
* [Multisite](#multisite)
|
||||||
* [Automatic configuration](#automatic-configuration)
|
* [Automatic configuration](#automatic-configuration)
|
||||||
|
* [Swarm mode](#swarm-mode)
|
||||||
|
* [Web UI](#web-ui)
|
||||||
* [Antibot challenge](#antibot-challenge)
|
* [Antibot challenge](#antibot-challenge)
|
||||||
|
* [Hardening](#hardening)
|
||||||
- [Tutorials and examples](#tutorials-and-examples)
|
- [Tutorials and examples](#tutorials-and-examples)
|
||||||
|
- [Include custom configurations](#include-custom-configurations)
|
||||||
|
- [Cache data](#cache-data)
|
||||||
- [List of environment variables](#list-of-environment-variables)
|
- [List of environment variables](#list-of-environment-variables)
|
||||||
* [nginx](#nginx)
|
* [nginx](#nginx)
|
||||||
+ [Misc](#misc)
|
+ [Misc](#misc)
|
||||||
@@ -64,14 +77,14 @@ Fooling automated tools/scanners :
|
|||||||
+ [Custom whitelisting](#custom-whitelisting)
|
+ [Custom whitelisting](#custom-whitelisting)
|
||||||
+ [Custom blacklisting](#custom-blacklisting)
|
+ [Custom blacklisting](#custom-blacklisting)
|
||||||
+ [Requests limiting](#requests-limiting)
|
+ [Requests limiting](#requests-limiting)
|
||||||
|
+ [Connections limiting](#connections-limiting)
|
||||||
+ [Countries](#countries)
|
+ [Countries](#countries)
|
||||||
* [PHP](#php)
|
* [PHP](#php)
|
||||||
* [Fail2ban](#fail2ban)
|
* [Fail2ban](#fail2ban)
|
||||||
* [ClamAV](#clamav)
|
* [ClamAV](#clamav)
|
||||||
|
* [Logrotate](#logrotate)
|
||||||
|
* [Cron jobs](#cron-jobs)
|
||||||
* [Misc](#misc-2)
|
* [Misc](#misc-2)
|
||||||
- [Include custom configurations](#include-custom-configurations)
|
|
||||||
- [Cache data](#cache-data)
|
|
||||||
- [Create your own image](#create-your-own-image)
|
|
||||||
|
|
||||||
# Live demo
|
# Live demo
|
||||||
You can find a live demo at https://demo-nginx.bunkerity.com.
|
You can find a live demo at https://demo-nginx.bunkerity.com.
|
||||||
@@ -84,7 +97,7 @@ You can find a live demo at https://demo-nginx.bunkerity.com.
|
|||||||
docker run -p 80:8080 -v /path/to/web/files:/www:ro bunkerity/bunkerized-nginx
|
docker run -p 80:8080 -v /path/to/web/files:/www:ro bunkerity/bunkerized-nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
Web files are stored in the /www directory, the container will serve files from there.
|
Web files are stored in the /www directory, the container will serve files from there. Please note that *bunkerized-nginx* doesn't run as root but with an unprivileged user with UID/GID 101 therefore you should set the rights of */path/to/web/files* accordingly.
|
||||||
|
|
||||||
## In combination with PHP
|
## In combination with PHP
|
||||||
|
|
||||||
@@ -117,8 +130,9 @@ docker run -p 80:8080 \
|
|||||||
bunkerity/bunkerized-nginx
|
bunkerity/bunkerized-nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
Certificates are stored in the /etc/letsencrypt directory, you should save it on your local drive.
|
Certificates are stored in the /etc/letsencrypt directory, you should save it on your local drive. Please note that *bunkerized-nginx* doesn't run as root but with an unprivileged user with UID/GID 101 therefore you should set the rights of */where/to/save/certificates* accordingly.
|
||||||
If you don't want your webserver to listen on HTTP add the environment variable `LISTEN_HTTP` with a *no* value. But Let's Encrypt needs the port 80 to be opened so redirecting the port is mandatory.
|
|
||||||
|
If you don't want your webserver to listen on HTTP add the environment variable `LISTEN_HTTP` with a *no* value (e.g. HTTPS only). But Let's Encrypt needs the port 80 to be opened so redirecting the port is mandatory.
|
||||||
|
|
||||||
Here you have three environment variables :
|
Here you have three environment variables :
|
||||||
- `SERVER_NAME` : define the FQDN of your webserver, this is mandatory for Let's Encrypt (www.yourdomain.com should point to your IP address)
|
- `SERVER_NAME` : define the FQDN of your webserver, this is mandatory for Let's Encrypt (www.yourdomain.com should point to your IP address)
|
||||||
@@ -174,10 +188,10 @@ docker run -p 80:8080 \
|
|||||||
-e AUTO_LETS_ENCRYPT=yes \
|
-e AUTO_LETS_ENCRYPT=yes \
|
||||||
-e REDIRECT_HTTP_TO_HTTPS=yes \
|
-e REDIRECT_HTTP_TO_HTTPS=yes \
|
||||||
-e USE_REVERSE_PROXY=yes \
|
-e USE_REVERSE_PROXY=yes \
|
||||||
-e app1.domain.com_PROXY_URL=/ \
|
-e app1.domain.com_REVERSE_PROXY_URL=/ \
|
||||||
-e app1.domain.com_PROXY_HOST=http://myapp1:8000 \
|
-e app1.domain.com_REVERSE_PROXY_HOST=http://myapp1:8000 \
|
||||||
-e app2.domain.com_PROXY_URL=/ \
|
-e app2.domain.com_REVERSE_PROXY_URL=/ \
|
||||||
-e app2.domain.com_PROXY_HOST=http://myapp2:8000 \
|
-e app2.domain.com_REVERSE_PROXY_HOST=http://myapp2:8000 \
|
||||||
bunkerity/bunkerized-nginx
|
bunkerity/bunkerized-nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -215,9 +229,15 @@ The */where/are/web/files* directory should have a structure like this :
|
|||||||
|
|
||||||
## Automatic configuration
|
## Automatic configuration
|
||||||
|
|
||||||
**This feature exposes, for now, a security risk because you need to mount the docker socket inside the container. You can test it but you should not use it in servers facing the internet.**
|
The downside of using environment variables is that you need to recreate a new container each time you want to add or remove a web service. An alternative is to use the *bunkerized-nginx-autoconf* image which listens for Docker events and "automagically" generates the configuration.
|
||||||
|
|
||||||
The downside of using environment variables is that you need to recreate a new container each time you want to add or remove aweb service. An alternative is to tell bunkerized-nginx to listen for Docker events by mounting the socket inside the container :
|
First we need a volume that will store the configurations :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker volume create nginx_conf
|
||||||
|
```
|
||||||
|
|
||||||
|
Then we run bunkerized-nginx with the `bunkerized-nginx.AUTOCONF` label, mount the created volume at /etc/nginx and set some default configurations for our services (e.g. : automatic Let's Encrypt and HTTP to HTTPS redirect) :
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker network create mynet
|
docker network create mynet
|
||||||
@@ -227,17 +247,28 @@ docker run -p 80:8080 \
|
|||||||
--network mynet \
|
--network mynet \
|
||||||
-v /where/to/save/certificates:/etc/letsencrypt \
|
-v /where/to/save/certificates:/etc/letsencrypt \
|
||||||
-v /where/are/web/files:/www:ro \
|
-v /where/are/web/files:/www:ro \
|
||||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
-v nginx_conf:/etc/nginx \
|
||||||
-e SERVER_NAME= \
|
-e SERVER_NAME= \
|
||||||
-e MULTISITE=yes \
|
-e MULTISITE=yes \
|
||||||
-e AUTO_LETS_ENCRYPT=yes \
|
-e AUTO_LETS_ENCRYPT=yes \
|
||||||
-e REDIRECT_HTTP_TO_HTTPS=yes \
|
-e REDIRECT_HTTP_TO_HTTPS=yes \
|
||||||
|
-l bunkerized.nginx.AUTOCONF \
|
||||||
bunkerity/bunkerized-nginx
|
bunkerity/bunkerized-nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
Please note by setting `SERVER_NAME` to nothing bunkerized-nginx won't create any server block.
|
When setting `SERVER_NAME` to nothing bunkerized-nginx won't create any server block (in case we only want automatic configuration).
|
||||||
|
|
||||||
You can now create a new container and use labels to dynamically configure bunkerized-nginx :
|
Once bunkerized-nginx is created, let's setup the autoconf container :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run -v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||||
|
-v nginx_conf:/etc/nginx \
|
||||||
|
bunkerity/bunkerized-nginx-autoconf
|
||||||
|
```
|
||||||
|
|
||||||
|
We can now create a new container and use labels to dynamically configure bunkerized-nginx. Labels for automatic configuration are the same as environment variables but with the "bunkerized-nginx." prefix.
|
||||||
|
|
||||||
|
Here is a PHP example :
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker run --network mynet \
|
docker run --network mynet \
|
||||||
@@ -246,11 +277,158 @@ docker run --network mynet \
|
|||||||
-l bunkerized-nginx.SERVER_NAME=app.domain.com \
|
-l bunkerized-nginx.SERVER_NAME=app.domain.com \
|
||||||
-l bunkerized-nginx.REMOTE_PHP=myapp \
|
-l bunkerized-nginx.REMOTE_PHP=myapp \
|
||||||
-l bunkerized-nginx.REMOTE_PHP_PATH=/app \
|
-l bunkerized-nginx.REMOTE_PHP_PATH=/app \
|
||||||
|
php:fpm
|
||||||
|
```
|
||||||
|
|
||||||
|
And a reverse proxy example :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run --network mynet \
|
||||||
|
--name anotherapp \
|
||||||
|
-l bunkerized-nginx.SERVER_NAME=app2.domain.com \
|
||||||
|
-l bunkerized-nginx.USE_REVERSE_PROXY=yes \
|
||||||
|
-l bunkerized-nginx.REVERSE_PROXY_URL=/ \
|
||||||
|
-l bunkerized-nginx.REVERSE_PROXY_HOST=http://anotherapp
|
||||||
|
tutum/hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
## Swarm mode
|
||||||
|
|
||||||
|
Automatic configuration through labels is also supported in swarm mode. The *bunkerized-nginx-autoconf* is used to listen for Swarm events (e.g. service create/rm) and "automagically" edit configurations files and reload nginx.
|
||||||
|
|
||||||
|
As a use case we will assume the following :
|
||||||
|
- Some managers are also workers (they will only run the *autoconf* container for obvious security reasons)
|
||||||
|
- The bunkerized-nginx service will be deployed on all workers (global mode) so clients can connect to each of them (e.g. load balancing, CDN, edge proxy, ...)
|
||||||
|
- There is a shared folder mounted on managers and workers (e.g. NFS, GlusterFS, CephFS, ...)
|
||||||
|
|
||||||
|
Let's start by creating the network to allow communications between our services :
|
||||||
|
```shell
|
||||||
|
docker network create -d overlay mynet
|
||||||
|
```
|
||||||
|
|
||||||
|
We can now create the *autoconf* service that will listen to swarm events :
|
||||||
|
```shell
|
||||||
|
docker service create --name autoconf \
|
||||||
|
--network mynet \
|
||||||
|
--mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock,ro \
|
||||||
|
--mount type=bind,source=/shared/confs,destination=/etc/nginx \
|
||||||
|
--mount type=bind,source=/shared/letsencrypt,destination=/etc/letsencrypt \
|
||||||
|
--mount type=bind,source=/shared/acme-challenge,destination=/acme-challenge \
|
||||||
|
-e SWARM_MODE=yes \
|
||||||
|
-e API_URI=/ChangeMeToSomethingHardToGuess \
|
||||||
|
--replicas 1 \
|
||||||
|
--constraint node.role==manager \
|
||||||
|
bunkerity/bunkerized-nginx-autoconf
|
||||||
|
```
|
||||||
|
|
||||||
|
**You need to change `API_URI` to something hard to guess since there is no other security mechanism to protect the API at the moment.**
|
||||||
|
|
||||||
|
When *autoconf* is created, it's time for the *bunkerized-nginx* service to be up :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker service create --name nginx \
|
||||||
|
--network mynet \
|
||||||
|
-p published=80,target=8080,mode=host \
|
||||||
|
-p published=443,target=8443,mode=host \
|
||||||
|
--mount type=bind,source=/shared/confs,destination=/etc/nginx \
|
||||||
|
--mount type=bind,source=/shared/letsencrypt,destination=/etc/letsencrypt,ro \
|
||||||
|
--mount type=bind,source=/shared/acme-challenge,destination=/acme-challenge,ro \
|
||||||
|
--mount type=bind,source=/shared/www,destination=/www,ro \
|
||||||
|
-e SWARM_MODE=yes \
|
||||||
|
-e USE_API=yes \
|
||||||
|
-e API_URI=/ChangeMeToSomethingHardToGuess \
|
||||||
|
-e MULTISITE=yes \
|
||||||
|
-e SERVER_NAME= \
|
||||||
|
-e AUTO_LETS_ENCRYPT=yes \
|
||||||
|
-e REDIRECT_HTTP_TO_HTTPS=yes \
|
||||||
|
-l bunkerized-nginx.AUTOCONF \
|
||||||
|
--mode global \
|
||||||
|
--constraint node.role==worker \
|
||||||
|
bunkerity/bunkerized-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
The `API_URI` value must be the same as the one specified for the *autoconf* service.
|
||||||
|
|
||||||
|
We can now create a new service and use labels to dynamically configure bunkerized-nginx. Labels for automatic configuration are the same as environment variables but with the "bunkerized-nginx." prefix.
|
||||||
|
|
||||||
|
Here is a PHP example :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker service create --name myapp \
|
||||||
|
--network mynet \
|
||||||
|
--mount type=bind,source=/shared/www/app.domain.com,destination=/app \
|
||||||
|
-l bunkerized-nginx.SERVER_NAME=app.domain.com \
|
||||||
|
-l bunkerized-nginx.REMOTE_PHP=myapp \
|
||||||
|
-l bunkerized-nginx.REMOTE_PHP_PATH=/app \
|
||||||
|
--constraint node.role==worker \
|
||||||
|
php:fpm
|
||||||
|
```
|
||||||
|
|
||||||
|
And a reverse proxy example :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker service create --name anotherapp \
|
||||||
|
--network mynet \
|
||||||
|
-l bunkerized-nginx.SERVER_NAME=app2.domain.com \
|
||||||
|
-l bunkerized-nginx.USE_REVERSE_PROXY=yes \
|
||||||
|
-l bunkerized-nginx.REVERSE_PROXY_URL=/ \
|
||||||
|
-l bunkerized-nginx.REVERSE_PROXY_HOST=http://anotherapp \
|
||||||
|
--constraint node.role==worker \
|
||||||
|
tutum/hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
## Web UI
|
||||||
|
|
||||||
|
**This feature exposes, for now, a security risk because you need to mount the docker socket inside a container exposing a web application. You can test it but you should not use it in servers facing the internet.**
|
||||||
|
|
||||||
|
A dedicated image, *bunkerized-nginx-ui*, lets you manage bunkerized-nginx instances and services configurations through a web user interface. This feature is still in beta, feel free to open a new issue if you find a bug and/or you have an idea to improve it.
|
||||||
|
|
||||||
|
First we need a volume that will store the configurations :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker volume create nginx_conf
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, we can create the bunkerized-nginx instance with the `bunkerized-nginx.UI` label and a reverse proxy configuration for our web UI :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker network create mynet
|
||||||
|
|
||||||
|
docker run -p 80:8080 \
|
||||||
|
-p 443:8443 \
|
||||||
|
--network mynet \
|
||||||
|
-v nginx_conf:/etc/nginx \
|
||||||
|
-v /where/are/web/files:/www:ro \
|
||||||
|
-v /where/to/save/certificates:/etc/letsencrypt \
|
||||||
|
-e SERVER_NAME=admin.domain.com \
|
||||||
|
-e MULTISITE=yes \
|
||||||
|
-e AUTO_LETS_ENCRYPT=yes \
|
||||||
|
-e REDIRECT_HTTP_TO_HTTPS=yes \
|
||||||
|
-e DISABLE_DEFAULT_SERVER=yes \
|
||||||
|
-e admin.domain.com_SERVE_FILES=no \
|
||||||
|
-e admin.domain.com_USE_AUTH_BASIC=yes \
|
||||||
|
-e admin.domain.com_AUTH_BASIC_USER=admin \
|
||||||
|
-e admin.domain.com_AUTH_BASIC_PASSWORD=password \
|
||||||
|
-e admin.domain.com_USE_REVERSE_PROXY=yes \
|
||||||
|
-e admin.domain.com_REVERSE_PROXY_URL=/webui/ \
|
||||||
|
-e admin.domain.com_REVERSE_PROXY_HOST=http://myui:5000/ \
|
||||||
|
-l bunkerized-nginx.UI \
|
||||||
bunkerity/bunkerized-nginx
|
bunkerity/bunkerized-nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
Labels for automatic configuration are the same as environment variables but with the "bunkerized-nginx." prefix.
|
The `AUTH_BASIC` environment variables let you define a login/password that must be provided before accessing to the web UI. At the moment, there is no authentication mechanism integrated into bunkerized-nginx-ui.
|
||||||
|
|
||||||
|
We can now create the bunkerized-nginx-ui container that will host the web UI behind bunkerized-nginx :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run --network mynet \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||||
|
-v nginx_conf:/etc/nginx \
|
||||||
|
-e ABSOLUTE_URI=https://admin.domain.com/webui/ \
|
||||||
|
bunkerity/bunkerized-nginx-ui
|
||||||
|
```
|
||||||
|
|
||||||
|
After that, the web UI should be accessible from https://admin.domain.com/webui/.
|
||||||
|
|
||||||
## Antibot challenge
|
## Antibot challenge
|
||||||
|
|
||||||
@@ -260,9 +438,53 @@ docker run -p 80:8080 -v /path/to/web/files:/www -e USE_ANTIBOT=captcha bunkerit
|
|||||||
|
|
||||||
When `USE_ANTIBOT` is set to *captcha*, every users visiting your website must complete a captcha before accessing the pages. Others challenges are also available : *cookie*, *javascript* or *recaptcha* (more info [here](#antibot)).
|
When `USE_ANTIBOT` is set to *captcha*, every users visiting your website must complete a captcha before accessing the pages. Others challenges are also available : *cookie*, *javascript* or *recaptcha* (more info [here](#antibot)).
|
||||||
|
|
||||||
|
## Hardening
|
||||||
|
|
||||||
|
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
|
||||||
|
docker run ... --drop-cap=all ... bunkerity/bunkerized-nginx
|
||||||
|
```
|
||||||
|
|
||||||
# Tutorials and examples
|
# Tutorials and examples
|
||||||
|
|
||||||
You will find some docker-compose.yml examples in the [examples directory](https://github.com/bunkerity/bunkerized-nginx/tree/master/examples) and tutorials about bunkerized-nginx in our [blog](https://www.bunkerity.com/category/bunkerized-nginx/).
|
You will find some docker-compose examples in the [examples directory](https://github.com/bunkerity/bunkerized-nginx/tree/master/examples).
|
||||||
|
|
||||||
|
# Include custom configurations
|
||||||
|
Custom configurations files (ending with .conf suffix) can be added in some directory inside the container :
|
||||||
|
- /http-confs : http context
|
||||||
|
- /server-confs : server context
|
||||||
|
- /pre-server-confs : before server context (add map or upstream config for example)
|
||||||
|
|
||||||
|
You just need to use a volume like this :
|
||||||
|
```shell
|
||||||
|
docker run ... -v /path/to/http/confs:/http-confs:ro ... -v /path/to/server/confs:/server-confs:ro ... bunkerity/bunkerized-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
When `MULTISITE` is set to *yes*, .conf files inside the /server-confs directory are loaded by all the server blocks. You can also set custom configuration for a specific server block by adding files in a subdirectory named as the host defined in the `SERVER_NAME` environment variable. Here is an example :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run ... -v /path/to/server/confs:/server-confs:ro ... -e MULTISITE=yes -e "SERVER_NAME=app1.domain.com app2.domain.com" ... bunkerity/bunkerized-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
The */path/to/server/confs* directory should have a structure like this :
|
||||||
|
```
|
||||||
|
/path/to/server/confs
|
||||||
|
├── app1.domain.com
|
||||||
|
│ └── custom.conf
|
||||||
|
│ └── ...
|
||||||
|
└── app2.domain.com
|
||||||
|
└── custom.conf
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
# Cache data
|
||||||
|
|
||||||
|
You can store cached data (blacklists, geoip DB, ...) to avoid downloading them again after a container deletion by mounting a volume on the /cache directory :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run ... -v /path/to/cache:/cache ... bunkerity/bunkerized-nginx
|
||||||
|
```
|
||||||
|
|
||||||
# List of environment variables
|
# List of environment variables
|
||||||
|
|
||||||
@@ -300,7 +522,7 @@ Only the HTTP methods listed here will be accepted by nginx. If not listed, ngin
|
|||||||
`DISABLE_DEFAULT_SERVER`
|
`DISABLE_DEFAULT_SERVER`
|
||||||
Values : *yes* | *no*
|
Values : *yes* | *no*
|
||||||
Default value : *no*
|
Default value : *no*
|
||||||
Context : *global*, *multisite*
|
Context : *global*
|
||||||
If set to yes, nginx will only respond to HTTP request when the Host header match a FQDN specified in the `SERVER_NAME` environment variable.
|
If set to yes, nginx will only respond to HTTP request when the Host header match a FQDN specified in the `SERVER_NAME` environment variable.
|
||||||
For example, it will close the connection if a bot access the site with direct ip.
|
For example, it will close the connection if a bot access the site with direct ip.
|
||||||
|
|
||||||
@@ -318,14 +540,14 @@ Context : *global*
|
|||||||
The IP addresses of the DNS resolvers to use when performing DNS lookups.
|
The IP addresses of the DNS resolvers to use when performing DNS lookups.
|
||||||
|
|
||||||
`ROOT_FOLDER`
|
`ROOT_FOLDER`
|
||||||
Values : *\<any valid path to web files\>
|
Values : *\<any valid path to web files\>*
|
||||||
Default value : */www*
|
Default value : */www*
|
||||||
Context : *global*
|
Context : *global*
|
||||||
The default folder where nginx will search for web files. Don't change it unless you want to make your own image.
|
The default folder where nginx will search for web files. Don't change it unless you want to make your own image.
|
||||||
|
|
||||||
`LOG_FORMAT`
|
`LOG_FORMAT`
|
||||||
Values : *\<any values accepted by the log_format directive\>*
|
Values : *\<any values accepted by the log_format directive\>*
|
||||||
Default value : *$remote_addr - $remote_user $host \[$time_local\] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"*
|
Default value : *$host $remote_addr - $remote_user \[$time_local\] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"*
|
||||||
Context : *global*
|
Context : *global*
|
||||||
The log format used by nginx to generate logs. More info [here](http://nginx.org/en/docs/http/ngx_http_log_module.html#log_format).
|
The log format used by nginx to generate logs. More info [here](http://nginx.org/en/docs/http/ngx_http_log_module.html#log_format).
|
||||||
|
|
||||||
@@ -333,7 +555,7 @@ The log format used by nginx to generate logs. More info [here](http://nginx.org
|
|||||||
Values : *\<any valid port greater than 1024\>*
|
Values : *\<any valid port greater than 1024\>*
|
||||||
Default value : *8080*
|
Default value : *8080*
|
||||||
Context : *global*
|
Context : *global*
|
||||||
The HTTP port number used by nginx and certbot inside the container.
|
The HTTP port number used by nginx inside the container.
|
||||||
|
|
||||||
`HTTPS_PORT`
|
`HTTPS_PORT`
|
||||||
Values : *\<any valid port greater than 1024\>*
|
Values : *\<any valid port greater than 1024\>*
|
||||||
@@ -425,6 +647,14 @@ 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*. Set it to *yes* when the corresponding `REVERSE_PROXY_HOST` is a WebSocket server.
|
||||||
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`
|
||||||
|
Values : *\<list of custom headers separated with a semicolon\>*
|
||||||
|
Examples : Access-Control-Allow-Origin 'https://mydomain.dev'; Custom_Api_Header 'test';
|
||||||
|
Default value : ""
|
||||||
|
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.
|
||||||
|
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`
|
||||||
Values : *yes* | *no*
|
Values : *yes* | *no*
|
||||||
Default value : *no*
|
Default value : *no*
|
||||||
@@ -751,7 +981,7 @@ You can customize the CRS (i.e. : add WordPress exclusions) by adding custom .co
|
|||||||
## Security headers
|
## Security headers
|
||||||
|
|
||||||
`X_FRAME_OPTIONS`
|
`X_FRAME_OPTIONS`
|
||||||
Values : *DENY* | *SAMEORIGIN* | *ALLOW-FROM https://www.website.net* | *ALLOWALL*
|
Values : *DENY* | *SAMEORIGIN* | *ALLOW-FROM https://www.website.net*
|
||||||
Default value : *DENY*
|
Default value : *DENY*
|
||||||
Context : *global*, *multisite*
|
Context : *global*, *multisite*
|
||||||
Policy to be used when the site is displayed through iframe. Can be used to mitigate clickjacking attacks.
|
Policy to be used when the site is displayed through iframe. Can be used to mitigate clickjacking attacks.
|
||||||
@@ -814,7 +1044,7 @@ More info [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Stric
|
|||||||
|
|
||||||
`CONTENT_SECURITY_POLICY`
|
`CONTENT_SECURITY_POLICY`
|
||||||
Values : *\<directive 1\>; \<directive 2\>; ...*
|
Values : *\<directive 1\>; \<directive 2\>; ...*
|
||||||
Default value : *default-src 'self'; frame-ancestors 'self'; form-action 'self'; block-all-mixed-content; sandbox allow-forms allow-same-origin allow-scripts; reflected-xss block; base-uri 'self'; referrer no-referrer*
|
Default value : *object-src 'none'; frame-ancestors 'self'; form-action 'self'; block-all-mixed-content; sandbox allow-forms allow-same-origin allow-scripts allow-popups; base-uri 'self';*
|
||||||
Context : *global*, *multisite*
|
Context : *global*, *multisite*
|
||||||
Policy to be used when loading resources (scripts, forms, frames, ...).
|
Policy to be used when loading resources (scripts, forms, frames, ...).
|
||||||
More info [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy).
|
More info [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy).
|
||||||
@@ -920,7 +1150,19 @@ The list of DNSBL zones to query when `USE_DNSBL` is set to *yes*.
|
|||||||
Values : *yes* | *no*
|
Values : *yes* | *no*
|
||||||
Default value : *no*
|
Default value : *no*
|
||||||
Context : *global*, *multisite*
|
Context : *global*, *multisite*
|
||||||
If set to *yes*, [CrowdSec](https://github.com/crowdsecurity/crowdsec) will be enabled with the [nginx collection](https://hub.crowdsec.net/author/crowdsecurity/collections/nginx). API pulls will be done automaticaly.
|
If set to *yes*, [CrowdSec](https://github.com/crowdsecurity/crowdsec) will be enabled. Please note that you need a CrowdSec instance running see example [here](https://github.com/bunkerity/bunkerized-nginx/tree/master/examples/crowdsec).
|
||||||
|
|
||||||
|
`CROWDSEC_HOST`
|
||||||
|
Values : *\<full URL to the CrowdSec instance API\>*
|
||||||
|
Default value :
|
||||||
|
Context : *global*
|
||||||
|
The full URL to the CrowdSec API.
|
||||||
|
|
||||||
|
`CROWDSEC_KEY`
|
||||||
|
Values : *\<CrowdSec bouncer key\>*
|
||||||
|
Default value :
|
||||||
|
Context : *global*
|
||||||
|
The CrowdSec key given by *cscli bouncer add BouncerName*.
|
||||||
|
|
||||||
### Custom whitelisting
|
### Custom whitelisting
|
||||||
|
|
||||||
@@ -948,6 +1190,12 @@ Default value : *.googlebot.com .google.com .search.msn.com .crawl.yahoot.net .c
|
|||||||
Context : *global*
|
Context : *global*
|
||||||
The list of reverse DNS suffixes to whitelist when `USE_WHITELIST_REVERSE` is set to *yes*. The default list contains suffixes of major search engines.
|
The list of reverse DNS suffixes to whitelist when `USE_WHITELIST_REVERSE` is set to *yes*. The default list contains suffixes of major search engines.
|
||||||
|
|
||||||
|
`WHITELIST_USER_AGENT`
|
||||||
|
Values : *\<list of regexes separated with spaces\>*
|
||||||
|
Default value :
|
||||||
|
Context : *global*, *multisite*
|
||||||
|
Whitelist user agent from being blocked by `BLOCK_USER_AGENT`.
|
||||||
|
|
||||||
### Custom blacklisting
|
### Custom blacklisting
|
||||||
|
|
||||||
`USE_BLACKLIST_IP`
|
`USE_BLACKLIST_IP`
|
||||||
@@ -993,7 +1241,7 @@ The rate limit to apply when `USE_LIMIT_REQ` is set to *yes*. Default is 10 requ
|
|||||||
Values : *<any valid integer\>*
|
Values : *<any valid integer\>*
|
||||||
Default value : *40*
|
Default value : *40*
|
||||||
Context : *global*, *multisite*
|
Context : *global*, *multisite*
|
||||||
The number of of requests to put in queue before rejecting requests.
|
The number of requests to put in queue before rejecting requests.
|
||||||
|
|
||||||
`LIMIT_REQ_CACHE`
|
`LIMIT_REQ_CACHE`
|
||||||
Values : *Xm* | *Xk*
|
Values : *Xm* | *Xk*
|
||||||
@@ -1001,6 +1249,27 @@ Default value : *10m*
|
|||||||
Context : *global*
|
Context : *global*
|
||||||
The size of the cache to store information about request limiting.
|
The size of the cache to store information about request limiting.
|
||||||
|
|
||||||
|
### Connections limiting
|
||||||
|
|
||||||
|
`USE_LIMIT_CONN`
|
||||||
|
Values : *yes* | *no*
|
||||||
|
Default value : *yes*
|
||||||
|
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)
|
||||||
|
More info connections limiting [here](http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html).
|
||||||
|
|
||||||
|
`LIMIT_CONN_MAX`
|
||||||
|
Values : *<any valid integer\>*
|
||||||
|
Default value : *40*
|
||||||
|
Context : *global*, *multisite*
|
||||||
|
The maximum number of connections per ip to put in queue before rejecting requests.
|
||||||
|
|
||||||
|
`LIMIT_CONN_CACHE`
|
||||||
|
Values : *Xm* | *Xk*
|
||||||
|
Default value : *10m*
|
||||||
|
Context : *global*
|
||||||
|
The size of the cache to store information about connection limiting.
|
||||||
|
|
||||||
### Countries
|
### Countries
|
||||||
|
|
||||||
`BLACKLIST_COUNTRY`
|
`BLACKLIST_COUNTRY`
|
||||||
@@ -1063,6 +1332,12 @@ Default : value : *15*
|
|||||||
Context : *global*
|
Context : *global*
|
||||||
The number of "strange" HTTP status codes to find between the time interval.
|
The number of "strange" HTTP status codes to find between the time interval.
|
||||||
|
|
||||||
|
`FAIL2BAN_IGNOREIP`
|
||||||
|
Values : *\<list of IP addresses or subnet separated with spaces\>*
|
||||||
|
Default value : 127.0.0.1/8 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8
|
||||||
|
Context : *global*
|
||||||
|
IPs or subnet which should never be ban by fail2ban.
|
||||||
|
|
||||||
## ClamAV
|
## ClamAV
|
||||||
|
|
||||||
`USE_CLAMAV_UPLOAD`
|
`USE_CLAMAV_UPLOAD`
|
||||||
@@ -1083,13 +1358,7 @@ 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.
|
||||||
|
|
||||||
## Misc
|
## Logrotate
|
||||||
|
|
||||||
`ADDITIONAL_MODULES`
|
|
||||||
Values : *\<list of packages separated with space\>*
|
|
||||||
Default value :
|
|
||||||
Context : *global*
|
|
||||||
You can specify additional modules to install. All [alpine packages](https://pkgs.alpinelinux.org/packages) are valid.
|
|
||||||
|
|
||||||
`LOGROTATE_MINSIZE`
|
`LOGROTATE_MINSIZE`
|
||||||
Values : *x* | *xk* | *xM* | *xG*
|
Values : *x* | *xk* | *xM* | *xG*
|
||||||
@@ -1103,37 +1372,84 @@ Default value : 7
|
|||||||
Context : *global*
|
Context : *global*
|
||||||
The number of days before rotated files are deleted.
|
The number of days before rotated files are deleted.
|
||||||
|
|
||||||
# Include custom configurations
|
## Cron jobs
|
||||||
Custom configurations files (ending with .conf suffix) can be added in some directory inside the container :
|
|
||||||
- /http-confs : http context
|
|
||||||
- /server-confs : server context
|
|
||||||
|
|
||||||
You just need to use a volume like this :
|
`AUTO_LETS_ENCRYPT_CRON`
|
||||||
```shell
|
Values : *\<cron expression\>*
|
||||||
docker run ... -v /path/to/http/confs:/http-confs:ro ... -v /path/to/server/confs:/server-confs:ro ... bunkerity/bunkerized-nginx
|
Default value : *15 0 \* \* \**
|
||||||
```
|
Context : *global*
|
||||||
|
Cron expression of how often certbot will try to renew the certificates.
|
||||||
|
|
||||||
When `MULTISITE` is set to *yes*, .conf files inside the /server-confs directory are loaded by all the server blocks. You can also set custom configuration for a specific server block by adding files in a subdirectory named as the host defined in the `SERVER_NAME` environment variable. Here is an example :
|
`BLOCK_USER_AGENT_CRON`
|
||||||
|
Values : *\<cron expression\>*
|
||||||
|
Default value : *30 0 \* \* \* \**
|
||||||
|
Context : *global*
|
||||||
|
Cron expression of how often the blacklist of user agent is updated.
|
||||||
|
|
||||||
```shell
|
`BLOCK_TOR_EXIT_NODE_CRON`
|
||||||
docker run ... -v /path/to/server/confs:/server-confs:ro ... -e MULTISITE=yes -e "SERVER_NAME=app1.domain.com app2.domain.com" ... bunkerity/bunkerized-nginx
|
Values : *\<cron expression\>*
|
||||||
```
|
Default value : *0 \*/1 \* \* \* \**
|
||||||
|
Context : *global*
|
||||||
|
Cron expression of how often the blacklist of tor exit node is updated.
|
||||||
|
|
||||||
The */path/to/server/confs* directory should have a structure like this :
|
`BLOCK_PROXIES_CRON`
|
||||||
```
|
Values : *\<cron expression\>*
|
||||||
/path/to/server/confs
|
Default value : *0 3 \* \* \* \**
|
||||||
├── app1.domain.com
|
Context : *global*
|
||||||
│ └── custom.conf
|
Cron expression of how often the blacklist of proxies is updated.
|
||||||
│ └── ...
|
|
||||||
└── app2.domain.com
|
|
||||||
└── custom.conf
|
|
||||||
└── ...
|
|
||||||
```
|
|
||||||
|
|
||||||
# Cache data
|
`BLOCK_ABUSERS_CRON`
|
||||||
|
Values : *\<cron expression\>*
|
||||||
|
Default value : *0 2 \* \* \* \**
|
||||||
|
Context : *global*
|
||||||
|
Cron expression of how often the blacklist of abusers is updated.
|
||||||
|
|
||||||
You can store cached data (blacklists, geoip DB, ...) to avoid downloading them again after a container deletion by mounting a volume on the /cache directory :
|
`BLOCK_REFERRER_CRON`
|
||||||
|
Values : *\<cron expression\>*
|
||||||
|
Default value : *45 0 \* \* \* \**
|
||||||
|
Context : *global*
|
||||||
|
Cron expression of how often the blacklist of referrer is updated.
|
||||||
|
|
||||||
```shell
|
`GEOIP_CRON`
|
||||||
docker run ... -v /path/to/cache:/cache ... bunkerity/bunkerized-nginx
|
Values : *\<cron expression\>*
|
||||||
```
|
Default value : *0 4 2 \* \**
|
||||||
|
Context : *global*
|
||||||
|
Cron expression of how often the GeoIP database is updated.
|
||||||
|
|
||||||
|
`USE_CLAMAV_SCAN_CRON`
|
||||||
|
Values : *\<cron expression\>*
|
||||||
|
Default value : *30 1 \* \* \**
|
||||||
|
Context : *global*
|
||||||
|
Cron expression of how often ClamAV will scan all the files inside the container.
|
||||||
|
|
||||||
|
`CLAMAV_UPDATE_CRON`
|
||||||
|
Values : *\<cron expression\>*
|
||||||
|
Default value : *0 1 \* \* \**
|
||||||
|
Context : *global*
|
||||||
|
Cron expression of how often ClamAV will update its database.
|
||||||
|
|
||||||
|
`LOGROTATE_CRON`
|
||||||
|
Values : *\<cron expression\>*
|
||||||
|
Default value : *0 0 \* \* \**
|
||||||
|
Context : *global*
|
||||||
|
Cron expression of how often Logrotate will rotate files.
|
||||||
|
|
||||||
|
## misc
|
||||||
|
|
||||||
|
`SWARM_MODE`
|
||||||
|
Values : *yes* | *no*
|
||||||
|
Default value : *no*
|
||||||
|
Context : *global*
|
||||||
|
Only set to *yes* when you use *bunkerized-nginx* with *autoconf* feature in swarm mode. More info [here](#swarm-mode).
|
||||||
|
|
||||||
|
`USE_API`
|
||||||
|
Values : *yes* | *no*
|
||||||
|
Default value : *no*
|
||||||
|
Context : *global*
|
||||||
|
Only set to *yes* when you use *bunkerized-nginx* with *autoconf* feature in swarm mode. More info [here](#swarm-mode).
|
||||||
|
|
||||||
|
`API_URI`
|
||||||
|
Values : *random* | *\<any valid URI path\>*
|
||||||
|
Default value : *random*
|
||||||
|
Context : *global*
|
||||||
|
Set it to a random path when you use *bunkerized-nginx* with *autoconf* feature in swarm mode. More info [here](#swarm-mode).
|
||||||
|
|||||||
120
autoconf/AutoConf.py
Normal file
120
autoconf/AutoConf.py
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
from Config import Config
|
||||||
|
import utils
|
||||||
|
import os
|
||||||
|
|
||||||
|
class AutoConf :
|
||||||
|
|
||||||
|
def __init__(self, swarm, api) :
|
||||||
|
self.__swarm = swarm
|
||||||
|
self.__servers = {}
|
||||||
|
self.__instances = {}
|
||||||
|
self.__sites = {}
|
||||||
|
self.__config = Config(self.__swarm, api)
|
||||||
|
|
||||||
|
def reload(self) :
|
||||||
|
return self.__config.reload(self.__instances)
|
||||||
|
|
||||||
|
def pre_process(self, objs) :
|
||||||
|
for instance in objs :
|
||||||
|
(id, name, labels) = self.__get_infos(instance)
|
||||||
|
if "bunkerized-nginx.AUTOCONF" in labels :
|
||||||
|
if self.__swarm :
|
||||||
|
self.__process_instance(instance, "create", id, name, labels)
|
||||||
|
else :
|
||||||
|
if instance.status in ("restarting", "running", "created", "exited") :
|
||||||
|
self.__process_instance(instance, "create", id, name, labels)
|
||||||
|
if instance.status == "running" :
|
||||||
|
self.__process_instance(instance, "start", id, name, labels)
|
||||||
|
|
||||||
|
for server in objs :
|
||||||
|
(id, name, labels) = self.__get_infos(server)
|
||||||
|
if "bunkerized-nginx.SERVER_NAME" in labels :
|
||||||
|
if self.__swarm :
|
||||||
|
self.__process_server(server, "create", id, name, labels)
|
||||||
|
else :
|
||||||
|
if server.status in ("restarting", "running", "created", "exited") :
|
||||||
|
self.__process_server(server, "create", id, name, labels)
|
||||||
|
if server.status == "running" :
|
||||||
|
self.__process_server(server, "start", id, name, labels)
|
||||||
|
|
||||||
|
def process(self, obj, event) :
|
||||||
|
(id, name, labels) = self.__get_infos(obj)
|
||||||
|
if "bunkerized-nginx.AUTOCONF" in labels :
|
||||||
|
self.__process_instance(obj, event, id, name, labels)
|
||||||
|
elif "bunkerized-nginx.SERVER_NAME" in labels :
|
||||||
|
self.__process_server(obj, event, id, name, labels)
|
||||||
|
|
||||||
|
def __get_infos(self, obj) :
|
||||||
|
if self.__swarm :
|
||||||
|
id = obj.id
|
||||||
|
name = obj.name
|
||||||
|
labels = obj.attrs["Spec"]["Labels"]
|
||||||
|
else :
|
||||||
|
id = obj.id
|
||||||
|
name = obj.name
|
||||||
|
labels = obj.labels
|
||||||
|
return (id, name, labels)
|
||||||
|
|
||||||
|
def __process_instance(self, instance, event, id, name, labels) :
|
||||||
|
if event == "create" :
|
||||||
|
self.__instances[id] = instance
|
||||||
|
if self.__swarm and len(self.__instances) == 1 :
|
||||||
|
if self.__config.initconf(self.__instances) :
|
||||||
|
utils.log("[*] initial config succeeded")
|
||||||
|
else :
|
||||||
|
utils.log("[!] initial config failed")
|
||||||
|
utils.log("[*] bunkerized-nginx instance created : " + name + " / " + id)
|
||||||
|
elif event == "start" :
|
||||||
|
self.__instances[id].reload()
|
||||||
|
utils.log("[*] bunkerized-nginx instance started : " + name + " / " + id)
|
||||||
|
elif event == "die" :
|
||||||
|
self.__instances[id].reload()
|
||||||
|
utils.log("[*] bunkerized-nginx instance stopped : " + name + " / " + id)
|
||||||
|
elif event == "destroy" or event == "remove" :
|
||||||
|
del self.__instances[id]
|
||||||
|
if self.__swarm and len(self.__instances) == 0 :
|
||||||
|
with open("/etc/crontabs/nginx", "w") as f :
|
||||||
|
f.write("")
|
||||||
|
if os.path.exists("/etc/nginx/autoconf") :
|
||||||
|
os.remove("/etc/nginx/autoconf")
|
||||||
|
utils.log("[*] bunkerized-nginx instance removed : " + name + " / " + id)
|
||||||
|
|
||||||
|
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.")}
|
||||||
|
if event == "create" :
|
||||||
|
if self.__config.generate(self.__instances, vars) :
|
||||||
|
utils.log("[*] Generated config for " + vars["SERVER_NAME"])
|
||||||
|
self.__servers[id] = instance
|
||||||
|
if self.__swarm :
|
||||||
|
if self.__config.activate(self.__instances, vars) :
|
||||||
|
utils.log("[*] Activated config for " + vars["SERVER_NAME"])
|
||||||
|
else :
|
||||||
|
utils.log("[!] Can't activate config for " + vars["SERVER_NAME"])
|
||||||
|
else :
|
||||||
|
utils.log("[!] Can't generate config for " + vars["SERVER_NAME"])
|
||||||
|
elif event == "start" :
|
||||||
|
if id in self.__servers :
|
||||||
|
self.__servers[id].reload()
|
||||||
|
if self.__config.activate(self.__instances, vars) :
|
||||||
|
utils.log("[*] Activated config for " + vars["SERVER_NAME"])
|
||||||
|
else :
|
||||||
|
utils.log("[!] Can't activate config for " + vars["SERVER_NAME"])
|
||||||
|
elif event == "die" :
|
||||||
|
if id in self.__servers :
|
||||||
|
self.__servers[id].reload()
|
||||||
|
if self.__config.deactivate(self.__instances, vars) :
|
||||||
|
utils.log("[*] Deactivated config for " + vars["SERVER_NAME"])
|
||||||
|
else :
|
||||||
|
utils.log("[!] Can't deactivate config for " + vars["SERVER_NAME"])
|
||||||
|
elif event == "destroy" or event == "remove" :
|
||||||
|
if id in self.__servers :
|
||||||
|
if self.__swarm :
|
||||||
|
if self.__config.deactivate(self.__instances, vars) :
|
||||||
|
utils.log("[*] Deactivated config for " + vars["SERVER_NAME"])
|
||||||
|
else :
|
||||||
|
utils.log("[!] Can't deactivate config for " + vars["SERVER_NAME"])
|
||||||
|
del self.__servers[id]
|
||||||
|
if self.__config.remove(vars) :
|
||||||
|
utils.log("[*] Removed config for " + vars["SERVER_NAME"])
|
||||||
|
else :
|
||||||
|
utils.log("[!] Can't remove config for " + vars["SERVER_NAME"])
|
||||||
178
autoconf/Config.py
Normal file
178
autoconf/Config.py
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import utils
|
||||||
|
import subprocess, shutil, os, traceback, requests, time
|
||||||
|
|
||||||
|
class Config :
|
||||||
|
|
||||||
|
def __init__(self, swarm, api) :
|
||||||
|
self.__swarm = swarm
|
||||||
|
self.__api = api
|
||||||
|
|
||||||
|
|
||||||
|
def initconf(self, instances) :
|
||||||
|
try :
|
||||||
|
for instance_id, instance in instances.items() :
|
||||||
|
env = instance.attrs["Spec"]["TaskTemplate"]["ContainerSpec"]["Env"]
|
||||||
|
break
|
||||||
|
vars = {}
|
||||||
|
for var_value in env :
|
||||||
|
var = var_value.split("=")[0]
|
||||||
|
value = var_value.replace(var + "=", "", 1)
|
||||||
|
vars[var] = value
|
||||||
|
if self.globalconf(instances) :
|
||||||
|
i = 0
|
||||||
|
started = False
|
||||||
|
while i < 10 :
|
||||||
|
if self.__ping(instances) :
|
||||||
|
started = True
|
||||||
|
break
|
||||||
|
i = i + 1
|
||||||
|
utils.log("[!] Waiting " + str(i) + " seconds before retrying to contact nginx instances")
|
||||||
|
time.sleep(i)
|
||||||
|
if started :
|
||||||
|
proc = subprocess.run(["/bin/su", "-s", "/opt/entrypoint/jobs.sh", "nginx"], env=vars, capture_output=True)
|
||||||
|
return proc.returncode == 0
|
||||||
|
else :
|
||||||
|
utils.log("[!] bunkerized-nginx instances are not started")
|
||||||
|
else :
|
||||||
|
utils.log("[!] Can't generate global conf")
|
||||||
|
except Exception as e :
|
||||||
|
traceback.print_exc()
|
||||||
|
utils.log("[!] Error while initializing config : " + str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def globalconf(self, instances) :
|
||||||
|
try :
|
||||||
|
for instance_id, instance in instances.items() :
|
||||||
|
env = instance.attrs["Spec"]["TaskTemplate"]["ContainerSpec"]["Env"]
|
||||||
|
break
|
||||||
|
vars = {}
|
||||||
|
for var_value in env :
|
||||||
|
var = var_value.split("=")[0]
|
||||||
|
value = var_value.replace(var + "=", "", 1)
|
||||||
|
vars[var] = value
|
||||||
|
proc = subprocess.run(["/bin/su", "-s", "/opt/entrypoint/global-config.sh", "nginx"], env=vars, capture_output=True)
|
||||||
|
if proc.returncode == 0 :
|
||||||
|
with open("/etc/nginx/autoconf", "w") as f :
|
||||||
|
f.write("ok")
|
||||||
|
return True
|
||||||
|
except Exception as e :
|
||||||
|
traceback.print_exc()
|
||||||
|
utils.log("[!] Error while generating global config : " + str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def generate(self, instances, vars) :
|
||||||
|
try :
|
||||||
|
# Get env vars from bunkerized-nginx instances
|
||||||
|
vars_instances = {}
|
||||||
|
for instance_id, instance in instances.items() :
|
||||||
|
if self.__swarm :
|
||||||
|
env = instance.attrs["Spec"]["TaskTemplate"]["ContainerSpec"]["Env"]
|
||||||
|
else :
|
||||||
|
env = instance.attrs["Config"]["Env"]
|
||||||
|
for var_value in env :
|
||||||
|
var = var_value.split("=")[0]
|
||||||
|
value = var_value.replace(var + "=", "", 1)
|
||||||
|
vars_instances[var] = value
|
||||||
|
vars_defaults = vars.copy()
|
||||||
|
vars_defaults.update(vars_instances)
|
||||||
|
vars_defaults.update(vars)
|
||||||
|
# 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)
|
||||||
|
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)
|
||||||
|
return proc.returncode == 0
|
||||||
|
return proc.returncode == 0
|
||||||
|
except Exception as e :
|
||||||
|
traceback.print_exc()
|
||||||
|
utils.log("[!] Error while generating site config : " + str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def activate(self, instances, vars) :
|
||||||
|
try :
|
||||||
|
# Check if file exists
|
||||||
|
if not os.path.isfile("/etc/nginx/" + vars["SERVER_NAME"] + "/server.conf") :
|
||||||
|
utils.log("[!] /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf doesn't exist")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Include the server conf
|
||||||
|
utils.replace_in_file("/etc/nginx/nginx.conf", "}", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n}")
|
||||||
|
|
||||||
|
return self.reload(instances)
|
||||||
|
except Exception as e :
|
||||||
|
traceback.print_exc()
|
||||||
|
utils.log("[!] Error while activating config : " + str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def deactivate(self, instances, vars) :
|
||||||
|
try :
|
||||||
|
# Check if file exists
|
||||||
|
if not os.path.isfile("/etc/nginx/" + vars["SERVER_NAME"] + "/server.conf") :
|
||||||
|
utils.log("[!] /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf doesn't exist")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Remove the include
|
||||||
|
utils.replace_in_file("/etc/nginx/nginx.conf", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n", "")
|
||||||
|
|
||||||
|
return self.reload(instances)
|
||||||
|
|
||||||
|
except Exception as e :
|
||||||
|
traceback.print_exc()
|
||||||
|
utils.log("[!] Error while deactivating config : " + str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def remove(self, instances, vars) :
|
||||||
|
try :
|
||||||
|
# Check if file exists
|
||||||
|
if not os.path.isfile("/etc/nginx/" + vars["SERVER_NAME"] + "/server.conf") :
|
||||||
|
utils.log("[!] /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf doesn't exist")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Remove the folder
|
||||||
|
shutil.rmtree("/etc/nginx/" + vars["SERVER_NAME"])
|
||||||
|
return True
|
||||||
|
except Exception as e :
|
||||||
|
utils.log("[!] Error while deactivating config : " + str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def reload(self, instances) :
|
||||||
|
return self.__api_call(instances, "/reload")
|
||||||
|
|
||||||
|
def __ping(self, instances) :
|
||||||
|
return self.__api_call(instances, "/ping")
|
||||||
|
|
||||||
|
def __api_call(self, instances, path) :
|
||||||
|
ret = True
|
||||||
|
for instance_id, instance in instances.items() :
|
||||||
|
# Reload the instance object just in case
|
||||||
|
instance.reload()
|
||||||
|
# Reload via API
|
||||||
|
if self.__swarm :
|
||||||
|
# Send POST request on http://serviceName.NodeID.TaskID:8000/reload
|
||||||
|
name = instance.name
|
||||||
|
for task in instance.tasks() :
|
||||||
|
if task["Status"]["State"] != "running" :
|
||||||
|
continue
|
||||||
|
nodeID = task["NodeID"]
|
||||||
|
taskID = task["ID"]
|
||||||
|
fqdn = name + "." + nodeID + "." + taskID
|
||||||
|
req = False
|
||||||
|
try :
|
||||||
|
req = requests.post("http://" + fqdn + ":8080" + self.__api + path)
|
||||||
|
except :
|
||||||
|
pass
|
||||||
|
if req and req.status_code == 200 :
|
||||||
|
utils.log("[*] Sent API order " + path + " to instance " + fqdn + " (service.node.task)")
|
||||||
|
else :
|
||||||
|
utils.log("[!] Can't send API order " + path + " to instance " + fqdn + " (service.node.task)")
|
||||||
|
ret = False
|
||||||
|
# Send SIGHUP to running instance
|
||||||
|
elif instance.status == "running" :
|
||||||
|
try :
|
||||||
|
instance.kill("SIGHUP")
|
||||||
|
utils.log("[*] Sent SIGHUP signal to bunkerized-nginx instance " + instance.name + " / " + instance.id)
|
||||||
|
except docker.errors.APIError as e :
|
||||||
|
utils.log("[!] Docker error while sending SIGHUP signal : " + str(e))
|
||||||
|
ret = False
|
||||||
|
return ret
|
||||||
38
autoconf/Dockerfile
Normal file
38
autoconf/Dockerfile
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
FROM nginx:stable-alpine AS builder
|
||||||
|
|
||||||
|
FROM alpine
|
||||||
|
|
||||||
|
COPY --from=builder /etc/nginx/ /opt/confs/nginx
|
||||||
|
|
||||||
|
RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
|
||||||
|
pip3 install docker requests && \
|
||||||
|
mkdir /opt/entrypoint && \
|
||||||
|
mkdir -p /opt/confs/site && \
|
||||||
|
mkdir -p /opt/confs/global && \
|
||||||
|
mkdir /opt/scripts && \
|
||||||
|
addgroup -g 101 nginx && \
|
||||||
|
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
|
||||||
|
mkdir /var/log/letsencrypt && \
|
||||||
|
chown root:nginx /var/log/letsencrypt && \
|
||||||
|
chmod 770 /var/log/letsencrypt && \
|
||||||
|
mkdir /var/lib/letsencrypt && \
|
||||||
|
chown root:nginx /var/lib/letsencrypt && \
|
||||||
|
chmod 770 /var/lib/letsencrypt && \
|
||||||
|
mkdir /cache && \
|
||||||
|
chown root:nginx /cache && \
|
||||||
|
chmod 770 /cache && \
|
||||||
|
touch /var/log/jobs.log && \
|
||||||
|
chown root:nginx /var/log/jobs.log && \
|
||||||
|
chmod 770 /var/log/jobs.log && \
|
||||||
|
chown -R root:nginx /opt/confs/nginx && \
|
||||||
|
chmod -R 770 /opt/confs/nginx
|
||||||
|
|
||||||
|
COPY autoconf/misc/logrotate.conf /etc/logrotate.conf
|
||||||
|
COPY scripts/* /opt/scripts/
|
||||||
|
COPY confs/site/ /opt/confs/site
|
||||||
|
COPY confs/global/ /opt/confs/global
|
||||||
|
COPY entrypoint/* /opt/entrypoint/
|
||||||
|
COPY autoconf/* /opt/entrypoint/
|
||||||
|
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh /opt/scripts/*.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
||||||
37
autoconf/Dockerfile-amd64
Normal file
37
autoconf/Dockerfile-amd64
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
FROM nginx:stable-alpine AS builder
|
||||||
|
|
||||||
|
FROM amd64/alpine
|
||||||
|
|
||||||
|
COPY --from=builder /etc/nginx/ /opt/confs/nginx
|
||||||
|
|
||||||
|
RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
|
||||||
|
pip3 install docker requests && \
|
||||||
|
mkdir /opt/entrypoint && \
|
||||||
|
mkdir -p /opt/confs/site && \
|
||||||
|
mkdir -p /opt/confs/global && \
|
||||||
|
addgroup -g 101 nginx && \
|
||||||
|
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
|
||||||
|
mkdir /var/log/letsencrypt && \
|
||||||
|
chown root:nginx /var/log/letsencrypt && \
|
||||||
|
chmod 770 /var/log/letsencrypt && \
|
||||||
|
mkdir /var/lib/letsencrypt && \
|
||||||
|
chown root:nginx /var/lib/letsencrypt && \
|
||||||
|
chmod 770 /var/lib/letsencrypt && \
|
||||||
|
mkdir /cache && \
|
||||||
|
chown root:nginx /cache && \
|
||||||
|
chmod 770 /cache && \
|
||||||
|
touch /var/log/jobs.log && \
|
||||||
|
chown root:nginx /var/log/jobs.log && \
|
||||||
|
chmod 770 /var/log/jobs.log && \
|
||||||
|
chown -R root:nginx /opt/confs/nginx && \
|
||||||
|
chmod -R 770 /opt/confs/nginx
|
||||||
|
|
||||||
|
COPY autoconf/misc/logrotate.conf /etc/logrotate.conf
|
||||||
|
COPY scripts/* /opt/scripts/
|
||||||
|
COPY confs/global/ /opt/confs/global
|
||||||
|
COPY confs/site/ /opt/confs/site
|
||||||
|
COPY entrypoint/* /opt/entrypoint/
|
||||||
|
COPY autoconf/* /opt/entrypoint/
|
||||||
|
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh /opt/scripts/*.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
||||||
43
autoconf/Dockerfile-arm32v7
Normal file
43
autoconf/Dockerfile-arm32v7
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
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
|
||||||
|
RUN apk add curl && curl -L ${QEMU_URL} | tar zxvf - -C . --strip-components 1
|
||||||
|
|
||||||
|
FROM nginx:stable-alpine AS builder2
|
||||||
|
|
||||||
|
FROM arm32v7/alpine
|
||||||
|
|
||||||
|
COPY --from=builder qemu-arm-static /usr/bin
|
||||||
|
COPY --from=builder2 /etc/nginx/ /opt/confs/nginx
|
||||||
|
|
||||||
|
RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
|
||||||
|
pip3 install docker requests && \
|
||||||
|
mkdir /opt/entrypoint && \
|
||||||
|
mkdir -p /opt/confs/site && \
|
||||||
|
mkdir -p /opt/confs/global && \
|
||||||
|
addgroup -g 101 nginx && \
|
||||||
|
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
|
||||||
|
mkdir /var/log/letsencrypt && \
|
||||||
|
chown root:nginx /var/log/letsencrypt && \
|
||||||
|
chmod 770 /var/log/letsencrypt && \
|
||||||
|
mkdir /var/lib/letsencrypt && \
|
||||||
|
chown root:nginx /var/lib/letsencrypt && \
|
||||||
|
chmod 770 /var/lib/letsencrypt && \
|
||||||
|
mkdir /cache && \
|
||||||
|
chown root:nginx /cache && \
|
||||||
|
chmod 770 /cache && \
|
||||||
|
touch /var/log/jobs.log && \
|
||||||
|
chown root:nginx /var/log/jobs.log && \
|
||||||
|
chmod 770 /var/log/jobs.log && \
|
||||||
|
chown -R root:nginx /opt/confs/nginx && \
|
||||||
|
chmod -R 770 /opt/confs/nginx
|
||||||
|
|
||||||
|
COPY autoconf/misc/logrotate.conf /etc/logrotate.conf
|
||||||
|
COPY scripts/* /opt/scripts/
|
||||||
|
COPY confs/global/ /opt/confs/global
|
||||||
|
COPY confs/site/ /opt/confs/site
|
||||||
|
COPY entrypoint/* /opt/entrypoint/
|
||||||
|
COPY autoconf/* /opt/entrypoint/
|
||||||
|
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh /opt/scripts/*.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
||||||
43
autoconf/Dockerfile-arm64v8
Normal file
43
autoconf/Dockerfile-arm64v8
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
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
|
||||||
|
RUN apk add curl && curl -L ${QEMU_URL} | tar zxvf - -C . --strip-components 1
|
||||||
|
|
||||||
|
FROM nginx:stable-alpine AS builder2
|
||||||
|
|
||||||
|
FROM arm64v8/alpine
|
||||||
|
|
||||||
|
COPY --from=builder qemu-aarch64-static /usr/bin
|
||||||
|
COPY --from=builder2 /etc/nginx/ /opt/confs/nginx
|
||||||
|
|
||||||
|
RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
|
||||||
|
pip3 install docker requests && \
|
||||||
|
mkdir /opt/entrypoint && \
|
||||||
|
mkdir -p /opt/confs/site && \
|
||||||
|
mkdir -p /opt/confs/global && \
|
||||||
|
addgroup -g 101 nginx && \
|
||||||
|
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
|
||||||
|
mkdir /var/log/letsencrypt && \
|
||||||
|
chown root:nginx /var/log/letsencrypt && \
|
||||||
|
chmod 770 /var/log/letsencrypt && \
|
||||||
|
mkdir /var/lib/letsencrypt && \
|
||||||
|
chown root:nginx /var/lib/letsencrypt && \
|
||||||
|
chmod 770 /var/lib/letsencrypt && \
|
||||||
|
mkdir /cache && \
|
||||||
|
chown root:nginx /cache && \
|
||||||
|
chmod 770 /cache && \
|
||||||
|
touch /var/log/jobs.log && \
|
||||||
|
chown root:nginx /var/log/jobs.log && \
|
||||||
|
chmod 770 /var/log/jobs.log && \
|
||||||
|
chown -R root:nginx /opt/confs/nginx && \
|
||||||
|
chmod -R 770 /opt/confs/nginx
|
||||||
|
|
||||||
|
COPY autoconf/misc/logrotate.conf /etc/logrotate.conf
|
||||||
|
COPY scripts/* /opt/scripts/
|
||||||
|
COPY confs/global/ /opt/confs/global
|
||||||
|
COPY confs/site/ /opt/confs/site
|
||||||
|
COPY entrypoint/* /opt/entrypoint/
|
||||||
|
COPY autoconf/* /opt/entrypoint/
|
||||||
|
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh /opt/scripts/*.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
||||||
37
autoconf/Dockerfile-i386
Normal file
37
autoconf/Dockerfile-i386
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
FROM nginx:stable-alpine AS builder
|
||||||
|
|
||||||
|
FROM i386/alpine
|
||||||
|
|
||||||
|
COPY --from=builder /etc/nginx/ /opt/confs/nginx
|
||||||
|
|
||||||
|
RUN apk add py3-pip apache2-utils bash certbot curl logrotate openssl && \
|
||||||
|
pip3 install docker requests && \
|
||||||
|
mkdir /opt/entrypoint && \
|
||||||
|
mkdir -p /opt/confs/site && \
|
||||||
|
mkdir -p /opt/confs/global && \
|
||||||
|
addgroup -g 101 nginx && \
|
||||||
|
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
|
||||||
|
mkdir /var/log/letsencrypt && \
|
||||||
|
chown root:nginx /var/log/letsencrypt && \
|
||||||
|
chmod 770 /var/log/letsencrypt && \
|
||||||
|
mkdir /var/lib/letsencrypt && \
|
||||||
|
chown root:nginx /var/lib/letsencrypt && \
|
||||||
|
chmod 770 /var/lib/letsencrypt && \
|
||||||
|
mkdir /cache && \
|
||||||
|
chown root:nginx /cache && \
|
||||||
|
chmod 770 /cache && \
|
||||||
|
touch /var/log/jobs.log && \
|
||||||
|
chown root:nginx /var/log/jobs.log && \
|
||||||
|
chmod 770 /var/log/jobs.log && \
|
||||||
|
chown -R root:nginx /opt/confs/nginx && \
|
||||||
|
chmod -R 770 /opt/confs/nginx
|
||||||
|
|
||||||
|
COPY autoconf/misc/logrotate.conf /etc/logrotate.conf
|
||||||
|
COPY scripts/* /opt/scripts/
|
||||||
|
COPY confs/global/ /opt/confs/global
|
||||||
|
COPY confs/site/ /opt/confs/site
|
||||||
|
COPY entrypoint/* /opt/entrypoint/
|
||||||
|
COPY autoconf/* /opt/entrypoint/
|
||||||
|
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh /opt/scripts/*.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/opt/entrypoint/entrypoint.sh"]
|
||||||
28
autoconf/ReloadServer.py
Normal file
28
autoconf/ReloadServer.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import socketserver, threading, utils, os, stat
|
||||||
|
|
||||||
|
class ReloadServerHandler(socketserver.StreamRequestHandler):
|
||||||
|
|
||||||
|
def handle(self) :
|
||||||
|
try :
|
||||||
|
data = self.request.recv(512)
|
||||||
|
if not data :
|
||||||
|
return
|
||||||
|
with self.server.lock :
|
||||||
|
ret = self.server.autoconf.reload()
|
||||||
|
if ret :
|
||||||
|
self.request.sendall("ok".encode("utf-8"))
|
||||||
|
else :
|
||||||
|
self.request.sendall("ko".encode("utf-8"))
|
||||||
|
except Exception as e :
|
||||||
|
utils.log("Exception " + str(e))
|
||||||
|
|
||||||
|
def run_reload_server(autoconf, lock) :
|
||||||
|
server = socketserver.UnixStreamServer("/tmp/autoconf.sock", ReloadServerHandler)
|
||||||
|
os.chown("/tmp/autoconf.sock", 0, 101)
|
||||||
|
os.chmod("/tmp/autoconf.sock", 0o770)
|
||||||
|
server.autoconf = autoconf
|
||||||
|
server.lock = lock
|
||||||
|
thread = threading.Thread(target=server.serve_forever)
|
||||||
|
thread.daemon = True
|
||||||
|
thread.start()
|
||||||
|
return (server, thread)
|
||||||
68
autoconf/app.py
Normal file
68
autoconf/app.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
from AutoConf import AutoConf
|
||||||
|
from ReloadServer import run_reload_server
|
||||||
|
import utils
|
||||||
|
import docker, os, stat, sys, select, threading
|
||||||
|
|
||||||
|
# Connect to the endpoint
|
||||||
|
endpoint = "/var/run/docker.sock"
|
||||||
|
if not os.path.exists(endpoint) or not stat.S_ISSOCK(os.stat(endpoint).st_mode) :
|
||||||
|
utils.log("[!] /var/run/docker.sock not found (is it mounted ?)")
|
||||||
|
sys.exit(1)
|
||||||
|
try :
|
||||||
|
client = docker.DockerClient(base_url='unix:///var/run/docker.sock')
|
||||||
|
except Exception as e :
|
||||||
|
utils.log("[!] Can't instantiate DockerClient : " + str(e))
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
# Check if we are in Swarm mode
|
||||||
|
swarm = os.getenv("SWARM_MODE") == "yes"
|
||||||
|
|
||||||
|
# Our object to process events
|
||||||
|
api = ""
|
||||||
|
if swarm :
|
||||||
|
api = os.getenv("API_URI")
|
||||||
|
autoconf = AutoConf(swarm, api)
|
||||||
|
lock = threading.Lock()
|
||||||
|
if swarm :
|
||||||
|
(server, thread) = run_reload_server(autoconf, lock)
|
||||||
|
|
||||||
|
# Get all bunkerized-nginx instances and web services created before
|
||||||
|
try :
|
||||||
|
if swarm :
|
||||||
|
before = client.services.list(filters={"label" : "bunkerized-nginx.AUTOCONF"}) + client.services.list(filters={"label" : "bunkerized-nginx.SERVER_NAME"})
|
||||||
|
else :
|
||||||
|
before = client.containers.list(all=True, filters={"label" : "bunkerized-nginx.AUTOCONF"}) + client.containers.list(filters={"label" : "bunkerized-nginx.SERVER_NAME"})
|
||||||
|
except docker.errors.APIError as e :
|
||||||
|
utils.log("[!] Docker API error " + str(e))
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
# Process them before events
|
||||||
|
with lock :
|
||||||
|
autoconf.pre_process(before)
|
||||||
|
|
||||||
|
# Process events received from Docker
|
||||||
|
try :
|
||||||
|
for event in client.events(decode=True) :
|
||||||
|
|
||||||
|
# Process only container/service events
|
||||||
|
if (swarm and event["Type"] != "service") or (not swarm and event["Type"] != "container") :
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get Container/Service object
|
||||||
|
try :
|
||||||
|
if swarm :
|
||||||
|
server = client.services.get(service_id=event["Actor"]["ID"])
|
||||||
|
else :
|
||||||
|
server = client.containers.get(event["id"])
|
||||||
|
except docker.errors.NotFound as e :
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Process the event
|
||||||
|
with lock :
|
||||||
|
autoconf.process(server, event["Action"])
|
||||||
|
|
||||||
|
except docker.errors.APIError as e :
|
||||||
|
utils.log("[!] Docker API error " + str(e))
|
||||||
|
sys.exit(4)
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
import docker, datetime, subprocess, shutil, os
|
|
||||||
|
|
||||||
def log(event) :
|
|
||||||
print("[" + str(datetime.datetime.now().replace(microsecond=0)) + "] AUTOCONF - " + event, flush=True)
|
|
||||||
|
|
||||||
def replace_in_file(file, old_str, new_str) :
|
|
||||||
with open(file) as f :
|
|
||||||
data = f.read()
|
|
||||||
data = data[::-1].replace(old_str[::-1], new_str[::-1], 1)[::-1]
|
|
||||||
with open(file, "w") as f :
|
|
||||||
f.write(data)
|
|
||||||
|
|
||||||
def generate(vars) :
|
|
||||||
vars_defaults = vars.copy()
|
|
||||||
vars_defaults.update(os.environ)
|
|
||||||
vars_defaults.update(vars)
|
|
||||||
subprocess.run(["/opt/entrypoint/site-config.sh", vars["SERVER_NAME"]], env=vars_defaults)
|
|
||||||
log("Generated config for " + vars["SERVER_NAME"])
|
|
||||||
|
|
||||||
def activate(vars) :
|
|
||||||
replace_in_file("/etc/nginx/nginx.conf", "}", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n}")
|
|
||||||
subprocess.run(["/usr/sbin/nginx", "-s", "reload"])
|
|
||||||
log("Activated config for " + vars["SERVER_NAME"])
|
|
||||||
|
|
||||||
def deactivate(vars) :
|
|
||||||
replace_in_file("/etc/nginx/nginx.conf", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n", "")
|
|
||||||
subprocess.run(["/usr/sbin/nginx", "-s", "reload"])
|
|
||||||
log("Deactivated config for " + vars["SERVER_NAME"])
|
|
||||||
|
|
||||||
def remove(vars) :
|
|
||||||
shutil.rmtree("/etc/nginx/" + vars["SERVER_NAME"])
|
|
||||||
log("Removed config for " + vars["SERVER_NAME"])
|
|
||||||
|
|
||||||
def process(id, event, vars) :
|
|
||||||
global containers
|
|
||||||
if event == "create" :
|
|
||||||
generate(vars)
|
|
||||||
containers.append(id)
|
|
||||||
elif event == "start" :
|
|
||||||
activate(vars)
|
|
||||||
elif event == "die" :
|
|
||||||
deactivate(vars)
|
|
||||||
elif event == "destroy" :
|
|
||||||
remove(vars)
|
|
||||||
containers.remove(id)
|
|
||||||
|
|
||||||
containers = []
|
|
||||||
|
|
||||||
client = docker.DockerClient(base_url='unix:///var/run/docker.sock')
|
|
||||||
|
|
||||||
# Process containers created before
|
|
||||||
for container in client.containers.list(all=True, filters={"label" : "bunkerized-nginx.SERVER_NAME"}) :
|
|
||||||
|
|
||||||
# Extract bunkerized-nginx.* labels
|
|
||||||
labels = container.labels.copy()
|
|
||||||
for label in container.labels :
|
|
||||||
if not label.startswith("bunkerized-nginx.") :
|
|
||||||
del labels[label]
|
|
||||||
# Remove bunkerized-nginx. on labels
|
|
||||||
vars = { k.replace("bunkerized-nginx.", "", 1) : v for k, v in labels.items()}
|
|
||||||
|
|
||||||
# Container is restarting or running
|
|
||||||
if container.status == "restarting" or container.status == "running" :
|
|
||||||
process(container.id, "create", vars)
|
|
||||||
process(container.id, "start", vars)
|
|
||||||
|
|
||||||
# Container is created or exited
|
|
||||||
if container.status == "created" or container.status == "exited" :
|
|
||||||
process(container.id, "create", vars)
|
|
||||||
|
|
||||||
for event in client.events(decode=True) :
|
|
||||||
|
|
||||||
# Process only container events
|
|
||||||
if event["Type"] != "container" :
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Check if a bunkerized-nginx.* label is present
|
|
||||||
present = False
|
|
||||||
for label in event["Actor"]["Attributes"] :
|
|
||||||
if label.startswith("bunkerized-nginx.") :
|
|
||||||
present = True
|
|
||||||
break
|
|
||||||
if not present :
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Only process if we generated a config
|
|
||||||
if not event["id"] in containers and event["Action"] != "create" :
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Extract bunkerized-nginx.* labels
|
|
||||||
labels = event["Actor"]["Attributes"].copy()
|
|
||||||
for label in event["Actor"]["Attributes"] :
|
|
||||||
if not label.startswith("bunkerized-nginx.") :
|
|
||||||
del labels[label]
|
|
||||||
# Remove bunkerized-nginx. on labels
|
|
||||||
vars = { k.replace("bunkerized-nginx.", "", 1) : v for k, v in labels.items()}
|
|
||||||
|
|
||||||
# Process the event
|
|
||||||
process(event["id"], event["Action"], vars)
|
|
||||||
42
autoconf/entrypoint.sh
Normal file
42
autoconf/entrypoint.sh
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "[*] Starting autoconf ..."
|
||||||
|
|
||||||
|
if [ "$SWARM_MODE" = "yes" ] ; then
|
||||||
|
cp -r /opt/confs/nginx/* /etc/nginx
|
||||||
|
chown -R root:nginx /etc/nginx
|
||||||
|
chmod -R 770 /etc/nginx
|
||||||
|
fi
|
||||||
|
|
||||||
|
# trap SIGTERM and SIGINT
|
||||||
|
function trap_exit() {
|
||||||
|
echo "[*] Catched stop operation"
|
||||||
|
echo "[*] Stopping crond ..."
|
||||||
|
pkill -TERM crond
|
||||||
|
echo "[*] Stopping python3 ..."
|
||||||
|
pkill -TERM python3
|
||||||
|
pkill -TERM tail
|
||||||
|
}
|
||||||
|
trap "trap_exit" TERM INT QUIT
|
||||||
|
|
||||||
|
# remove old crontabs
|
||||||
|
echo "" > /etc/crontabs/root
|
||||||
|
|
||||||
|
# setup logrotate
|
||||||
|
touch /var/log/jobs.log
|
||||||
|
echo "0 0 * * * /usr/sbin/logrotate -f /etc/logrotate.conf > /dev/null 2>&1" >> /etc/crontabs/root
|
||||||
|
|
||||||
|
# start cron
|
||||||
|
crond
|
||||||
|
|
||||||
|
# run autoconf app
|
||||||
|
/opt/entrypoint/app.py &
|
||||||
|
|
||||||
|
# display logs
|
||||||
|
tail -F /var/log/jobs.log &
|
||||||
|
pid="$!"
|
||||||
|
wait "$pid"
|
||||||
|
|
||||||
|
# stop
|
||||||
|
echo "[*] autoconf stopped"
|
||||||
|
exit 0
|
||||||
12
autoconf/hooks/post_push
Normal file
12
autoconf/hooks/post_push
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
curl -Lo manifest-tool https://github.com/estesp/manifest-tool/releases/download/v1.0.3/manifest-tool-linux-amd64
|
||||||
|
chmod +x manifest-tool
|
||||||
|
|
||||||
|
VERSION=$(cat VERSION | tr -d '\n')
|
||||||
|
if [ "$SOURCE_BRANCH" = "dev" ] ; then
|
||||||
|
./manifest-tool push from-args --ignore-missing --platforms linux/amd64,linux/386,linux/arm/v7,linux/arm64/v8 --template bunkerity/bunkerized-nginx-autoconf:dev-ARCHVARIANT --target bunkerity/bunkerized-nginx-autoconf:dev
|
||||||
|
elif [ "$SOURCE_BRANCH" = "master" ] ; then
|
||||||
|
./manifest-tool push from-args --ignore-missing --platforms linux/amd64,linux/386,linux/arm/v7,linux/arm64/v8 --template bunkerity/bunkerized-nginx-autoconf:ARCHVARIANT --target bunkerity/bunkerized-nginx-autoconf:${VERSION}
|
||||||
|
./manifest-tool push from-args --ignore-missing --platforms linux/amd64,linux/386,linux/arm/v7,linux/arm64/v8 --template bunkerity/bunkerized-nginx-autoconf:ARCHVARIANT --target bunkerity/bunkerized-nginx-autoconf:latest
|
||||||
|
fi
|
||||||
5
autoconf/hooks/pre_build
Normal file
5
autoconf/hooks/pre_build
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Register qemu-*-static for all supported processors except the
|
||||||
|
# current one, but also remove all registered binfmt_misc before
|
||||||
|
docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||||
23
autoconf/misc/logrotate.conf
Normal file
23
autoconf/misc/logrotate.conf
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/var/log/*.log /var/log/letsencrypt/*.log {
|
||||||
|
# compress old files using gzip
|
||||||
|
compress
|
||||||
|
|
||||||
|
# rotate everyday
|
||||||
|
daily
|
||||||
|
|
||||||
|
# remove old logs after X days
|
||||||
|
maxage 7
|
||||||
|
rotate 7
|
||||||
|
|
||||||
|
# no errors if a file is missing
|
||||||
|
missingok
|
||||||
|
|
||||||
|
# disable mailing
|
||||||
|
nomail
|
||||||
|
|
||||||
|
# mininum size of a logfile before rotating
|
||||||
|
minsize 10M
|
||||||
|
|
||||||
|
# make a copy and truncate the files
|
||||||
|
copytruncate
|
||||||
|
}
|
||||||
19
autoconf/reload.py
Normal file
19
autoconf/reload.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import sys, socket, os
|
||||||
|
|
||||||
|
if not os.path.exists("/tmp/autoconf.sock") :
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try :
|
||||||
|
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
client.connect("/tmp/autoconf.sock")
|
||||||
|
client.send("reload".encode("utf-8"))
|
||||||
|
data = client.recv(512)
|
||||||
|
client.close()
|
||||||
|
if not data or data.decode("utf-8") != "ok" :
|
||||||
|
sys.exit(3)
|
||||||
|
except Exception as e :
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
24
autoconf/utils.py
Normal file
24
autoconf/utils.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
def log(event) :
|
||||||
|
print("[" + str(datetime.datetime.now().replace(microsecond=0)) + "] " + event, flush=True)
|
||||||
|
|
||||||
|
def replace_in_file(file, old_str, new_str) :
|
||||||
|
with open(file) as f :
|
||||||
|
data = f.read()
|
||||||
|
data = data[::-1].replace(old_str[::-1], new_str[::-1], 1)[::-1]
|
||||||
|
with open(file, "w") as f :
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
|
def install_cron(service, vars, crons) :
|
||||||
|
for var in vars :
|
||||||
|
if var in crons :
|
||||||
|
with open("/etc/crontabs/root", "a+") as f :
|
||||||
|
f.write(vars[var] + " /opt/cron/" + crons[var] + ".py " + service["Actor"]["ID"])
|
||||||
|
|
||||||
|
def uninstall_cron(service, vars, crons) :
|
||||||
|
for var in vars :
|
||||||
|
if var in crons :
|
||||||
|
replace_in_file("/etc/crontabs/root", vars[var] + " /opt/cron/" + crons[var] + ".py " + service["Actor"]["ID"] + "\n", "")
|
||||||
31
compile.sh
31
compile.sh
@@ -30,7 +30,7 @@ function git_secure_clone() {
|
|||||||
NTASK=$(nproc)
|
NTASK=$(nproc)
|
||||||
|
|
||||||
# install build dependencies
|
# install build dependencies
|
||||||
apk add --no-cache --virtual build autoconf libtool automake git geoip-dev yajl-dev g++ curl-dev libxml2-dev pcre-dev make linux-headers libmaxminddb-dev musl-dev lua-dev gd-dev gnupg brotli-dev
|
apk add --no-cache --virtual build autoconf libtool automake git geoip-dev yajl-dev g++ gcc curl-dev libxml2-dev pcre-dev make linux-headers libmaxminddb-dev musl-dev lua-dev gd-dev gnupg brotli-dev openssl-dev
|
||||||
|
|
||||||
# compile and install ModSecurity library
|
# compile and install ModSecurity library
|
||||||
cd /tmp
|
cd /tmp
|
||||||
@@ -50,8 +50,9 @@ make install-strip
|
|||||||
cd /tmp
|
cd /tmp
|
||||||
git_secure_clone https://github.com/coreruleset/coreruleset.git 7776fe23f127fd2315bad0e400bdceb2cabb97dc
|
git_secure_clone https://github.com/coreruleset/coreruleset.git 7776fe23f127fd2315bad0e400bdceb2cabb97dc
|
||||||
cd coreruleset
|
cd coreruleset
|
||||||
cp -r rules /etc/nginx/owasp-crs
|
mkdir /opt/owasp
|
||||||
cp crs-setup.conf.example /etc/nginx/owasp-crs.conf
|
cp -r rules /opt/owasp/crs
|
||||||
|
cp crs-setup.conf.example /opt/owasp/crs.conf
|
||||||
|
|
||||||
# get nginx modules
|
# get nginx modules
|
||||||
cd /tmp
|
cd /tmp
|
||||||
@@ -111,6 +112,30 @@ git_secure_clone https://github.com/ledgetech/lua-resty-http.git 984fdc260543763
|
|||||||
cd lua-resty-http
|
cd lua-resty-http
|
||||||
make install
|
make install
|
||||||
cd /tmp
|
cd /tmp
|
||||||
|
git_secure_clone https://github.com/Neopallium/lualogging.git cadc4e8fd652be07a65b121a3e024838db330c15
|
||||||
|
cd lualogging
|
||||||
|
cp -r src/* /usr/local/lib/lua
|
||||||
|
cd /tmp
|
||||||
|
git_secure_clone https://github.com/diegonehab/luasocket.git 5b18e475f38fcf28429b1cc4b17baee3b9793a62
|
||||||
|
cd luasocket
|
||||||
|
make -j $NTASK
|
||||||
|
make CDIR_linux=lib/lua/5.1 LDIR_linux=lib/lua install
|
||||||
|
cd /tmp
|
||||||
|
git_secure_clone https://github.com/brunoos/luasec.git c6704919bdc85f3324340bdb35c2795a02f7d625
|
||||||
|
cd luasec
|
||||||
|
make linux -j $NTASK
|
||||||
|
make LUACPATH=/usr/local/lib/lua/5.1 LUAPATH=/usr/local/lib/lua install
|
||||||
|
cd /tmp
|
||||||
|
git_secure_clone https://github.com/crowdsecurity/lua-cs-bouncer.git 3c235c813fc453dcf51a391bc9e9a36ca77958b0
|
||||||
|
cd lua-cs-bouncer
|
||||||
|
mkdir /usr/local/lib/lua/crowdsec
|
||||||
|
cp lib/*.lua /usr/local/lib/lua/crowdsec
|
||||||
|
cp template.conf /usr/local/lib/lua/crowdsec/crowdsec.conf
|
||||||
|
sed -i 's/^API_URL=.*/API_URL=%CROWDSEC_HOST%/' /usr/local/lib/lua/crowdsec/crowdsec.conf
|
||||||
|
sed -i 's/^API_KEY=.*/API_KEY=%CROWDSEC_KEY%/' /usr/local/lib/lua/crowdsec/crowdsec.conf
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|||||||
30
confs/global/api-temp.conf
Normal file
30
confs/global/api-temp.conf
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
location ~ ^%API_URI%/ping {
|
||||||
|
return 444;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^%API_URI% {
|
||||||
|
|
||||||
|
rewrite_by_lua_block {
|
||||||
|
|
||||||
|
local api = require "api"
|
||||||
|
local api_uri = "%API_URI%"
|
||||||
|
|
||||||
|
if api.is_api_call(api_uri) then
|
||||||
|
ngx.header.content_type = 'text/plain'
|
||||||
|
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.say("ok")
|
||||||
|
else
|
||||||
|
ngx.log(ngx.WARN, "[API] API call " .. ngx.var.request_uri .. " failed from " .. ngx.var.remote_addr)
|
||||||
|
ngx.say("ko")
|
||||||
|
end
|
||||||
|
|
||||||
|
ngx.exit(ngx.HTTP_OK)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
ngx.exit(ngx.OK)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
21
confs/global/api.conf
Normal file
21
confs/global/api.conf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
rewrite_by_lua_block {
|
||||||
|
|
||||||
|
local api = require "api"
|
||||||
|
local api_uri = "%API_URI%"
|
||||||
|
|
||||||
|
if api.is_api_call(api_uri) then
|
||||||
|
ngx.header.content_type = 'text/plain'
|
||||||
|
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.say("ok")
|
||||||
|
else
|
||||||
|
ngx.log(ngx.WARN, "[API] API call " .. ngx.var.request_uri .. " failed from " .. ngx.var.remote_addr)
|
||||||
|
ngx.say("ko")
|
||||||
|
end
|
||||||
|
|
||||||
|
ngx.exit(ngx.HTTP_OK)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
ngx.exit(ngx.OK)
|
||||||
|
}
|
||||||
0
confs/global/block-abusers.conf
Normal file
0
confs/global/block-abusers.conf
Normal file
0
confs/global/block-proxies.conf
Normal file
0
confs/global/block-proxies.conf
Normal file
0
confs/global/block-tor-exit-node.conf
Normal file
0
confs/global/block-tor-exit-node.conf
Normal file
@@ -1,5 +1,8 @@
|
|||||||
|
load_module /usr/lib/nginx/modules/ngx_http_lua_module.so;
|
||||||
|
|
||||||
daemon on;
|
daemon on;
|
||||||
pid /tmp/nginx.pid;
|
|
||||||
|
pid /tmp/nginx-temp.pid;
|
||||||
|
|
||||||
events {
|
events {
|
||||||
worker_connections 1024;
|
worker_connections 1024;
|
||||||
@@ -7,12 +10,19 @@ events {
|
|||||||
}
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
|
proxy_temp_path /tmp/proxy_temp;
|
||||||
|
client_body_temp_path /tmp/client_temp;
|
||||||
|
fastcgi_temp_path /tmp/fastcgi_temp;
|
||||||
|
uwsgi_temp_path /tmp/uwsgi_temp;
|
||||||
|
scgi_temp_path /tmp/scgi_temp;
|
||||||
|
lua_package_path "/usr/local/lib/lua/?.lua;;";
|
||||||
server {
|
server {
|
||||||
listen 0.0.0.0:%HTTP_PORT% default_server;
|
listen 0.0.0.0:%HTTP_PORT% default_server;
|
||||||
server_name _;
|
server_name _;
|
||||||
location ~ ^/.well-known/acme-challenge/ {
|
location ~ ^/.well-known/acme-challenge/ {
|
||||||
root /acme-challenge;
|
root /acme-challenge;
|
||||||
}
|
}
|
||||||
|
%USE_API%
|
||||||
location / {
|
location / {
|
||||||
return 444;
|
return 444;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ 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:/dev/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:/dev/log,nohostname,facility=local0 warn;
|
error_log syslog:server=unix:/tmp/log,nohostname,facility=local0 warn;
|
||||||
|
|
||||||
# temp paths
|
# temp paths
|
||||||
proxy_temp_path /tmp/proxy_temp;
|
proxy_temp_path /tmp/proxy_temp;
|
||||||
@@ -71,6 +71,9 @@ http {
|
|||||||
# resolvers to use
|
# resolvers to use
|
||||||
resolver %DNS_RESOLVERS% ipv6=off;
|
resolver %DNS_RESOLVERS% ipv6=off;
|
||||||
|
|
||||||
|
# remove ports when sending redirects
|
||||||
|
port_in_redirect off;
|
||||||
|
|
||||||
# lua path and dicts
|
# lua path and dicts
|
||||||
lua_package_path "/usr/local/lib/lua/?.lua;;";
|
lua_package_path "/usr/local/lib/lua/?.lua;;";
|
||||||
%WHITELIST_IP_CACHE%
|
%WHITELIST_IP_CACHE%
|
||||||
@@ -85,6 +88,9 @@ http {
|
|||||||
# shared memory zone for limit_req
|
# shared memory zone for limit_req
|
||||||
%LIMIT_REQ_ZONE%
|
%LIMIT_REQ_ZONE%
|
||||||
|
|
||||||
|
# shared memory zone for limit_conn
|
||||||
|
%LIMIT_CONN_ZONE%
|
||||||
|
|
||||||
# whitelist or blacklist country
|
# whitelist or blacklist country
|
||||||
%USE_COUNTRY%
|
%USE_COUNTRY%
|
||||||
|
|
||||||
@@ -105,4 +111,7 @@ http {
|
|||||||
|
|
||||||
# server config(s)
|
# server config(s)
|
||||||
%INCLUDE_SERVER%
|
%INCLUDE_SERVER%
|
||||||
|
|
||||||
|
# API
|
||||||
|
%USE_API%
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +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)
|
||||||
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()
|
||||||
@@ -21,16 +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)
|
||||||
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)
|
||||||
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)
|
||||||
return ngx.redirect("%ANTIBOT_URI%")
|
return ngx.redirect("%ANTIBOT_URI%")
|
||||||
end
|
end
|
||||||
cookie.set({captcha = "ok"})
|
cookie.set({captcha = "ok"})
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ location = %ANTIBOT_URI% {
|
|||||||
local cookie = require "cookie"
|
local cookie = require "cookie"
|
||||||
local javascript = require "javascript"
|
local javascript = require "javascript"
|
||||||
if not cookie.is_set("challenge") then
|
if not cookie.is_set("challenge") then
|
||||||
|
ngx.log(ngx.WARN, "[ANTIBOT] javascript fail (1) for " .. ngx.var.remote_addr)
|
||||||
return ngx.exit(ngx.HTTP_FORBIDDEN)
|
return ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||||
end
|
end
|
||||||
local challenge = cookie.get("challenge")
|
local challenge = cookie.get("challenge")
|
||||||
@@ -20,16 +21,19 @@ location = %ANTIBOT_URI% {
|
|||||||
local cookie = require "cookie"
|
local cookie = require "cookie"
|
||||||
local javascript = require "javascript"
|
local javascript = require "javascript"
|
||||||
if not cookie.is_set("challenge") then
|
if not cookie.is_set("challenge") then
|
||||||
|
ngx.log(ngx.WARN, "[ANTIBOT] javascript 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["challenge"] then
|
if err == "truncated" or not args or not args["challenge"] then
|
||||||
|
ngx.log(ngx.WARN, "[ANTIBOT] javascript fail (3) for " .. ngx.var.remote_addr)
|
||||||
return ngx.exit(ngx.HTTP_FORBIDDEN)
|
return ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||||
end
|
end
|
||||||
local challenge = args["challenge"]
|
local challenge = args["challenge"]
|
||||||
local check = javascript.check(cookie.get("challenge"), challenge)
|
local check = javascript.check(cookie.get("challenge"), challenge)
|
||||||
if not check then
|
if not check then
|
||||||
|
ngx.log(ngx.WARN, "[ANTIBOT] javascript fail (4) for " .. ngx.var.remote_addr)
|
||||||
return ngx.exit(ngx.HTTP_FORBIDDEN)
|
return ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||||
end
|
end
|
||||||
cookie.set({javascript = "ok"})
|
cookie.set({javascript = "ok"})
|
||||||
|
|||||||
@@ -7,6 +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)
|
||||||
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%")
|
||||||
@@ -19,17 +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)
|
||||||
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)
|
||||||
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, "client has recaptcha score of " .. tostring(check))
|
ngx.log(ngx.WARN, "[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"})
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
auth_basic "%AUTH_BASIC_TEXT%";
|
auth_basic "%AUTH_BASIC_TEXT%";
|
||||||
auth_basic_user_file /etc/nginx/.htpasswd;
|
auth_basic_user_file %NGINX_PREFIX%.htpasswd;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
location %AUTH_BASIC_LOCATION% {
|
location %AUTH_BASIC_LOCATION% {
|
||||||
auth_basic "%AUTH_BASIC_TEXT%";
|
auth_basic "%AUTH_BASIC_TEXT%";
|
||||||
auth_basic_user_file /etc/nginx/.htpasswd;
|
auth_basic_user_file %NGINX_PREFIX%.htpasswd;
|
||||||
}
|
}
|
||||||
|
|||||||
25
confs/site/fastcgi.conf
Normal file
25
confs/site/fastcgi.conf
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_param QUERY_STRING $query_string;
|
||||||
|
fastcgi_param REQUEST_METHOD $request_method;
|
||||||
|
fastcgi_param CONTENT_TYPE $content_type;
|
||||||
|
fastcgi_param CONTENT_LENGTH $content_length;
|
||||||
|
|
||||||
|
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||||
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
|
fastcgi_param DOCUMENT_URI $document_uri;
|
||||||
|
fastcgi_param DOCUMENT_ROOT $document_root;
|
||||||
|
fastcgi_param SERVER_PROTOCOL $server_protocol;
|
||||||
|
fastcgi_param REQUEST_SCHEME $scheme;
|
||||||
|
fastcgi_param HTTPS $https if_not_empty;
|
||||||
|
|
||||||
|
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
|
||||||
|
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
|
||||||
|
|
||||||
|
fastcgi_param REMOTE_ADDR $remote_addr;
|
||||||
|
fastcgi_param REMOTE_PORT $remote_port;
|
||||||
|
fastcgi_param SERVER_ADDR $server_addr;
|
||||||
|
fastcgi_param SERVER_PORT $server_port;
|
||||||
|
fastcgi_param SERVER_NAME $server_name;
|
||||||
|
|
||||||
|
# PHP only, required if PHP was built with --enable-force-cgi-redirect
|
||||||
|
fastcgi_param REDIRECT_STATUS 200;
|
||||||
@@ -2,7 +2,7 @@ listen 0.0.0.0:%HTTPS_PORT% ssl %HTTP2%;
|
|||||||
ssl_certificate %HTTPS_CERT%;
|
ssl_certificate %HTTPS_CERT%;
|
||||||
ssl_certificate_key %HTTPS_KEY%;
|
ssl_certificate_key %HTTPS_KEY%;
|
||||||
ssl_protocols %HTTPS_PROTOCOLS%;
|
ssl_protocols %HTTPS_PROTOCOLS%;
|
||||||
ssl_prefer_server_ciphers off;
|
ssl_prefer_server_ciphers on;
|
||||||
ssl_session_tickets off;
|
ssl_session_tickets off;
|
||||||
ssl_session_timeout 1d;
|
ssl_session_timeout 1d;
|
||||||
ssl_session_cache shared:MozSSL:10m;
|
ssl_session_cache shared:MozSSL:10m;
|
||||||
|
|||||||
1
confs/site/limit-conn.conf
Normal file
1
confs/site/limit-conn.conf
Normal file
@@ -0,0 +1 @@
|
|||||||
|
limit_conn ddos %LIMIT_CONN_MAX%;
|
||||||
@@ -3,6 +3,7 @@ set $session_check_addr on;
|
|||||||
|
|
||||||
access_by_lua_block {
|
access_by_lua_block {
|
||||||
|
|
||||||
|
local use_lets_encrypt = %USE_LETS_ENCRYPT%
|
||||||
local use_whitelist_ip = %USE_WHITELIST_IP%
|
local use_whitelist_ip = %USE_WHITELIST_IP%
|
||||||
local use_whitelist_reverse = %USE_WHITELIST_REVERSE%
|
local use_whitelist_reverse = %USE_WHITELIST_REVERSE%
|
||||||
local use_user_agent = %USE_USER_AGENT%
|
local use_user_agent = %USE_USER_AGENT%
|
||||||
@@ -18,6 +19,7 @@ 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"
|
||||||
@@ -26,8 +28,14 @@ local javascript = require "javascript"
|
|||||||
local captcha = require "captcha"
|
local captcha = require "captcha"
|
||||||
local recaptcha = require "recaptcha"
|
local recaptcha = require "recaptcha"
|
||||||
|
|
||||||
-- antibot
|
-- user variables
|
||||||
local antibot_uri = "%ANTIBOT_URI%"
|
local antibot_uri = "%ANTIBOT_URI%"
|
||||||
|
local whitelist_user_agent = {%WHITELIST_USER_AGENT%}
|
||||||
|
|
||||||
|
-- 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
|
||||||
@@ -80,16 +88,32 @@ 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 ua = headers["User-Agent"]
|
||||||
|
if not whitelist_user_agent ~= "" then
|
||||||
|
local k_ua_white, v_ua_white = next(whitelist_user_agent, nil)
|
||||||
|
while v_ua_white do
|
||||||
|
local rst_whitelist = string.match(ua, v_ua_white)
|
||||||
|
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
|
||||||
|
ngx.log(ngx.WARN, "[BLOCK] User-Agent " .. ngx.var.http_user_agent .. " is blacklisted")
|
||||||
ngx.exit(ngx.HTTP_FORBIDDEN)
|
ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||||
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.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.exit(ngx.HTTP_FORBIDDEN)
|
ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -119,6 +143,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)
|
||||||
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
|
||||||
@@ -140,7 +165,7 @@ end
|
|||||||
-- captcha check
|
-- captcha check
|
||||||
if use_antibot_captcha then
|
if use_antibot_captcha then
|
||||||
if not cookie.is_set("captcha") then
|
if not cookie.is_set("captcha") then
|
||||||
if ngx.var.request_uri ~= antibot_uri and ngx.var.request_uri ~= "/favicon.ico" then
|
if ngx.var.request_uri ~= antibot_uri 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
|
||||||
@@ -150,7 +175,7 @@ end
|
|||||||
-- recaptcha check
|
-- recaptcha check
|
||||||
if use_antibot_recaptcha then
|
if use_antibot_recaptcha then
|
||||||
if not cookie.is_set("recaptcha") then
|
if not cookie.is_set("recaptcha") then
|
||||||
if ngx.var.request_uri ~= antibot_uri and ngx.var.request_uri ~= "/favicon.ico" then
|
if ngx.var.request_uri ~= antibot_uri 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
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Protocol $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
location %REVERSE_PROXY_URL% {
|
location %REVERSE_PROXY_URL% {
|
||||||
proxy_pass %REVERSE_PROXY_HOST%;
|
proxy_pass %REVERSE_PROXY_HOST%;
|
||||||
|
%REVERSE_PROXY_HEADERS%
|
||||||
%REVERSE_PROXY_WS%
|
%REVERSE_PROXY_WS%
|
||||||
|
%REVERSE_PROXY_CUSTOM_HEADERS%
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
%PRE_SERVER_CONF%
|
||||||
|
|
||||||
server {
|
server {
|
||||||
%FASTCGI_PATH%
|
%FASTCGI_PATH%
|
||||||
%SERVER_CONF%
|
%SERVER_CONF%
|
||||||
@@ -15,6 +17,7 @@ server {
|
|||||||
return 405;
|
return 405;
|
||||||
}
|
}
|
||||||
%LIMIT_REQ%
|
%LIMIT_REQ%
|
||||||
|
%LIMIT_CONN%
|
||||||
%AUTH_BASIC%
|
%AUTH_BASIC%
|
||||||
%REMOVE_HEADERS%
|
%REMOVE_HEADERS%
|
||||||
%X_FRAME_OPTIONS%
|
%X_FRAME_OPTIONS%
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
function git_secure_clone() {
|
|
||||||
repo="$1"
|
|
||||||
commit="$2"
|
|
||||||
folder=$(echo "$repo" | sed -E "s@https://github.com/.*/(.*)\.git@\1@")
|
|
||||||
git clone "$repo"
|
|
||||||
cd "$folder"
|
|
||||||
git checkout "${commit}^{commit}"
|
|
||||||
if [ $? -ne 0 ] ; then
|
|
||||||
echo "[!] Commit hash $commit is absent from repository $repo !"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
cd ..
|
|
||||||
}
|
|
||||||
|
|
||||||
NTASK=$(nproc)
|
|
||||||
|
|
||||||
# install build dependencies
|
|
||||||
apk add --no-cache --virtual build git bash lua-dev mariadb-dev sqlite-dev gettext make go jq
|
|
||||||
|
|
||||||
# build and install crowdsec
|
|
||||||
cd /tmp
|
|
||||||
git_secure_clone https://github.com/crowdsecurity/crowdsec.git 2fdf7624da381af605baa46f319f2ed3015807e4
|
|
||||||
cd crowdsec
|
|
||||||
make -j $NTASK build
|
|
||||||
./wizard.sh --bininstall
|
|
||||||
sed -i 's/^machine_id:.*//' /etc/crowdsec/config/api.yaml
|
|
||||||
sed -i 's/^password:.*//' /etc/crowdsec/config/api.yaml
|
|
||||||
|
|
||||||
# install nginx collection
|
|
||||||
cscli update
|
|
||||||
cscli install collection crowdsecurity/nginx
|
|
||||||
sed -i "s/^filter:.*$/filter: \"evt.Line.Labels.type == 'nginx'\"/" /etc/crowdsec/config/parsers/s01-parse/nginx-logs.yaml
|
|
||||||
sed -i 's/apply_on: message/apply_on: Line.Raw/g' /etc/crowdsec/config/parsers/s01-parse/nginx-logs.yaml
|
|
||||||
|
|
||||||
# build and install luasql
|
|
||||||
cd /tmp
|
|
||||||
git_secure_clone https://github.com/keplerproject/luasql.git 22d4a911f35cf851af9db71124e3998d96fb3fa1
|
|
||||||
cd luasql
|
|
||||||
make -j $NTASK sqlite3 mysql
|
|
||||||
mkdir /usr/local/lib/lua/5.1/luasql
|
|
||||||
cp src/*.so /usr/local/lib/lua/5.1/luasql
|
|
||||||
|
|
||||||
# install lualogging
|
|
||||||
cd /tmp
|
|
||||||
git_secure_clone https://github.com/Neopallium/lualogging.git cadc4e8fd652be07a65b121a3e024838db330c15
|
|
||||||
cd lualogging
|
|
||||||
cp -r src/* /usr/local/lib/lua
|
|
||||||
|
|
||||||
# install cs-lua-lib
|
|
||||||
cd /tmp
|
|
||||||
git_secure_clone https://github.com/crowdsecurity/cs-lua-lib.git 97e55a555a8f6d46c1c2032825a4578090283301
|
|
||||||
cd cs-lua-lib
|
|
||||||
mkdir /usr/local/lib/lua/crowdsec
|
|
||||||
cp lib/*.lua /usr/local/lib/lua/crowdsec
|
|
||||||
cp template.conf /usr/local/lib/lua/crowdsec/crowdsec.conf
|
|
||||||
rm /usr/local/lib/lua/crowdsec/lrucache.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
|
|
||||||
|
|
||||||
# remove build dependencies
|
|
||||||
apk del build
|
|
||||||
21
entrypoint/clamav.sh
Normal file
21
entrypoint/clamav.sh
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# load default values
|
||||||
|
. /opt/entrypoint/defaults.sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# clamav setup
|
||||||
|
if [ "$(has_value USE_CLAMAV_UPLOAD yes)" != "" ] || [ "$USE_CLAMAV_SCAN" = "yes" ] ; then
|
||||||
|
echo "[*] Updating clamav (in background) ..."
|
||||||
|
freshclam > /dev/null 2>&1 &
|
||||||
|
echo "$CLAMAV_UPDATE_CRON /usr/bin/freshclam > /dev/null 2>&1" >> /etc/crontabs/nginx
|
||||||
|
fi
|
||||||
|
if [ "$USE_CLAMAV_SCAN" = "yes" ] ; then
|
||||||
|
if [ "$USE_CLAMAV_SCAN_REMOVE" = "yes" ] ; then
|
||||||
|
echo "$USE_CLAMAV_SCAN_CRON /usr/bin/clamscan -r -i --no-summary --remove / >> /var/log/clamav.log 2>&1" >> /etc/crontabs/nginx
|
||||||
|
else
|
||||||
|
echo "$USE_CLAMAV_SCAN_CRON /usr/bin/clamscan -r -i --no-summary / >> /var/log/clamav.log 2>&1" >> /etc/crontabs/nginx
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
MULTISITE="${MULTISITE-no}"
|
MULTISITE="${MULTISITE-no}"
|
||||||
LOG_FORMAT="${LOG_FORMAT-\$remote_addr - \$remote_user \$host [\$time_local] \"\$request\" \$status \$body_bytes_sent \"\$http_referer\" \"\$http_user_agent\"}"
|
LOG_FORMAT="${LOG_FORMAT-\$host \$remote_addr - \$remote_user [\$time_local] \"\$request\" \$status \$body_bytes_sent \"\$http_referer\" \"\$http_user_agent\"}"
|
||||||
HTTP_PORT="${HTTP_PORT-8080}"
|
HTTP_PORT="${HTTP_PORT-8080}"
|
||||||
HTTPS_PORT="${HTTPS_PORT-8443}"
|
HTTPS_PORT="${HTTPS_PORT-8443}"
|
||||||
MAX_CLIENT_SIZE="${MAX_CLIENT_SIZE-10m}"
|
MAX_CLIENT_SIZE="${MAX_CLIENT_SIZE-10m}"
|
||||||
@@ -45,17 +45,24 @@ DISABLE_DEFAULT_SERVER="${DISABLE_DEFAULT_SERVER-no}"
|
|||||||
SERVER_NAME="${SERVER_NAME-www.bunkerity.com}"
|
SERVER_NAME="${SERVER_NAME-www.bunkerity.com}"
|
||||||
ALLOWED_METHODS="${ALLOWED_METHODS-GET|POST|HEAD}"
|
ALLOWED_METHODS="${ALLOWED_METHODS-GET|POST|HEAD}"
|
||||||
BLOCK_USER_AGENT="${BLOCK_USER_AGENT-yes}"
|
BLOCK_USER_AGENT="${BLOCK_USER_AGENT-yes}"
|
||||||
|
WHITELIST_USER_AGENT="${WHITELIST_USER_AGENT-}"
|
||||||
|
BLOCK_USER_AGENT_CRON="${BLOCK_USER_AGENT_CRON-30 0 * * *}"
|
||||||
BLOCK_REFERRER="${BLOCK_REFERRER-yes}"
|
BLOCK_REFERRER="${BLOCK_REFERRER-yes}"
|
||||||
|
BLOCK_REFERRER_CRON="${BLOCK_REFERRER_CRON-45 0 * * *}"
|
||||||
BLOCK_TOR_EXIT_NODE="${BLOCK_TOR_EXIT_NODE-yes}"
|
BLOCK_TOR_EXIT_NODE="${BLOCK_TOR_EXIT_NODE-yes}"
|
||||||
|
BLOCK_TOR_EXIT_NODE_CRON="${BLOCK_TOR_EXIT_NODE_CRON-0 */1 * * *}"
|
||||||
BLOCK_PROXIES="${BLOCK_PROXIES-yes}"
|
BLOCK_PROXIES="${BLOCK_PROXIES-yes}"
|
||||||
|
BLOCK_PROXIES_CRON="${BLOCK_PROXIES_CRON-0 3 * * *}"
|
||||||
BLOCK_ABUSERS="${BLOCK_ABUSERS-yes}"
|
BLOCK_ABUSERS="${BLOCK_ABUSERS-yes}"
|
||||||
|
BLOCK_ABUSERS_CRON="${BLOCK_ABUSERS_CRON-0 2 * * *}"
|
||||||
AUTO_LETS_ENCRYPT="${AUTO_LETS_ENCRYPT-no}"
|
AUTO_LETS_ENCRYPT="${AUTO_LETS_ENCRYPT-no}"
|
||||||
|
AUTO_LETS_ENCRYPT_CRON="${AUTO_LETS_ENCRYPT_CRON-15 0 * * *}"
|
||||||
HTTP2="${HTTP2-yes}"
|
HTTP2="${HTTP2-yes}"
|
||||||
HTTPS_PROTOCOLS="${HTTPS_PROTOCOLS-TLSv1.2 TLSv1.3}"
|
HTTPS_PROTOCOLS="${HTTPS_PROTOCOLS-TLSv1.2 TLSv1.3}"
|
||||||
STRICT_TRANSPORT_SECURITY="${STRICT_TRANSPORT_SECURITY-max-age=31536000}"
|
STRICT_TRANSPORT_SECURITY="${STRICT_TRANSPORT_SECURITY-max-age=31536000}"
|
||||||
USE_MODSECURITY="${USE_MODSECURITY-yes}"
|
USE_MODSECURITY="${USE_MODSECURITY-yes}"
|
||||||
USE_MODSECURITY_CRS="${USE_MODSECURITY_CRS-yes}"
|
USE_MODSECURITY_CRS="${USE_MODSECURITY_CRS-yes}"
|
||||||
CONTENT_SECURITY_POLICY="${CONTENT_SECURITY_POLICY-object-src 'none'; frame-ancestors 'self'; form-action 'self'; block-all-mixed-content; sandbox allow-forms allow-same-origin allow-scripts; base-uri 'self';}"
|
CONTENT_SECURITY_POLICY="${CONTENT_SECURITY_POLICY-object-src 'none'; frame-ancestors 'self'; form-action 'self'; block-all-mixed-content; sandbox allow-forms allow-same-origin allow-scripts allow-popups; base-uri 'self';}"
|
||||||
COOKIE_FLAGS="${COOKIE_FLAGS-* HttpOnly SameSite=Lax}"
|
COOKIE_FLAGS="${COOKIE_FLAGS-* HttpOnly SameSite=Lax}"
|
||||||
COOKIE_AUTO_SECURE_FLAG="${COOKIE_AUTO_SECURE_FLAG-yes}"
|
COOKIE_AUTO_SECURE_FLAG="${COOKIE_AUTO_SECURE_FLAG-yes}"
|
||||||
SERVE_FILES="${SERVE_FILES-yes}"
|
SERVE_FILES="${SERVE_FILES-yes}"
|
||||||
@@ -67,8 +74,11 @@ FAIL2BAN_STATUS_CODES="${FAIL2BAN_STATUS_CODES-400|401|403|404|405|444}"
|
|||||||
FAIL2BAN_BANTIME="${FAIL2BAN_BANTIME-3600}"
|
FAIL2BAN_BANTIME="${FAIL2BAN_BANTIME-3600}"
|
||||||
FAIL2BAN_FINDTIME="${FAIL2BAN_FINDTIME-60}"
|
FAIL2BAN_FINDTIME="${FAIL2BAN_FINDTIME-60}"
|
||||||
FAIL2BAN_MAXRETRY="${FAIL2BAN_MAXRETRY-15}"
|
FAIL2BAN_MAXRETRY="${FAIL2BAN_MAXRETRY-15}"
|
||||||
|
FAIL2BAN_IGNOREIP="${FAIL2BAN_IGNOREIP-127.0.0.1/8 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8}"
|
||||||
USE_CLAMAV_UPLOAD="${USE_CLAMAV_UPLOAD-yes}"
|
USE_CLAMAV_UPLOAD="${USE_CLAMAV_UPLOAD-yes}"
|
||||||
USE_CLAMAV_SCAN="${USE_CLAMAV_SCAN-yes}"
|
USE_CLAMAV_SCAN="${USE_CLAMAV_SCAN-yes}"
|
||||||
|
USE_CLAMAV_SCAN_CRON="${USE_CLAMAV_SCAN_CRON-30 1 * * *}"
|
||||||
|
CLAMAV_UPDATE_CRON="${CLAMAV_UPDATE_CRON-0 1 * * *}"
|
||||||
CLAMAV_SCAN_REMOVE="${CLAMAV_SCAN_REMOVE-yes}"
|
CLAMAV_SCAN_REMOVE="${CLAMAV_SCAN_REMOVE-yes}"
|
||||||
USE_AUTH_BASIC="${USE_AUTH_BASIC-no}"
|
USE_AUTH_BASIC="${USE_AUTH_BASIC-no}"
|
||||||
AUTH_BASIC_TEXT="${AUTH_BASIC_TEXT-Restricted area}"
|
AUTH_BASIC_TEXT="${AUTH_BASIC_TEXT-Restricted area}"
|
||||||
@@ -79,6 +89,7 @@ USE_CUSTOM_HTTPS="${USE_CUSTOM_HTTPS-no}"
|
|||||||
ROOT_FOLDER="${ROOT_FOLDER-/www}"
|
ROOT_FOLDER="${ROOT_FOLDER-/www}"
|
||||||
LOGROTATE_MINSIZE="${LOGROTATE_MINSIZE-10M}"
|
LOGROTATE_MINSIZE="${LOGROTATE_MINSIZE-10M}"
|
||||||
LOGROTATE_MAXAGE="${LOGROTATE_MAXAGE-7}"
|
LOGROTATE_MAXAGE="${LOGROTATE_MAXAGE-7}"
|
||||||
|
LOGROTATE_CRON="${LOGROTATE_CRON-0 0 * * *}"
|
||||||
DNS_RESOLVERS="${DNS_RESOLVERS-127.0.0.11}"
|
DNS_RESOLVERS="${DNS_RESOLVERS-127.0.0.11}"
|
||||||
USE_WHITELIST_IP="${USE_WHITELIST_IP-yes}"
|
USE_WHITELIST_IP="${USE_WHITELIST_IP-yes}"
|
||||||
WHITELIST_IP_LIST="${WHITELIST_IP_LIST-127.0.0.1 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}"
|
WHITELIST_IP_LIST="${WHITELIST_IP_LIST-127.0.0.1 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}"
|
||||||
@@ -94,10 +105,14 @@ USE_LIMIT_REQ="${USE_LIMIT_REQ-yes}"
|
|||||||
LIMIT_REQ_RATE="${LIMIT_REQ_RATE-20r/s}"
|
LIMIT_REQ_RATE="${LIMIT_REQ_RATE-20r/s}"
|
||||||
LIMIT_REQ_BURST="${LIMIT_REQ_BURST-40}"
|
LIMIT_REQ_BURST="${LIMIT_REQ_BURST-40}"
|
||||||
LIMIT_REQ_CACHE="${LIMIT_REQ_CACHE-10m}"
|
LIMIT_REQ_CACHE="${LIMIT_REQ_CACHE-10m}"
|
||||||
|
USE_LIMIT_CONN="${USE_LIMIT_CONN-yes}"
|
||||||
|
LIMIT_CONN_MAX="${LIMIT_CONN_MAX-40}"
|
||||||
|
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}"
|
||||||
PROXY_REAL_IP_HEADER="${PROXY_REAL_IP_HEADER-X-Forwarded-For}"
|
PROXY_REAL_IP_HEADER="${PROXY_REAL_IP_HEADER-X-Forwarded-For}"
|
||||||
PROXY_REAL_IP_RECURSIVE="${PROXY_REAL_IP_RECURSIVE-on}"
|
PROXY_REAL_IP_RECURSIVE="${PROXY_REAL_IP_RECURSIVE-on}"
|
||||||
|
GEOIP_CRON="${GEOIP_CRON-0 4 2 * *}"
|
||||||
GENERATE_SELF_SIGNED_SSL="${GENERATE_SELF_SIGNED_SSL-no}"
|
GENERATE_SELF_SIGNED_SSL="${GENERATE_SELF_SIGNED_SSL-no}"
|
||||||
SELF_SIGNED_SSL_EXPIRY="${SELF_SIGNED_SSL_EXPIRY-365}"
|
SELF_SIGNED_SSL_EXPIRY="${SELF_SIGNED_SSL_EXPIRY-365}"
|
||||||
SELF_SIGNED_SSL_COUNTRY="${SELF_SIGNED_SSL_COUNTRY-CH}"
|
SELF_SIGNED_SSL_COUNTRY="${SELF_SIGNED_SSL_COUNTRY-CH}"
|
||||||
@@ -111,3 +126,6 @@ USE_ANTIBOT="${USE_ANTIBOT-no}"
|
|||||||
ANTIBOT_RECAPTCHA_SCORE="${ANTIBOT_RECAPTCHA_SCORE-0.7}"
|
ANTIBOT_RECAPTCHA_SCORE="${ANTIBOT_RECAPTCHA_SCORE-0.7}"
|
||||||
ANTIBOT_SESSION_SECRET="${ANTIBOT_SESSION_SECRET-random}"
|
ANTIBOT_SESSION_SECRET="${ANTIBOT_SESSION_SECRET-random}"
|
||||||
USE_CROWDSEC="${USE_CROWDSEC-no}"
|
USE_CROWDSEC="${USE_CROWDSEC-no}"
|
||||||
|
USE_API="${USE_API-no}"
|
||||||
|
API_URI="${API_URI-random}"
|
||||||
|
SWARM_MODE="${SWARM_MODE-no}"
|
||||||
|
|||||||
@@ -25,53 +25,104 @@ function trap_exit() {
|
|||||||
pkill -TERM rsyslogd
|
pkill -TERM rsyslogd
|
||||||
pkill -TERM tail
|
pkill -TERM tail
|
||||||
}
|
}
|
||||||
trap "trap_exit" TERM INT
|
trap "trap_exit" TERM INT QUIT
|
||||||
|
|
||||||
|
# trap SIGHUP
|
||||||
|
function trap_reload() {
|
||||||
|
echo "[*] Catched reload operation"
|
||||||
|
if [ "$MULTISITE" = "yes" ] && [ "$SWARM_MODE" != "yes" ] ; then
|
||||||
|
/opt/entrypoint/multisite-config.sh
|
||||||
|
fi
|
||||||
|
if [ -f /tmp/nginx.pid ] ; then
|
||||||
|
echo "[*] Reloading nginx ..."
|
||||||
|
nginx -s reload
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
echo "[*] Reload successfull"
|
||||||
|
else
|
||||||
|
echo "[!] Reload failed"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "[!] Ignored reload operation because nginx is not running"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap "trap_reload" HUP
|
||||||
|
|
||||||
# do the configuration magic if needed
|
# do the configuration magic if needed
|
||||||
if [ ! -f "/opt/installed" ] ; then
|
if [ ! -f "/opt/installed" ] ; then
|
||||||
|
|
||||||
echo "[*] Configuring bunkerized-nginx ..."
|
echo "[*] Configuring bunkerized-nginx ..."
|
||||||
/opt/entrypoint/global-config.sh
|
|
||||||
if [ "$MULTISITE" = "yes" ] ; then
|
# logs config
|
||||||
for server in $SERVER_NAME ; do
|
/opt/entrypoint/logs.sh
|
||||||
/opt/entrypoint/site-config.sh "$server"
|
|
||||||
echo "[*] Multi site - $server configuration done"
|
# lua config
|
||||||
done
|
# TODO : move variables from /usr/local/lib/lua + multisite support ?
|
||||||
else
|
/opt/entrypoint/lua.sh
|
||||||
/opt/entrypoint/site-config.sh
|
|
||||||
echo "[*] Single site - $SERVER_NAME configuration done"
|
# fail2ban config
|
||||||
|
/opt/entrypoint/fail2ban.sh
|
||||||
|
|
||||||
|
# clamav config
|
||||||
|
/opt/entrypoint/clamav.sh
|
||||||
|
|
||||||
|
# start temp nginx to solve Let's Encrypt challenges if needed
|
||||||
|
/opt/entrypoint/nginx-temp.sh
|
||||||
|
|
||||||
|
# only do config if we are not in swarm mode
|
||||||
|
if [ "$SWARM_MODE" = "no" ] ; then
|
||||||
|
# global config
|
||||||
|
/opt/entrypoint/global-config.sh
|
||||||
|
# background jobs
|
||||||
|
/opt/entrypoint/jobs.sh
|
||||||
|
# multisite configs
|
||||||
|
if [ "$MULTISITE" = "yes" ] ; then
|
||||||
|
for server in $SERVER_NAME ; do
|
||||||
|
/opt/entrypoint/site-config.sh "$server"
|
||||||
|
echo "[*] Multi site - $server configuration done"
|
||||||
|
done
|
||||||
|
/opt/entrypoint/multisite-config.sh
|
||||||
|
# singlesite config
|
||||||
|
else
|
||||||
|
/opt/entrypoint/site-config.sh
|
||||||
|
echo "[*] Single site - $SERVER_NAME configuration done"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
touch /opt/installed
|
touch /opt/installed
|
||||||
else
|
else
|
||||||
echo "[*] Skipping configuration process"
|
echo "[*] Skipping configuration process"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# fix nginx configs rights (and modules through the symlink)
|
|
||||||
chown -R root:nginx /etc/nginx/
|
|
||||||
chmod -R 740 /etc/nginx/
|
|
||||||
find /etc/nginx -type d -exec chmod 750 {} \;
|
|
||||||
|
|
||||||
# fix let's encrypt rights
|
|
||||||
if [ "$AUTO_LETS_ENCRYPT" = "yes" ] ; then
|
|
||||||
chown -R root:nginx /etc/letsencrypt
|
|
||||||
chmod -R 740 /etc/letsencrypt
|
|
||||||
find /etc/letsencrypt -type d -exec chmod 750 {} \;
|
|
||||||
fi
|
|
||||||
|
|
||||||
# start rsyslogd
|
# start rsyslogd
|
||||||
rsyslogd
|
rsyslogd -i /tmp/rsyslogd.pid
|
||||||
|
|
||||||
# start crond
|
# start crond
|
||||||
crond
|
crond
|
||||||
|
|
||||||
# start nginx
|
# wait until config has been generated if we are in swarm mode
|
||||||
if [ -f "/tmp/nginx.pid" ] ; then
|
if [ "$SWARM_MODE" = "yes" ] ; then
|
||||||
nginx -s quit
|
echo "[*] Waiting until config has been generated ..."
|
||||||
|
while [ ! -f "/etc/nginx/autoconf" ] ; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# stop temp config if needed
|
||||||
|
if [ -f "/tmp/nginx-temp.pid" ] ; then
|
||||||
|
nginx -c /tmp/nginx-temp.conf -s quit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# run nginx
|
||||||
echo "[*] Running nginx ..."
|
echo "[*] Running nginx ..."
|
||||||
su -s "/usr/sbin/nginx" nginx
|
nginx
|
||||||
|
if [ "$?" -eq 0 ] ; then
|
||||||
|
echo "[*] nginx successfully started !"
|
||||||
|
else
|
||||||
|
echo "[!] nginx failed to start"
|
||||||
|
fi
|
||||||
|
|
||||||
# list of log files to display
|
# list of log files to display
|
||||||
LOGS="/var/log/access.log /var/log/error.log"
|
LOGS="/var/log/access.log /var/log/error.log /var/log/jobs.log"
|
||||||
|
|
||||||
# start fail2ban
|
# start fail2ban
|
||||||
if [ "$USE_FAIL2BAN" = "yes" ] ; then
|
if [ "$USE_FAIL2BAN" = "yes" ] ; then
|
||||||
@@ -80,12 +131,6 @@ if [ "$USE_FAIL2BAN" = "yes" ] ; then
|
|||||||
LOGS="$LOGS /var/log/fail2ban.log"
|
LOGS="$LOGS /var/log/fail2ban.log"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# start crowdsec
|
|
||||||
if [ "$USE_CROWDSEC" = "yes" ] ; then
|
|
||||||
echo "[*] Running crowdsec ..."
|
|
||||||
crowdsec
|
|
||||||
fi
|
|
||||||
|
|
||||||
# autotest
|
# autotest
|
||||||
if [ "$1" == "test" ] ; then
|
if [ "$1" == "test" ] ; then
|
||||||
sleep 10
|
sleep 10
|
||||||
@@ -97,17 +142,12 @@ if [ "$1" == "test" ] ; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# start the autoconf manager
|
|
||||||
if [ -S "/var/run/docker.sock" ] ; then
|
|
||||||
echo "[*] Running autoconf ..."
|
|
||||||
touch /var/log/autoconf.log
|
|
||||||
/opt/autoconf/autoconf.py > /var/log/autoconf.log 2>&1 &
|
|
||||||
LOGS="$LOGS /var/log/autoconf.log"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# display logs
|
# display logs
|
||||||
tail -F $LOGS &
|
tail -F $LOGS &
|
||||||
wait $!
|
pid="$!"
|
||||||
|
while [ -f "/tmp/nginx.pid" ] ; do
|
||||||
|
wait "$pid"
|
||||||
|
done
|
||||||
|
|
||||||
# sigterm trapped
|
# sigterm trapped
|
||||||
echo "[*] bunkerized-nginx stopped"
|
echo "[*] bunkerized-nginx stopped"
|
||||||
|
|||||||
19
entrypoint/fail2ban.sh
Normal file
19
entrypoint/fail2ban.sh
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# load default values
|
||||||
|
. /opt/entrypoint/defaults.sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# fail2ban setup
|
||||||
|
if [ "$(has_value USE_FAIL2BAN yes)" != "" ] ; then
|
||||||
|
cp /opt/fail2ban/nginx-action.local /etc/fail2ban/action.d/nginx-action.local
|
||||||
|
cp /opt/fail2ban/nginx-filter.local /etc/fail2ban/filter.d/nginx-filter.local
|
||||||
|
cp /opt/fail2ban/nginx-jail.local /etc/fail2ban/jail.d/nginx-jail.local
|
||||||
|
replace_in_file "/etc/fail2ban/jail.d/nginx-jail.local" "%FAIL2BAN_BANTIME%" "$FAIL2BAN_BANTIME"
|
||||||
|
replace_in_file "/etc/fail2ban/jail.d/nginx-jail.local" "%FAIL2BAN_FINDTIME%" "$FAIL2BAN_FINDTIME"
|
||||||
|
replace_in_file "/etc/fail2ban/jail.d/nginx-jail.local" "%FAIL2BAN_MAXRETRY%" "$FAIL2BAN_MAXRETRY"
|
||||||
|
replace_in_file "/etc/fail2ban/jail.d/nginx-jail.local" "%FAIL2BAN_IGNOREIP%" "$FAIL2BAN_IGNOREIP"
|
||||||
|
replace_in_file "/etc/fail2ban/filter.d/nginx-filter.local" "%FAIL2BAN_STATUS_CODES%" "$FAIL2BAN_STATUS_CODES"
|
||||||
|
fi
|
||||||
@@ -7,25 +7,8 @@
|
|||||||
. /opt/entrypoint/utils.sh
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
# copy stub confs
|
# copy stub confs
|
||||||
cp /opt/logs/rsyslog.conf /etc/rsyslog.conf
|
|
||||||
cp /opt/logs/logrotate.conf /etc/logrotate.conf
|
|
||||||
cp -r /opt/lua/* /usr/local/lib/lua
|
|
||||||
cp /opt/confs/global/* /etc/nginx/
|
cp /opt/confs/global/* /etc/nginx/
|
||||||
|
|
||||||
# remove cron jobs
|
|
||||||
echo "" > /etc/crontabs/root
|
|
||||||
|
|
||||||
# install additional modules if needed
|
|
||||||
if [ "$ADDITIONAL_MODULES" != "" ] ; then
|
|
||||||
apk add $ADDITIONAL_MODULES
|
|
||||||
fi
|
|
||||||
|
|
||||||
# start nginx with temp conf for let's encrypt challenges
|
|
||||||
if [ "$(has_value AUTO_LETS_ENCRYPT yes)" != "" ] ; then
|
|
||||||
replace_in_file "/etc/nginx/nginx-temp.conf" "%HTTP_PORT%" "$HTTP_PORT"
|
|
||||||
nginx -c /etc/nginx/nginx-temp.conf
|
|
||||||
fi
|
|
||||||
|
|
||||||
# include server block(s)
|
# include server block(s)
|
||||||
if [ "$MULTISITE" = "yes" ] ; then
|
if [ "$MULTISITE" = "yes" ] ; then
|
||||||
includes=""
|
includes=""
|
||||||
@@ -100,7 +83,7 @@ if [ "$AUTO_LETS_ENCRYPT" = "yes" ] ; then
|
|||||||
/opt/scripts/certbot-new.sh "$DOMAINS_LETS_ENCRYPT" "$EMAIL_LETS_ENCRYPT"
|
/opt/scripts/certbot-new.sh "$DOMAINS_LETS_ENCRYPT" "$EMAIL_LETS_ENCRYPT"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
echo "0 0 * * * /opt/scripts/certbot-renew.sh > /dev/null 2>&1" >> /etc/crontabs/root
|
echo "$AUTO_LETS_ENCRYPT_CRON /opt/scripts/certbot-renew.sh > /dev/null 2>&1" >> /etc/crontabs/nginx
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# self-signed certificate
|
# self-signed certificate
|
||||||
@@ -119,14 +102,7 @@ if [ "$BLACKLIST_COUNTRY" != "" ] || [ "$WHITELIST_COUNTRY" != "" ] ; then
|
|||||||
replace_in_file "/etc/nginx/geoip.conf" "%DEFAULT%" "yes"
|
replace_in_file "/etc/nginx/geoip.conf" "%DEFAULT%" "yes"
|
||||||
replace_in_file "/etc/nginx/geoip.conf" "%COUNTRY%" "$(echo $BLACKLIST_COUNTRY | sed 's/ / no;\\n/g') no;"
|
replace_in_file "/etc/nginx/geoip.conf" "%COUNTRY%" "$(echo $BLACKLIST_COUNTRY | sed 's/ / no;\\n/g') no;"
|
||||||
fi
|
fi
|
||||||
echo "0 0 2 * * /opt/scripts/geoip.sh" >> /etc/crontabs/root
|
echo "$GEOIP_CRON /opt/scripts/geoip.sh" >> /etc/crontabs/nginx
|
||||||
if [ -f "/cache/geoip.mmdb" ] ; then
|
|
||||||
echo "[*] Copying cached geoip.mmdb ..."
|
|
||||||
cp /cache/geoip.mmdb /etc/nginx/geoip.mmdb
|
|
||||||
else
|
|
||||||
echo "[*] Downloading GeoIP database (in background) ..."
|
|
||||||
/opt/scripts/geoip.sh &
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%USE_COUNTRY%" ""
|
replace_in_file "/etc/nginx/nginx.conf" "%USE_COUNTRY%" ""
|
||||||
fi
|
fi
|
||||||
@@ -134,14 +110,7 @@ fi
|
|||||||
# block bad UA
|
# block bad UA
|
||||||
if [ "$(has_value BLOCK_USER_AGENT yes)" != "" ] ; then
|
if [ "$(has_value BLOCK_USER_AGENT yes)" != "" ] ; then
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%BLOCK_USER_AGENT%" "include /etc/nginx/map-user-agent.conf;"
|
replace_in_file "/etc/nginx/nginx.conf" "%BLOCK_USER_AGENT%" "include /etc/nginx/map-user-agent.conf;"
|
||||||
echo "0 0 * * * /opt/scripts/user-agents.sh" >> /etc/crontabs/root
|
echo "$BLOCK_USER_AGENT_CRON /opt/scripts/user-agents.sh" >> /etc/crontabs/nginx
|
||||||
if [ -f "/cache/map-user-agent.conf" ] ; then
|
|
||||||
echo "[*] Copying cached map-user-agent.conf ..."
|
|
||||||
cp /cache/map-user-agent.conf /etc/nginx/map-user-agent.conf
|
|
||||||
else
|
|
||||||
echo "[*] Downloading bad user-agent list (in background) ..."
|
|
||||||
/opt/scripts/user-agents.sh &
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%BLOCK_USER_AGENT%" ""
|
replace_in_file "/etc/nginx/nginx.conf" "%BLOCK_USER_AGENT%" ""
|
||||||
fi
|
fi
|
||||||
@@ -149,57 +118,27 @@ fi
|
|||||||
# block bad refferer
|
# block bad refferer
|
||||||
if [ "$(has_value BLOCK_REFERRER yes)" != "" ] ; then
|
if [ "$(has_value BLOCK_REFERRER yes)" != "" ] ; then
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%BLOCK_REFERRER%" "include /etc/nginx/map-referrer.conf;"
|
replace_in_file "/etc/nginx/nginx.conf" "%BLOCK_REFERRER%" "include /etc/nginx/map-referrer.conf;"
|
||||||
echo "0 0 * * * /opt/scripts/referrers.sh" >> /etc/crontabs/root
|
echo "$BLOCK_REFERRER_CRON /opt/scripts/referrers.sh" >> /etc/crontabs/nginx
|
||||||
if [ -f "/cache/map-referrer.conf" ] ; then
|
|
||||||
echo "[*] Copying cached map-referrer.conf ..."
|
|
||||||
cp /cache/map-referrer.conf /etc/nginx/map-referrer.conf
|
|
||||||
else
|
|
||||||
echo "[*] Downloading bad referrer list (in background) ..."
|
|
||||||
/opt/scripts/referrers.sh &
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%BLOCK_REFERRER%" ""
|
replace_in_file "/etc/nginx/nginx.conf" "%BLOCK_REFERRER%" ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# block TOR exit nodes
|
# block TOR exit nodes
|
||||||
if [ "$(has_value BLOCK_TOR_EXIT_NODE yes)" != "" ] ; then
|
if [ "$(has_value BLOCK_TOR_EXIT_NODE yes)" != "" ] ; then
|
||||||
echo "0 * * * * /opt/scripts/exit-nodes.sh" >> /etc/crontabs/root
|
echo "$BLOCK_TOR_EXIT_NODE_CRON /opt/scripts/exit-nodes.sh" >> /etc/crontabs/nginx
|
||||||
if [ -f "/cache/block-tor-exit-node.conf" ] ; then
|
|
||||||
echo "[*] Copying cached block-tor-exit-node.conf ..."
|
|
||||||
cp /cache/block-tor-exit-node.conf /etc/nginx/block-tor-exit-node.conf
|
|
||||||
else
|
|
||||||
echo "[*] Downloading tor exit nodes list (in background) ..."
|
|
||||||
/opt/scripts/exit-nodes.sh &
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# block proxies
|
# block proxies
|
||||||
if [ "$(has_value BLOCK_PROXIES yes)" != "" ] ; then
|
if [ "$(has_value BLOCK_PROXIES yes)" != "" ] ; then
|
||||||
echo "0 0 * * * /opt/scripts/proxies.sh" >> /etc/crontabs/root
|
echo "$BLOCK_PROXIES_CRON /opt/scripts/proxies.sh" >> /etc/crontabs/nginx
|
||||||
if [ -f "/cache/block-proxies.conf" ] ; then
|
|
||||||
echo "[*] Copying cached block-proxies.conf ..."
|
|
||||||
cp /cache/block-proxies.conf /etc/nginx/block-proxies.conf
|
|
||||||
else
|
|
||||||
echo "[*] Downloading proxies list (in background) ..."
|
|
||||||
/opt/scripts/proxies.sh &
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# block abusers
|
# block abusers
|
||||||
if [ "$(has_value BLOCK_ABUSERS yes)" != "" ] ; then
|
if [ "$(has_value BLOCK_ABUSERS yes)" != "" ] ; then
|
||||||
echo "0 0 * * * /opt/scripts/abusers.sh" >> /etc/crontabs/root
|
echo "$BLOCK_ABUSERS_CRON /opt/scripts/abusers.sh" >> /etc/crontabs/nginx
|
||||||
if [ -f "/cache/block-abusers.conf" ] ; then
|
|
||||||
echo "[*] Copying cached block-abusers.conf ..."
|
|
||||||
cp /cache/block-abusers.conf /etc/nginx/block-abusers.conf
|
|
||||||
else
|
|
||||||
echo "[*] Downloading abusers list (in background) ..."
|
|
||||||
/opt/scripts/abusers.sh &
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# DNS resolvers
|
# DNS resolvers
|
||||||
resolvers=$(spaces_to_lua "$DNS_RESOLVERS")
|
|
||||||
replace_in_file "/usr/local/lib/lua/dns.lua" "%DNS_RESOLVERS%" "$resolvers"
|
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%DNS_RESOLVERS%" "$DNS_RESOLVERS"
|
replace_in_file "/etc/nginx/nginx.conf" "%DNS_RESOLVERS%" "$DNS_RESOLVERS"
|
||||||
|
|
||||||
# whitelist IP
|
# whitelist IP
|
||||||
@@ -208,8 +147,6 @@ if [ "$(has_value USE_WHITELIST_IP yes)" != "" ] ; then
|
|||||||
else
|
else
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%WHITELIST_IP_CACHE%" ""
|
replace_in_file "/etc/nginx/nginx.conf" "%WHITELIST_IP_CACHE%" ""
|
||||||
fi
|
fi
|
||||||
list=$(spaces_to_lua "$WHITELIST_IP_LIST")
|
|
||||||
replace_in_file "/usr/local/lib/lua/whitelist.lua" "%WHITELIST_IP_LIST%" "$list"
|
|
||||||
|
|
||||||
# whitelist rDNS
|
# whitelist rDNS
|
||||||
if [ "$(has_value USE_WHITELIST_REVERSE yes)" != "" ] ; then
|
if [ "$(has_value USE_WHITELIST_REVERSE yes)" != "" ] ; then
|
||||||
@@ -217,8 +154,6 @@ if [ "$(has_value USE_WHITELIST_REVERSE yes)" != "" ] ; then
|
|||||||
else
|
else
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%WHITELIST_REVERSE_CACHE%" ""
|
replace_in_file "/etc/nginx/nginx.conf" "%WHITELIST_REVERSE_CACHE%" ""
|
||||||
fi
|
fi
|
||||||
list=$(spaces_to_lua "$WHITELIST_REVERSE_LIST")
|
|
||||||
replace_in_file "/usr/local/lib/lua/whitelist.lua" "%WHITELIST_REVERSE_LIST%" "$list"
|
|
||||||
|
|
||||||
# blacklist IP
|
# blacklist IP
|
||||||
if [ "$(has_value USE_BLACKLIST_IP yes)" != "" ] ; then
|
if [ "$(has_value USE_BLACKLIST_IP yes)" != "" ] ; then
|
||||||
@@ -226,8 +161,6 @@ if [ "$(has_value USE_BLACKLIST_IP yes)" != "" ] ; then
|
|||||||
else
|
else
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%BLACKLIST_IP_CACHE%" ""
|
replace_in_file "/etc/nginx/nginx.conf" "%BLACKLIST_IP_CACHE%" ""
|
||||||
fi
|
fi
|
||||||
list=$(spaces_to_lua "$BLACKLIST_IP_LIST")
|
|
||||||
replace_in_file "/usr/local/lib/lua/blacklist.lua" "%BLACKLIST_IP_LIST%" "$list"
|
|
||||||
|
|
||||||
# blacklist rDNS
|
# blacklist rDNS
|
||||||
if [ "$(has_value USE_BLACKLIST_REVERSE yes)" != "" ] ; then
|
if [ "$(has_value USE_BLACKLIST_REVERSE yes)" != "" ] ; then
|
||||||
@@ -235,8 +168,6 @@ if [ "$(has_value USE_BLACKLIST_REVERSE yes)" != "" ] ; then
|
|||||||
else
|
else
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%BLACKLIST_REVERSE_CACHE%" ""
|
replace_in_file "/etc/nginx/nginx.conf" "%BLACKLIST_REVERSE_CACHE%" ""
|
||||||
fi
|
fi
|
||||||
list=$(spaces_to_lua "$BLACKLIST_REVERSE_LIST")
|
|
||||||
replace_in_file "/usr/local/lib/lua/blacklist.lua" "%BLACKLIST_REVERSE_LIST%" "$list"
|
|
||||||
|
|
||||||
# request limiting
|
# request limiting
|
||||||
if [ "$(has_value USE_LIMIT_REQ yes)" != "" ] ; then
|
if [ "$(has_value USE_LIMIT_REQ yes)" != "" ] ; then
|
||||||
@@ -245,14 +176,19 @@ else
|
|||||||
replace_in_file "/etc/nginx/nginx.conf" "%LIMIT_REQ_ZONE%" ""
|
replace_in_file "/etc/nginx/nginx.conf" "%LIMIT_REQ_ZONE%" ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# connection limiting
|
||||||
|
if [ "$(has_value USE_LIMIT_CONN yes)" != "" ] ; then
|
||||||
|
replace_in_file "/etc/nginx/nginx.conf" "%LIMIT_CONN_ZONE%" "limit_conn_zone \$binary_remote_addr zone=ddos:${LIMIT_CONN_CACHE};"
|
||||||
|
else
|
||||||
|
replace_in_file "/etc/nginx/nginx.conf" "%LIMIT_CONN_ZONE%" ""
|
||||||
|
fi
|
||||||
|
|
||||||
# DNSBL
|
# DNSBL
|
||||||
if [ "$(has_value USE_DNSBL yes)" != "" ] ; then
|
if [ "$(has_value USE_DNSBL yes)" != "" ] ; then
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%DNSBL_CACHE%" "lua_shared_dict dnsbl_cache 10m;"
|
replace_in_file "/etc/nginx/nginx.conf" "%DNSBL_CACHE%" "lua_shared_dict dnsbl_cache 10m;"
|
||||||
else
|
else
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%DNSBL_CACHE%" "lua_shared_dict dnsbl_cache 10m;"
|
replace_in_file "/etc/nginx/nginx.conf" "%DNSBL_CACHE%" "lua_shared_dict dnsbl_cache 10m;"
|
||||||
fi
|
fi
|
||||||
list=$(spaces_to_lua "$DNSBL_LIST")
|
|
||||||
replace_in_file "/usr/local/lib/lua/dnsbl.lua" "%DNSBL_LIST%" "$list"
|
|
||||||
|
|
||||||
# disable default site
|
# disable default site
|
||||||
if [ "$DISABLE_DEFAULT_SERVER" = "yes" ] && [ "$MULTISITE" = "yes" ] ; then
|
if [ "$DISABLE_DEFAULT_SERVER" = "yes" ] && [ "$MULTISITE" = "yes" ] ; then
|
||||||
@@ -264,46 +200,23 @@ fi
|
|||||||
# fail2ban setup
|
# fail2ban setup
|
||||||
if [ "$(has_value USE_FAIL2BAN yes)" != "" ] ; then
|
if [ "$(has_value USE_FAIL2BAN yes)" != "" ] ; then
|
||||||
echo "" > /etc/nginx/fail2ban-ip.conf
|
echo "" > /etc/nginx/fail2ban-ip.conf
|
||||||
rm -rf /etc/fail2ban/jail.d/*.conf
|
|
||||||
cp /opt/fail2ban/nginx-action.local /etc/fail2ban/action.d/nginx-action.local
|
|
||||||
cp /opt/fail2ban/nginx-filter.local /etc/fail2ban/filter.d/nginx-filter.local
|
|
||||||
cp /opt/fail2ban/nginx-jail.local /etc/fail2ban/jail.d/nginx-jail.local
|
|
||||||
replace_in_file "/etc/fail2ban/jail.d/nginx-jail.local" "%FAIL2BAN_BANTIME%" "$FAIL2BAN_BANTIME"
|
|
||||||
replace_in_file "/etc/fail2ban/jail.d/nginx-jail.local" "%FAIL2BAN_FINDTIME%" "$FAIL2BAN_FINDTIME"
|
|
||||||
replace_in_file "/etc/fail2ban/jail.d/nginx-jail.local" "%FAIL2BAN_MAXRETRY%" "$FAIL2BAN_MAXRETRY"
|
|
||||||
replace_in_file "/etc/fail2ban/filter.d/nginx-filter.local" "%FAIL2BAN_STATUS_CODES%" "$FAIL2BAN_STATUS_CODES"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# clamav setup
|
|
||||||
if [ "$(has_value USE_CLAMAV_UPLOAD yes)" != "" ] || [ "$USE_CLAMAV_SCAN" = "yes" ] ; then
|
|
||||||
echo "[*] Updating clamav (in background) ..."
|
|
||||||
freshclam > /dev/null 2>&1 &
|
|
||||||
echo "0 0 * * * /usr/bin/freshclam > /dev/null 2>&1" >> /etc/crontabs/root
|
|
||||||
fi
|
|
||||||
if [ "$USE_CLAMAV_SCAN" = "yes" ] ; then
|
|
||||||
if [ "$USE_CLAMAV_SCAN_REMOVE" = "yes" ] ; then
|
|
||||||
echo "0 */1 * * * /usr/bin/clamscan -r -i --no-summary --remove / >> /var/log/clamav.log 2>&1" >> /etc/crontabs/root
|
|
||||||
else
|
|
||||||
echo "0 */1 * * * /usr/bin/clamscan -r -i --no-summary / >> /var/log/clamav.log 2>&1" >> /etc/crontabs/root
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# CrowdSec setup
|
# CrowdSec setup
|
||||||
if [ "$(has_value USE_CROWDSEC yes)" != "" ] ; then
|
if [ "$(has_value USE_CROWDSEC yes)" != "" ] ; then
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%USE_CROWDSEC%" "include /etc/nginx/crowdsec.conf;"
|
replace_in_file "/etc/nginx/nginx.conf" "%USE_CROWDSEC%" "include /etc/nginx/crowdsec.conf;"
|
||||||
cp /opt/crowdsec/acquis.yaml /etc/crowdsec/config/acquis.yaml
|
|
||||||
cscli api register >> /etc/crowdsec/config/api.yaml
|
|
||||||
cscli api pull
|
|
||||||
echo "0 0 * * * /usr/local/bin/cscli api pull > /dev/null 2>&1" >> /etc/crontabs/root
|
|
||||||
else
|
else
|
||||||
replace_in_file "/etc/nginx/nginx.conf" "%USE_CROWDSEC%" ""
|
replace_in_file "/etc/nginx/nginx.conf" "%USE_CROWDSEC%" ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# create empty logs
|
# API
|
||||||
touch /var/log/access.log
|
if [ "$USE_API" = "yes" ] ; then
|
||||||
touch /var/log/error.log
|
replace_in_file "/etc/nginx/nginx.conf" "%USE_API%" "include /etc/nginx/api.conf;"
|
||||||
|
if [ "$API_URI" = "random" ] ; then
|
||||||
# setup logrotate
|
API_URI="/$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)"
|
||||||
replace_in_file "/etc/logrotate.conf" "%LOGROTATE_MAXAGE%" "$LOGROTATE_MAXAGE"
|
echo "[*] Generated API URI : $API_URI"
|
||||||
replace_in_file "/etc/logrotate.conf" "%LOGROTATE_MINSIZE%" "$LOGROTATE_MINSIZE"
|
fi
|
||||||
echo "0 0 * * * /opt/scripts/logrotate.sh > /dev/null 2>&1" >> /etc/crontabs/root
|
replace_in_file "/etc/nginx/api.conf" "%API_URI%" "$API_URI"
|
||||||
|
else
|
||||||
|
replace_in_file "/etc/nginx/nginx.conf" "%USE_API%" ""
|
||||||
|
fi
|
||||||
|
|||||||
73
entrypoint/jobs.sh
Normal file
73
entrypoint/jobs.sh
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# load default values
|
||||||
|
. ./opt/entrypoint/defaults.sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# GeoIP
|
||||||
|
if [ "$BLACKLIST_COUNTRY" != "" ] || [ "$WHITELIST_COUNTRY" != "" ] ; then
|
||||||
|
if [ -f "/cache/geoip.mmdb" ] ; then
|
||||||
|
echo "[*] Copying cached geoip.mmdb ..."
|
||||||
|
cp /cache/geoip.mmdb /etc/nginx/geoip.mmdb
|
||||||
|
else
|
||||||
|
echo "[*] Downloading GeoIP database (in background) ..."
|
||||||
|
/opt/scripts/geoip.sh > /dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# User-Agents
|
||||||
|
if [ "$(has_value BLOCK_USER_AGENT yes)" != "" ] ; then
|
||||||
|
if [ -f "/cache/map-user-agent.conf" ] ; then
|
||||||
|
echo "[*] Copying cached map-user-agent.conf ..."
|
||||||
|
cp /cache/map-user-agent.conf /etc/nginx/map-user-agent.conf
|
||||||
|
else
|
||||||
|
echo "[*] Downloading bad user-agent list (in background) ..."
|
||||||
|
/opt/scripts/user-agents.sh > /dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Referrers
|
||||||
|
if [ "$(has_value BLOCK_REFERRER yes)" != "" ] ; then
|
||||||
|
if [ -f "/cache/map-referrer.conf" ] ; then
|
||||||
|
echo "[*] Copying cached map-referrer.conf ..."
|
||||||
|
cp /cache/map-referrer.conf /etc/nginx/map-referrer.conf
|
||||||
|
else
|
||||||
|
echo "[*] Downloading bad referrer list (in background) ..."
|
||||||
|
/opt/scripts/referrers.sh > /dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# exit nodes
|
||||||
|
if [ "$(has_value BLOCK_TOR_EXIT_NODE yes)" != "" ] ; then
|
||||||
|
if [ -f "/cache/block-tor-exit-node.conf" ] ; then
|
||||||
|
echo "[*] Copying cached block-tor-exit-node.conf ..."
|
||||||
|
cp /cache/block-tor-exit-node.conf /etc/nginx/block-tor-exit-node.conf
|
||||||
|
else
|
||||||
|
echo "[*] Downloading tor exit nodes list (in background) ..."
|
||||||
|
/opt/scripts/exit-nodes.sh > /dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# proxies
|
||||||
|
if [ "$(has_value BLOCK_PROXIES yes)" != "" ] ; then
|
||||||
|
if [ -f "/cache/block-proxies.conf" ] ; then
|
||||||
|
echo "[*] Copying cached block-proxies.conf ..."
|
||||||
|
cp /cache/block-proxies.conf /etc/nginx/block-proxies.conf
|
||||||
|
else
|
||||||
|
echo "[*] Downloading proxies list (in background) ..."
|
||||||
|
/opt/scripts/proxies.sh > /dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# abusers
|
||||||
|
if [ "$(has_value BLOCK_ABUSERS yes)" != "" ] ; then
|
||||||
|
if [ -f "/cache/block-abusers.conf" ] ; then
|
||||||
|
echo "[*] Copying cached block-abusers.conf ..."
|
||||||
|
cp /cache/block-abusers.conf /etc/nginx/block-abusers.conf
|
||||||
|
else
|
||||||
|
echo "[*] Downloading abusers list (in background) ..."
|
||||||
|
/opt/scripts/abusers.sh > /dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
fi
|
||||||
21
entrypoint/logs.sh
Normal file
21
entrypoint/logs.sh
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# load default values
|
||||||
|
. /opt/entrypoint/defaults.sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# copy stub confs
|
||||||
|
cat /opt/logs/rsyslog.conf > /etc/rsyslog.conf
|
||||||
|
cat /opt/logs/logrotate.conf > /etc/logrotate.conf
|
||||||
|
|
||||||
|
# create empty logs
|
||||||
|
touch /var/log/access.log
|
||||||
|
touch /var/log/error.log
|
||||||
|
touch /var/log/jobs.log
|
||||||
|
|
||||||
|
# setup logrotate
|
||||||
|
replace_in_file "/etc/logrotate.conf" "%LOGROTATE_MAXAGE%" "$LOGROTATE_MAXAGE"
|
||||||
|
replace_in_file "/etc/logrotate.conf" "%LOGROTATE_MINSIZE%" "$LOGROTATE_MINSIZE"
|
||||||
|
echo "$LOGROTATE_CRON /opt/scripts/logrotate.sh > /dev/null 2>&1" >> /etc/crontabs/nginx
|
||||||
40
entrypoint/lua.sh
Normal file
40
entrypoint/lua.sh
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# load default values
|
||||||
|
. /opt/entrypoint/defaults.sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# copy stub LUA scripts
|
||||||
|
cp -r /opt/lua/* /usr/local/lib/lua
|
||||||
|
|
||||||
|
# DNS resolvers
|
||||||
|
resolvers=$(spaces_to_lua "$DNS_RESOLVERS")
|
||||||
|
replace_in_file "/usr/local/lib/lua/dns.lua" "%DNS_RESOLVERS%" "$resolvers"
|
||||||
|
|
||||||
|
# whitelist IP
|
||||||
|
list=$(spaces_to_lua "$WHITELIST_IP_LIST")
|
||||||
|
replace_in_file "/usr/local/lib/lua/whitelist.lua" "%WHITELIST_IP_LIST%" "$list"
|
||||||
|
|
||||||
|
# whitelist rDNS
|
||||||
|
list=$(spaces_to_lua "$WHITELIST_REVERSE_LIST")
|
||||||
|
replace_in_file "/usr/local/lib/lua/whitelist.lua" "%WHITELIST_REVERSE_LIST%" "$list"
|
||||||
|
|
||||||
|
# blacklist IP
|
||||||
|
list=$(spaces_to_lua "$BLACKLIST_IP_LIST")
|
||||||
|
replace_in_file "/usr/local/lib/lua/blacklist.lua" "%BLACKLIST_IP_LIST%" "$list"
|
||||||
|
|
||||||
|
# blacklist rDNS
|
||||||
|
list=$(spaces_to_lua "$BLACKLIST_REVERSE_LIST")
|
||||||
|
replace_in_file "/usr/local/lib/lua/blacklist.lua" "%BLACKLIST_REVERSE_LIST%" "$list"
|
||||||
|
|
||||||
|
# DNSBL
|
||||||
|
list=$(spaces_to_lua "$DNSBL_LIST")
|
||||||
|
replace_in_file "/usr/local/lib/lua/dnsbl.lua" "%DNSBL_LIST%" "$list"
|
||||||
|
|
||||||
|
# CrowdSec setup
|
||||||
|
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_KEY%" "$CROWDSEC_KEY"
|
||||||
|
fi
|
||||||
40
entrypoint/multisite-config.sh
Normal file
40
entrypoint/multisite-config.sh
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# load default values
|
||||||
|
. /opt/entrypoint/defaults.sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
if [ "$MULTISITE" = "yes" ] ; then
|
||||||
|
servers=$(find /etc/nginx -name "server.conf" | cut -d '/' -f 4)
|
||||||
|
for server in $servers ; do
|
||||||
|
if [ "$server" = "server.conf" ] ; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
SERVER_PREFIX="/etc/nginx/${server}/"
|
||||||
|
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)"
|
||||||
|
fi
|
||||||
|
if grep "modsecurity.conf" ${SERVER_PREFIX}server.conf > /dev/null ; then
|
||||||
|
modsec_custom=""
|
||||||
|
if ls /modsec-confs/*.conf > /dev/null 2>&1 ; then
|
||||||
|
modsec_custom="include /modsec-confs/*.conf\n"
|
||||||
|
fi
|
||||||
|
if ls /modsec-confs/${server}/*.conf > /dev/null 2>&1 ; then
|
||||||
|
modsec_custom="${modsec_custom}include /modsec-confs/${server}/*.conf\n"
|
||||||
|
fi
|
||||||
|
replace_in_file "${SERVER_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_RULES%" "$modsec_custom"
|
||||||
|
if grep "owasp/crs.conf" ${SERVER_PREFIX}modsecurity-rules.conf > /dev/null ; then
|
||||||
|
modsec_crs_custom=""
|
||||||
|
if ls /modsec-crs-confs/*.conf > /dev/null 2>&1 ; then
|
||||||
|
modsec_crs_custom="include /modsec-crs-confs/*.conf\n"
|
||||||
|
fi
|
||||||
|
if ls /modsec-crs-confs/${server}/*.conf > /dev/null 2>&1 ; then
|
||||||
|
modsec_crs_custom="${modsec_crs_custom}include /modsec-crs-confs/${server}/*.conf\n"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
replace_in_file "${SERVER_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_CRS%" "$modsec_crs_custom"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
26
entrypoint/nginx-temp.sh
Normal file
26
entrypoint/nginx-temp.sh
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# load default values
|
||||||
|
. /opt/entrypoint/defaults.sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# start nginx with temp conf for let's encrypt challenges and API
|
||||||
|
if [ "$(has_value AUTO_LETS_ENCRYPT yes)" != "" ] || [ "$SWARM_MODE" = "yes" ] ; then
|
||||||
|
cp /opt/confs/global/nginx-temp.conf /tmp/nginx-temp.conf
|
||||||
|
cp /opt/confs/global/api-temp.conf /tmp/api.conf
|
||||||
|
if [ "$SWARM_MODE" = "yes" ] ; then
|
||||||
|
replace_in_file "/tmp/nginx-temp.conf" "%USE_API%" "include /tmp/api.conf;"
|
||||||
|
replace_in_file "/tmp/api.conf" "%API_URI%" "$API_URI"
|
||||||
|
else
|
||||||
|
replace_in_file "/tmp/nginx-temp.conf" "%USE_API%" ""
|
||||||
|
fi
|
||||||
|
replace_in_file "/tmp/nginx-temp.conf" "%HTTP_PORT%" "$HTTP_PORT"
|
||||||
|
nginx -c /tmp/nginx-temp.conf
|
||||||
|
if [ "$?" -eq 0 ] ; then
|
||||||
|
echo "[*] Successfully started temp nginx"
|
||||||
|
else
|
||||||
|
echo "[!] Can't start temp nginx"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -10,30 +10,39 @@
|
|||||||
NGINX_PREFIX="/etc/nginx/"
|
NGINX_PREFIX="/etc/nginx/"
|
||||||
if [ "$MULTISITE" = "yes" ] ; then
|
if [ "$MULTISITE" = "yes" ] ; then
|
||||||
NGINX_PREFIX="${NGINX_PREFIX}${1}/"
|
NGINX_PREFIX="${NGINX_PREFIX}${1}/"
|
||||||
for var in $(env) ; do
|
if [ ! -d "$NGINX_PREFIX" ] ; then
|
||||||
name=$(echo "$var" | cut -d '=' -f 1)
|
mkdir "$NGINX_PREFIX"
|
||||||
check=$(echo "$name" | grep "^$1_")
|
fi
|
||||||
if [ "$check" != "" ] ; then
|
|
||||||
repl_name=$(echo "$name" | sed "s~${1}_~~")
|
|
||||||
repl_value=$(echo "$var" | sed "s~${name}=~~")
|
|
||||||
read -r "$repl_name" <<< $repl_value
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
ROOT_FOLDER="${ROOT_FOLDER}/$1"
|
ROOT_FOLDER="${ROOT_FOLDER}/$1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# copy stub confs
|
|
||||||
if [ "$MULTISITE" = "yes" ] ; then
|
if [ "$MULTISITE" = "yes" ] ; then
|
||||||
mkdir "$NGINX_PREFIX"
|
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}=~~")
|
||||||
|
read -r "$repl_name" <<< $repl_value
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
set | grep -E -v "^(HOSTNAME|PWD|PKG_RELEASE|NJS_VERSION|SHLVL|PATH|_|NGINX_VERSION|HOME)=" > "${NGINX_PREFIX}nginx.env"
|
||||||
|
if [ "$MULTISITE" = "yes" ] ; then
|
||||||
|
for server in $SERVER_NAME ; do
|
||||||
|
sed -i "~^${server}_.*=.*~d" "${NGINX_PREFIX}nginx.env"
|
||||||
|
done
|
||||||
|
sed -i "~^SERVER_NAME=.*~SERVER_NAME=${1}~" "${NGINX_PREFIX}nginx.env"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# copy stub confs
|
||||||
cp /opt/confs/site/* "$NGINX_PREFIX"
|
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/${1}/*.conf;"
|
||||||
|
replace_in_file "${NGINX_PREFIX}server.conf" "%PRE_SERVER_CONF%" "include /pre-server-confs/*.conf;\ninclude /pre-server-confs/${1}/*.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;"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# max body size
|
# max body size
|
||||||
@@ -45,26 +54,34 @@ replace_in_file "${NGINX_PREFIX}server.conf" "%SERVER_TOKENS%" "$SERVER_TOKENS"
|
|||||||
# reverse proxy
|
# reverse proxy
|
||||||
if [ "$USE_REVERSE_PROXY" = "yes" ] ; then
|
if [ "$USE_REVERSE_PROXY" = "yes" ] ; then
|
||||||
i=1
|
i=1
|
||||||
for var in $(env) ; do
|
for var in $(set | cut -d '=' -f 1 | grep "^REVERSE_PROXY_URL") ; do
|
||||||
check1=$(echo "$var" | grep "^REVERSE_PROXY_URL")
|
url=$(echo "$var")
|
||||||
check2=$(echo "$var" | grep "^${1}_REVERSE_PROXY_URL")
|
url_value=$(echo "${!var}")
|
||||||
if [ "$check1" != "" ] || [ "$check2" != "" ] ; then
|
host=$(echo "$var" | sed "s/URL/HOST/")
|
||||||
name=$(echo "$var" | cut -d '=' -f 1)
|
host_value=$(echo "${!host}")
|
||||||
value=$(echo "$var" | sed "s/${name}=//")
|
custom_headers=$(echo "$var" | sed "s/URL/HEADERS/")
|
||||||
host=$(echo "$name" | sed "s/URL/HOST/")
|
custom_headers_value=$(echo "${!custom_headers}")
|
||||||
host_value=$(env | grep "^${host}=" | sed "s/${host}=//")
|
ws=$(echo "$var" | sed "s/URL/WS/")
|
||||||
ws=$(echo "$name" | sed "s/URL/WS/")
|
ws_value=$(echo "${!ws}")
|
||||||
ws_value=$(env | grep "^${ws}=" | sed "s/${ws}=//")
|
cp "${NGINX_PREFIX}reverse-proxy.conf" "${NGINX_PREFIX}reverse-proxy-${i}.conf"
|
||||||
cp "${NGINX_PREFIX}reverse-proxy.conf" "${NGINX_PREFIX}reverse-proxy-${i}.conf"
|
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_URL%" "$url_value"
|
||||||
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_URL%" "$value"
|
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_HOST%" "$host_value"
|
||||||
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_HOST%" "$host_value"
|
if [ "$custom_headers_value" != "" ] ; then
|
||||||
if [ "$ws_value" = "yes" ] ; then
|
IFS_=$IFS
|
||||||
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_WS%" "proxy_http_version 1.1;\nproxy_set_header Upgrade \$http_upgrade;\nproxy_set_header Connection \"Upgrade\";\n"
|
IFS=';'
|
||||||
else
|
for header_value in $(echo "$custom_headers_value") ; do
|
||||||
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_WS%" ""
|
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_CUSTOM_HEADERS%" "more_set_headers $header_value;\n%REVERSE_PROXY_CUSTOM_HEADERS%"
|
||||||
fi
|
done
|
||||||
i=$(($i + 1))
|
IFS=$IFS_
|
||||||
fi
|
fi
|
||||||
|
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_CUSTOM_HEADERS%" ""
|
||||||
|
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_HEADERS%" "include ${NGINX_PREFIX}reverse-proxy-headers.conf;"
|
||||||
|
if [ "$ws_value" = "yes" ] ; then
|
||||||
|
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_WS%" "proxy_http_version 1.1;\nproxy_set_header Upgrade \$http_upgrade;\nproxy_set_header Connection \"Upgrade\";\n"
|
||||||
|
else
|
||||||
|
replace_in_file "${NGINX_PREFIX}reverse-proxy-${i}.conf" "%REVERSE_PROXY_WS%" ""
|
||||||
|
fi
|
||||||
|
i=$(($i + 1))
|
||||||
done
|
done
|
||||||
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_REVERSE_PROXY%" "include ${NGINX_PREFIX}reverse-proxy-*.conf;"
|
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_REVERSE_PROXY%" "include ${NGINX_PREFIX}reverse-proxy-*.conf;"
|
||||||
else
|
else
|
||||||
@@ -137,9 +154,6 @@ if [ "$REMOTE_PHP" != "" ] ; then
|
|||||||
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_PHP%" "include ${NGINX_PREFIX}php.conf;"
|
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_PHP%" "include ${NGINX_PREFIX}php.conf;"
|
||||||
replace_in_file "${NGINX_PREFIX}server.conf" "%FASTCGI_PATH%" "include ${NGINX_PREFIX}fastcgi.conf;"
|
replace_in_file "${NGINX_PREFIX}server.conf" "%FASTCGI_PATH%" "include ${NGINX_PREFIX}fastcgi.conf;"
|
||||||
replace_in_file "${NGINX_PREFIX}php.conf" "%REMOTE_PHP%" "$REMOTE_PHP"
|
replace_in_file "${NGINX_PREFIX}php.conf" "%REMOTE_PHP%" "$REMOTE_PHP"
|
||||||
if [ "$MULTISITE" = "yes" ] ; then
|
|
||||||
cp /etc/nginx/fastcgi.conf ${NGINX_PREFIX}fastcgi.conf && chown root:nginx ${NGINX_PREFIX}fastcgi.conf
|
|
||||||
fi
|
|
||||||
replace_in_file "${NGINX_PREFIX}fastcgi.conf" "\$document_root" "${REMOTE_PHP_PATH}/"
|
replace_in_file "${NGINX_PREFIX}fastcgi.conf" "\$document_root" "${REMOTE_PHP_PATH}/"
|
||||||
else
|
else
|
||||||
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_PHP%" ""
|
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_PHP%" ""
|
||||||
@@ -263,8 +277,15 @@ fi
|
|||||||
# block bad UA
|
# block bad UA
|
||||||
if [ "$BLOCK_USER_AGENT" = "yes" ] ; then
|
if [ "$BLOCK_USER_AGENT" = "yes" ] ; then
|
||||||
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_USER_AGENT%" "true"
|
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_USER_AGENT%" "true"
|
||||||
|
if [ "$WHITELIST_USER_AGENT" != "" ] ; then
|
||||||
|
list=$(spaces_to_lua "$WHITELIST_USER_AGENT")
|
||||||
|
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%WHITELIST_USER_AGENT%" "$list"
|
||||||
|
else
|
||||||
|
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%WHITELIST_USER_AGENT%" ""
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_USER_AGENT%" "false"
|
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_USER_AGENT%" "false"
|
||||||
|
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%WHITELIST_USER_AGENT%" ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# block bad referrer
|
# block bad referrer
|
||||||
@@ -318,29 +339,30 @@ if [ "$AUTO_LETS_ENCRYPT" = "yes" ] || [ "$USE_CUSTOM_HTTPS" = "yes" ] || [ "$GE
|
|||||||
replace_in_file "${NGINX_PREFIX}https.conf" "%STRICT_TRANSPORT_SECURITY%" ""
|
replace_in_file "${NGINX_PREFIX}https.conf" "%STRICT_TRANSPORT_SECURITY%" ""
|
||||||
fi
|
fi
|
||||||
if [ "$AUTO_LETS_ENCRYPT" = "yes" ] ; then
|
if [ "$AUTO_LETS_ENCRYPT" = "yes" ] ; then
|
||||||
|
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_LETS_ENCRYPT%" "true"
|
||||||
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="$1"
|
||||||
if [ ! -f /etc/letsencrypt/live/${1}/fullchain.pem ] ; then
|
EMAIL_LETS_ENCRYPT="${EMAIL_LETS_ENCRYPT-contact@$1}"
|
||||||
echo "[*] Performing Let's Encrypt challenge for $1 ..."
|
echo -n "$EMAIL_LETS_ENCRYPT" > ${NGINX_PREFIX}email-lets-encrypt.txt
|
||||||
EMAIL_LETS_ENCRYPT="${EMAIL_LETS_ENCRYPT-contact@$1}"
|
|
||||||
/opt/scripts/certbot-new.sh "$1" "$EMAIL_LETS_ENCRYPT"
|
|
||||||
fi
|
|
||||||
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"
|
||||||
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_KEY%" "/etc/letsencrypt/live/${FIRST_SERVER_NAME}/privkey.pem"
|
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_KEY%" "/etc/letsencrypt/live/${FIRST_SERVER_NAME}/privkey.pem"
|
||||||
replace_in_file "${NGINX_PREFIX}https.conf" "%LETS_ENCRYPT_WEBROOT%" "include ${NGINX_PREFIX}lets-encrypt-webroot.conf;"
|
replace_in_file "${NGINX_PREFIX}https.conf" "%LETS_ENCRYPT_WEBROOT%" "include ${NGINX_PREFIX}lets-encrypt-webroot.conf;"
|
||||||
elif [ "$USE_CUSTOM_HTTPS" = "yes" ] ; then
|
elif [ "$USE_CUSTOM_HTTPS" = "yes" ] ; then
|
||||||
|
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_LETS_ENCRYPT%" "false"
|
||||||
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_CERT%" "$CUSTOM_HTTPS_CERT"
|
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_CERT%" "$CUSTOM_HTTPS_CERT"
|
||||||
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_KEY%" "$CUSTOM_HTTPS_KEY"
|
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_KEY%" "$CUSTOM_HTTPS_KEY"
|
||||||
replace_in_file "${NGINX_PREFIX}https.conf" "%LETS_ENCRYPT_WEBROOT%" ""
|
replace_in_file "${NGINX_PREFIX}https.conf" "%LETS_ENCRYPT_WEBROOT%" ""
|
||||||
elif [ "$GENERATE_SELF_SIGNED_SSL" = "yes" ] ; then
|
elif [ "$GENERATE_SELF_SIGNED_SSL" = "yes" ] ; then
|
||||||
|
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_LETS_ENCRYPT%" "false"
|
||||||
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_CERT%" "/etc/nginx/self-signed-ssl/cert.pem"
|
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_CERT%" "/etc/nginx/self-signed-ssl/cert.pem"
|
||||||
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_KEY%" "/etc/nginx/self-signed-ssl/key.pem"
|
replace_in_file "${NGINX_PREFIX}https.conf" "%HTTPS_KEY%" "/etc/nginx/self-signed-ssl/key.pem"
|
||||||
replace_in_file "${NGINX_PREFIX}https.conf" "%LETS_ENCRYPT_WEBROOT%" ""
|
replace_in_file "${NGINX_PREFIX}https.conf" "%LETS_ENCRYPT_WEBROOT%" ""
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
replace_in_file "${NGINX_PREFIX}main-lua.conf" "%USE_LETS_ENCRYPT%" "false"
|
||||||
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_HTTPS%" ""
|
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_HTTPS%" ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -360,27 +382,25 @@ fi
|
|||||||
|
|
||||||
# ModSecurity config
|
# ModSecurity config
|
||||||
if [ "$USE_MODSECURITY" = "yes" ] ; then
|
if [ "$USE_MODSECURITY" = "yes" ] ; then
|
||||||
replace_in_file "${NGINX_PREFIX}modsecurity.conf" "%MODSEC_RULES_FILE%" "${NGINX_PREFIX}/modsecurity-rules.conf"
|
replace_in_file "${NGINX_PREFIX}modsecurity.conf" "%MODSEC_RULES_FILE%" "${NGINX_PREFIX}modsecurity-rules.conf"
|
||||||
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_MODSECURITY%" "include ${NGINX_PREFIX}modsecurity.conf;"
|
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_MODSECURITY%" "include ${NGINX_PREFIX}modsecurity.conf;"
|
||||||
modsec_custom=""
|
if [ "$MULTISITE" != "yes" ] ; then
|
||||||
if ls /modsec-confs/*.conf > /dev/null 2>&1 ; then
|
modsec_custom=""
|
||||||
modsec_custom="include /modsec-confs/*.conf\n"
|
if ls /modsec-confs/*.conf > /dev/null 2>&1 ; then
|
||||||
|
modsec_custom="include /modsec-confs/*.conf\n"
|
||||||
|
fi
|
||||||
|
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_RULES%" "$modsec_custom"
|
||||||
fi
|
fi
|
||||||
if [ "$MULTISITE" = "yes" ] && ls /modsec-confs/${1}/*.conf > /dev/null 2>&1 ; then
|
|
||||||
modsec_custom="${modsec_custom}include /modsec-confs/${1}/*.conf\n"
|
|
||||||
fi
|
|
||||||
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_RULES%" "$modsec_custom"
|
|
||||||
if [ "$USE_MODSECURITY_CRS" = "yes" ] ; then
|
if [ "$USE_MODSECURITY_CRS" = "yes" ] ; then
|
||||||
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS%" "include /etc/nginx/owasp-crs.conf"
|
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS%" "include /opt/owasp/crs.conf"
|
||||||
modsec_crs_custom=""
|
if [ "$MULTISITE" != "yes" ] ; then
|
||||||
if ls /modsec-crs-confs/*.conf > /dev/null 2>&1 ; then
|
modsec_crs_custom=""
|
||||||
modsec_crs_custom="include /modsec-crs-confs/*.conf\n"
|
if ls /modsec-crs-confs/*.conf > /dev/null 2>&1 ; then
|
||||||
|
modsec_crs_custom="include /modsec-crs-confs/*.conf\n"
|
||||||
|
fi
|
||||||
|
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_CRS%" "$modsec_crs_custom"
|
||||||
fi
|
fi
|
||||||
if [ "$MULTISITE" = "yes" ] && ls /modsec-crs-confs/${1}/*.conf > /dev/null 2>&1 ; then
|
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS_RULES%" "include /opt/owasp/crs/*.conf"
|
||||||
modsec_crs_custom="${modsec_custom}include /modsec-crs-confs/${1}/*.conf\n"
|
|
||||||
fi
|
|
||||||
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_CRS%" "$modsec_crs_custom"
|
|
||||||
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS_RULES%" "include /etc/nginx/owasp-crs/*.conf"
|
|
||||||
else
|
else
|
||||||
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS%" ""
|
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CRS%" ""
|
||||||
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_CRS%" ""
|
replace_in_file "${NGINX_PREFIX}modsecurity-rules.conf" "%MODSECURITY_INCLUDE_CUSTOM_CRS%" ""
|
||||||
@@ -406,11 +426,11 @@ fi
|
|||||||
|
|
||||||
# custom errors
|
# custom errors
|
||||||
ERRORS=""
|
ERRORS=""
|
||||||
for var in $(env) ; do
|
for var in $(compgen -e) ; do
|
||||||
var_name=$(echo "$var" | cut -d '=' -f 1 | cut -d '_' -f 1)
|
var_name=$(echo "$var" | cut -d '_' -f 1)
|
||||||
if [ "z${var_name}" = "zERROR" ] ; then
|
if [ "z${var_name}" = "zERROR" ] ; then
|
||||||
err_code=$(echo "$var" | cut -d '=' -f 1 | cut -d '_' -f 2)
|
err_code=$(echo "$var" | cut -d '_' -f 2)
|
||||||
err_page=$(echo "$var" | cut -d '=' -f 2)
|
err_page=$(echo "${!var}")
|
||||||
cp /opt/confs/error.conf ${NGINX_PREFIX}error-${err_code}.conf
|
cp /opt/confs/error.conf ${NGINX_PREFIX}error-${err_code}.conf
|
||||||
replace_in_file "${NGINX_PREFIX}error-${err_code}.conf" "%CODE%" "$err_code"
|
replace_in_file "${NGINX_PREFIX}error-${err_code}.conf" "%CODE%" "$err_code"
|
||||||
replace_in_file "${NGINX_PREFIX}error-${err_code}.conf" "%PAGE%" "$err_page"
|
replace_in_file "${NGINX_PREFIX}error-${err_code}.conf" "%PAGE%" "$err_page"
|
||||||
@@ -424,11 +444,13 @@ replace_in_file "${NGINX_PREFIX}server.conf" "%ERRORS%" "$ERRORS"
|
|||||||
if [ "$USE_AUTH_BASIC" = "yes" ] ; then
|
if [ "$USE_AUTH_BASIC" = "yes" ] ; then
|
||||||
if [ "$AUTH_BASIC_LOCATION" = "sitewide" ] ; then
|
if [ "$AUTH_BASIC_LOCATION" = "sitewide" ] ; then
|
||||||
replace_in_file "${NGINX_PREFIX}server.conf" "%AUTH_BASIC%" "include ${NGINX_PREFIX}auth-basic-sitewide.conf;"
|
replace_in_file "${NGINX_PREFIX}server.conf" "%AUTH_BASIC%" "include ${NGINX_PREFIX}auth-basic-sitewide.conf;"
|
||||||
replace_in_file "${NGINX_PREFIX}auth-basic-sitewide.conf" "%AUTH_BASIC_TEXT%" "$AUTH_BASIC_TEXT";
|
replace_in_file "${NGINX_PREFIX}auth-basic-sitewide.conf" "%AUTH_BASIC_TEXT%" "$AUTH_BASIC_TEXT"
|
||||||
|
replace_in_file "${NGINX_PREFIX}auth-basic-sitewide.conf" "%NGINX_PREFIX%" "$NGINX_PREFIX"
|
||||||
else
|
else
|
||||||
replace_in_file "${NGINX_PREFIX}server.conf" "%AUTH_BASIC%" "include ${NGINX_PREFIX}auth-basic.conf;"
|
replace_in_file "${NGINX_PREFIX}server.conf" "%AUTH_BASIC%" "include ${NGINX_PREFIX}auth-basic.conf;"
|
||||||
replace_in_file "${NGINX_PREFIX}auth-basic.conf" "%AUTH_BASIC_LOCATION%" "$AUTH_BASIC_LOCATION";
|
replace_in_file "${NGINX_PREFIX}auth-basic.conf" "%AUTH_BASIC_LOCATION%" "$AUTH_BASIC_LOCATION"
|
||||||
replace_in_file "${NGINX_PREFIX}auth-basic.conf" "%AUTH_BASIC_TEXT%" "$AUTH_BASIC_TEXT";
|
replace_in_file "${NGINX_PREFIX}auth-basic.conf" "%AUTH_BASIC_TEXT%" "$AUTH_BASIC_TEXT"
|
||||||
|
replace_in_file "${NGINX_PREFIX}auth-basic.conf" "%NGINX_PREFIX%" "$NGINX_PREFIX"
|
||||||
fi
|
fi
|
||||||
htpasswd -b -B -c ${NGINX_PREFIX}.htpasswd "$AUTH_BASIC_USER" "$AUTH_BASIC_PASSWORD"
|
htpasswd -b -B -c ${NGINX_PREFIX}.htpasswd "$AUTH_BASIC_USER" "$AUTH_BASIC_PASSWORD"
|
||||||
else
|
else
|
||||||
@@ -537,6 +559,14 @@ else
|
|||||||
replace_in_file "${NGINX_PREFIX}server.conf" "%LIMIT_REQ%" ""
|
replace_in_file "${NGINX_PREFIX}server.conf" "%LIMIT_REQ%" ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# connection limiting
|
||||||
|
if [ "$USE_LIMIT_CONN" = "yes" ] ; then
|
||||||
|
replace_in_file "${NGINX_PREFIX}server.conf" "%LIMIT_CONN%" "include ${NGINX_PREFIX}limit-conn.conf;"
|
||||||
|
replace_in_file "${NGINX_PREFIX}limit-conn.conf" "%LIMIT_CONN_MAX%" "$LIMIT_CONN_MAX"
|
||||||
|
else
|
||||||
|
replace_in_file "${NGINX_PREFIX}server.conf" "%LIMIT_CONN%" ""
|
||||||
|
fi
|
||||||
|
|
||||||
# fail2ban
|
# fail2ban
|
||||||
if [ "$USE_FAIL2BAN" = "yes" ] ; then
|
if [ "$USE_FAIL2BAN" = "yes" ] ; then
|
||||||
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_FAIL2BAN%" "include /etc/nginx/fail2ban-ip.conf;"
|
replace_in_file "${NGINX_PREFIX}server.conf" "%USE_FAIL2BAN%" "include /etc/nginx/fail2ban-ip.conf;"
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ function replace_in_file() {
|
|||||||
# escape slashes
|
# escape slashes
|
||||||
pattern=$(echo "$2" | sed "s/\//\\\\\//g")
|
pattern=$(echo "$2" | sed "s/\//\\\\\//g")
|
||||||
replace=$(echo "$3" | sed "s/\//\\\\\//g")
|
replace=$(echo "$3" | sed "s/\//\\\\\//g")
|
||||||
sed -i "s/$pattern/$replace/g" "$1"
|
sed "s/$pattern/$replace/g" "$1" > /tmp/sed
|
||||||
|
cat /tmp/sed > "$1"
|
||||||
|
rm /tmp/sed
|
||||||
}
|
}
|
||||||
|
|
||||||
# convert space separated values to LUA
|
# convert space separated values to LUA
|
||||||
@@ -26,13 +28,19 @@ function has_value() {
|
|||||||
echo "ok"
|
echo "ok"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
for var in $(env) ; do
|
for var in $(env | grep -E "^.*_${1}=") ; do
|
||||||
domain=$(echo "$var" | cut -d '_' -f 1)
|
domain=$(echo "$var" | cut -d '_' -f 1)
|
||||||
name=$(echo "$var" | cut -d '=' -f 1 | sed "s~${domain}_~~")
|
value=$(echo "$var" | sed "s~^${domain}_${1}=~~")
|
||||||
value=$(echo "$var" | sed "s~${domain}_${name}=~~")
|
if [ "$value" == "$2" ] ; then
|
||||||
if [ "$name" == "$1" ] && [ "$value" == "$2" ] ; then
|
|
||||||
echo "ok"
|
echo "ok"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# log to jobs.log
|
||||||
|
function job_log() {
|
||||||
|
when="$(date '+[%Y-%m-%d %H:%M:%S]')"
|
||||||
|
what="$1"
|
||||||
|
echo "$when $what" >> /var/log/jobs.log
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ services:
|
|||||||
- 80:8080
|
- 80:8080
|
||||||
- 443:8443
|
- 443:8443
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
- ./letsencrypt:/etc/letsencrypt
|
- ./letsencrypt:/etc/letsencrypt
|
||||||
- ./web-files:/www:ro
|
- ./web-files:/www:ro
|
||||||
|
- autoconf:/etc/nginx
|
||||||
environment:
|
environment:
|
||||||
- SERVER_NAME= # must be left blank if you don't want to setup "static" conf
|
- SERVER_NAME= # must be left blank if you don't want to setup "static" conf
|
||||||
- MULTISITE=yes
|
- MULTISITE=yes
|
||||||
@@ -21,6 +21,17 @@ services:
|
|||||||
- USE_CLIENT_CACHE=yes
|
- USE_CLIENT_CACHE=yes
|
||||||
- USE_GZIP=yes
|
- USE_GZIP=yes
|
||||||
- USE_BROTLI=yes
|
- USE_BROTLI=yes
|
||||||
|
labels:
|
||||||
|
- "bunkerized-nginx.AUTOCONF"
|
||||||
|
|
||||||
|
myautoconf:
|
||||||
|
image: bunkerity/bunkerized-nginx-autoconf
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- autoconf:/etc/nginx
|
||||||
|
depends_on:
|
||||||
|
- mywww
|
||||||
|
|
||||||
myapp1:
|
myapp1:
|
||||||
image: php:fpm
|
image: php:fpm
|
||||||
@@ -51,3 +62,6 @@ services:
|
|||||||
- "bunkerized-nginx.SERVER_NAME=app3.website.com" # replace with your domain
|
- "bunkerized-nginx.SERVER_NAME=app3.website.com" # replace with your domain
|
||||||
- "bunkerized-nginx.REMOTE_PHP=myapp3"
|
- "bunkerized-nginx.REMOTE_PHP=myapp3"
|
||||||
- "bunkerized-nginx.REMOTE_PHP_PATH=/app"
|
- "bunkerized-nginx.REMOTE_PHP_PATH=/app"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
autoconf:
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ services:
|
|||||||
- 80:8080
|
- 80:8080
|
||||||
- 443:8443
|
- 443:8443
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
- ./letsencrypt:/etc/letsencrypt
|
- ./letsencrypt:/etc/letsencrypt
|
||||||
|
- autoconf:/etc/nginx
|
||||||
environment:
|
environment:
|
||||||
- SERVER_NAME= # must be left blank if you don't want to setup "static" conf
|
- SERVER_NAME= # must be left blank if you don't want to setup "static" conf
|
||||||
- MULTISITE=yes
|
- MULTISITE=yes
|
||||||
@@ -21,6 +21,17 @@ services:
|
|||||||
- USE_GZIP=yes
|
- USE_GZIP=yes
|
||||||
- USE_BROTLI=yes
|
- USE_BROTLI=yes
|
||||||
- USE_REVERSE_PROXY=yes
|
- USE_REVERSE_PROXY=yes
|
||||||
|
labels:
|
||||||
|
- "bunkerized-nginx.AUTOCONF"
|
||||||
|
|
||||||
|
myautoconf:
|
||||||
|
image: bunkerity/bunkerized-nginx-autoconf
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- autoconf:/etc/nginx
|
||||||
|
depends_on:
|
||||||
|
- mywww
|
||||||
|
|
||||||
myapp1:
|
myapp1:
|
||||||
build: js-app
|
build: js-app
|
||||||
@@ -51,3 +62,6 @@ services:
|
|||||||
- "bunkerized-nginx.SERVER_NAME=app3.website.com" # replace with your domain
|
- "bunkerized-nginx.SERVER_NAME=app3.website.com" # replace with your domain
|
||||||
- "bunkerized-nginx.REVERSE_PROXY_URL=/"
|
- "bunkerized-nginx.REVERSE_PROXY_URL=/"
|
||||||
- "bunkerized-nginx.REVERSE_PROXY_HOST=http://myapp3:3000"
|
- "bunkerized-nginx.REVERSE_PROXY_HOST=http://myapp3:3000"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
autoconf:
|
||||||
|
|||||||
3
examples/crowdsec/bouncer_key.sh
Normal file
3
examples/crowdsec/bouncer_key.sh
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
docker-compose exec mycrowdsec cscli bouncers add MyBouncer
|
||||||
70
examples/crowdsec/docker-compose.yml
Normal file
70
examples/crowdsec/docker-compose.yml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
mywww:
|
||||||
|
image: bunkerity/bunkerized-nginx
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 80:8080
|
||||||
|
- 443:8443
|
||||||
|
volumes:
|
||||||
|
- ./web-files:/www:ro
|
||||||
|
- ./letsencrypt:/etc/letsencrypt
|
||||||
|
- nginx_logs:/var/log
|
||||||
|
environment:
|
||||||
|
- SERVER_NAME=app1.website.com app2.website.com # replace with your domains
|
||||||
|
- MULTISITE=yes
|
||||||
|
- AUTO_LETS_ENCRYPT=yes
|
||||||
|
- REDIRECT_HTTP_TO_HTTPS=yes
|
||||||
|
- DISABLE_DEFAULT_SERVER=yes
|
||||||
|
- USE_CLIENT_CACHE=yes
|
||||||
|
- USE_GZIP=yes
|
||||||
|
- USE_BROTLI=yes
|
||||||
|
- USE_CROWDSEC=yes
|
||||||
|
- CROWDSEC_HOST=http://mycrowdsec:8080
|
||||||
|
- CROWDSEC_KEY= # you need to generate it (see bouncer_key.sh)
|
||||||
|
- 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
|
||||||
|
networks:
|
||||||
|
- net0
|
||||||
|
- net1
|
||||||
|
- net2
|
||||||
|
|
||||||
|
mycrowdsec:
|
||||||
|
image: crowdsecurity/crowdsec:v1.0.2
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./acquis.yaml:/etc/crowdsec/acquis.yaml
|
||||||
|
- nginx_logs:/var/log:ro
|
||||||
|
environment:
|
||||||
|
- COLLECTIONS=crowdsecurity/nginx
|
||||||
|
- REGISTER_TO_ONLINE_API=true
|
||||||
|
networks:
|
||||||
|
- net0
|
||||||
|
|
||||||
|
myapp1:
|
||||||
|
image: php:fpm
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./web-files/app1.website.com:/app
|
||||||
|
networks:
|
||||||
|
- net1
|
||||||
|
|
||||||
|
myapp2:
|
||||||
|
image: php:fpm
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./web-files/app2.website.com:/app
|
||||||
|
networks:
|
||||||
|
- net2
|
||||||
|
|
||||||
|
networks:
|
||||||
|
net0:
|
||||||
|
net1:
|
||||||
|
net2:
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
nginx_logs:
|
||||||
5
examples/crowdsec/web-files/app1.website.com/index.php
Normal file
5
examples/crowdsec/web-files/app1.website.com/index.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
echo "hello from app1 !";
|
||||||
|
|
||||||
|
?>
|
||||||
5
examples/crowdsec/web-files/app2.website.com/index.php
Normal file
5
examples/crowdsec/web-files/app2.website.com/index.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
echo "hello from app2 !";
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -3,7 +3,7 @@ version: '3'
|
|||||||
services:
|
services:
|
||||||
|
|
||||||
myreverse:
|
myreverse:
|
||||||
image: bunkerity/bunkerized-nginx:dev
|
image: bunkerity/bunkerized-nginx
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- 80:8080
|
- 80:8080
|
||||||
|
|||||||
97
examples/swarm/stack.yml
Normal file
97
examples/swarm/stack.yml
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
autoconf:
|
||||||
|
image: bunkerity/bunkerized-nginx-autoconf
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- /shared/confs:/etc/nginx
|
||||||
|
- /shared/letsencrypt:/etc/letsencrypt
|
||||||
|
- /shared/acme-challenge:/acme-challenge
|
||||||
|
environment:
|
||||||
|
- SWARM_MODE=yes
|
||||||
|
- API_URI=/ChangeMeToSomethingHardToGuess # must match API_URI from nginx
|
||||||
|
networks:
|
||||||
|
- net_config
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
placement:
|
||||||
|
constraints:
|
||||||
|
- "node.role==manager"
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: bunkerity/bunkerized-nginx
|
||||||
|
ports:
|
||||||
|
- published: 80
|
||||||
|
target: 8080
|
||||||
|
mode: host
|
||||||
|
protocol: tcp
|
||||||
|
- published: 443
|
||||||
|
target: 8443
|
||||||
|
mode: host
|
||||||
|
protocol: tcp
|
||||||
|
volumes:
|
||||||
|
- /shared/confs:/etc/nginx:ro
|
||||||
|
- /shared/letsencrypt:/etc/letsencrypt:ro
|
||||||
|
- /shared/acme-challenge:/acme-challenge:ro
|
||||||
|
- /shared/www:/www:ro
|
||||||
|
environment:
|
||||||
|
- SWARM_MODE=yes
|
||||||
|
- USE_API=yes
|
||||||
|
- API_URI=/ChangeMeToSomethingHardToGuess # must match API_URI from autoconf
|
||||||
|
- MULTISITE=yes
|
||||||
|
- SERVER_NAME=
|
||||||
|
- AUTO_LETS_ENCRYPT=yes
|
||||||
|
- REDIRECT_HTTP_TO_HTTPS=yes
|
||||||
|
- DISABLE_DEFAULT_SERVER=yes
|
||||||
|
networks:
|
||||||
|
- net_config
|
||||||
|
- net_services
|
||||||
|
deploy:
|
||||||
|
mode: global
|
||||||
|
placement:
|
||||||
|
constraints:
|
||||||
|
- "node.role==worker"
|
||||||
|
labels:
|
||||||
|
- "bunkerized-nginx.AUTOCONF"
|
||||||
|
|
||||||
|
app1:
|
||||||
|
image: php:fpm-alpine
|
||||||
|
volumes:
|
||||||
|
- /shared/www/app1.website.com:/www
|
||||||
|
networks:
|
||||||
|
- net_services
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
placement:
|
||||||
|
constraints:
|
||||||
|
- "node.role==worker"
|
||||||
|
labels:
|
||||||
|
- "bunkerized-nginx.SERVER_NAME=app1.website.com"
|
||||||
|
- "bunkerized-nginx.REMOTE_PHP=php"
|
||||||
|
- "bunkerized-nginx.REMOTE_PHP_PATH=/www"
|
||||||
|
|
||||||
|
app2:
|
||||||
|
image: phpmyadmin:apache
|
||||||
|
environment:
|
||||||
|
- PMA_ARBITRARY=1
|
||||||
|
- PMA_ABSOLUTE_URI=https://app2.website.com
|
||||||
|
networks:
|
||||||
|
- net_services
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
placement:
|
||||||
|
constraints:
|
||||||
|
- "node.role==worker"
|
||||||
|
labels:
|
||||||
|
- "bunkerized-nginx.SERVER_NAME=app2.website.com"
|
||||||
|
- "bunkerized-nginx.USE_REVERSE_PROXY=yes"
|
||||||
|
- "bunkerized-nginx.REVERSE_PROXY_URL=/"
|
||||||
|
- "bunkerized-nginx.REVERSE_PROXY_HOST=http://app2"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
net_config:
|
||||||
|
driver: overlay
|
||||||
|
net_services:
|
||||||
|
driver: overlay
|
||||||
43
examples/web-ui/docker-compose.yml
Normal file
43
examples/web-ui/docker-compose.yml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
mywww:
|
||||||
|
image: bunkerity/bunkerized-nginx
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 80:8080
|
||||||
|
- 443:8443
|
||||||
|
volumes:
|
||||||
|
- ./letsencrypt:/etc/letsencrypt
|
||||||
|
- ./web-files:/www:ro
|
||||||
|
- autoconf:/etc/nginx
|
||||||
|
environment:
|
||||||
|
- SERVER_NAME=admin.website.com # replace with your domain
|
||||||
|
- MULTISITE=yes
|
||||||
|
- AUTO_LETS_ENCRYPT=yes
|
||||||
|
- REDIRECT_HTTP_TO_HTTPS=yes
|
||||||
|
- DISABLE_DEFAULT_SERVER=yes
|
||||||
|
- USE_GZIP=yes
|
||||||
|
- USE_BROTLI=yes
|
||||||
|
- admin.website.com_SERVE_FILES=no
|
||||||
|
- 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_PASSWORD=admin # change it to something hard to guess
|
||||||
|
- admin.website.com_USE_REVERSE_PROXY=yes
|
||||||
|
- admin.website.com_REVERSE_PROXY_URL=/admin/ # change it to something hard to guess
|
||||||
|
- admin.website.com_REVERSE_PROXY_HOST=http://myui:5000/
|
||||||
|
labels:
|
||||||
|
- "bunkerized-nginx.UI"
|
||||||
|
|
||||||
|
myui:
|
||||||
|
image: bunkerity/bunkerized-nginx-ui
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- autoconf:/etc/nginx
|
||||||
|
environment:
|
||||||
|
- ABSOLUTE_URI=https://admin.website.com/admin/ # change it to your full URI
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
autoconf:
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
bantime = %FAIL2BAN_BANTIME%
|
bantime = %FAIL2BAN_BANTIME%
|
||||||
findtime = %FAIL2BAN_FINDTIME%
|
findtime = %FAIL2BAN_FINDTIME%
|
||||||
maxretry = %FAIL2BAN_MAXRETRY%
|
maxretry = %FAIL2BAN_MAXRETRY%
|
||||||
|
ignoreip = %FAIL2BAN_IGNOREIP%
|
||||||
enabled = true
|
enabled = true
|
||||||
action = nginx-action
|
action = nginx-action
|
||||||
logpath = /var/log/access.log
|
logpath = /var/log/access.log
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/var/log/*.log /var/log/clamav/*.log /var/log/nginx/*.log {
|
/var/log/*.log /var/log/clamav/*.log /var/log/nginx/*.log /var/log/letsencrypt/*.log {
|
||||||
# compress old files using gzip
|
# compress old files using gzip
|
||||||
compress
|
compress
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
$WorkDirectory /var/lib/rsyslog
|
$WorkDirectory /var/lib/rsyslog
|
||||||
|
|
||||||
# Sets default permissions for all log files.
|
# Sets default permissions for all log files.
|
||||||
$FileOwner root
|
$FileOwner nginx
|
||||||
$FileGroup root
|
$FileGroup nginx
|
||||||
$FileCreateMode 0600
|
$FileCreateMode 0660
|
||||||
$DirCreateMode 0700
|
$DirCreateMode 0770
|
||||||
$Umask 0077
|
$Umask 0007
|
||||||
|
|
||||||
# Include all config files in /etc/rsyslog.d/.
|
# Include all config files in /etc/rsyslog.d/.
|
||||||
include(file="/etc/rsyslog.d/*.conf" mode="optional")
|
include(file="/etc/rsyslog.d/*.conf" mode="optional")
|
||||||
@@ -16,10 +16,10 @@ include(file="/etc/rsyslog.d/*.conf" mode="optional")
|
|||||||
#### Modules ####
|
#### Modules ####
|
||||||
|
|
||||||
# Provides --MARK-- message capability.
|
# Provides --MARK-- message capability.
|
||||||
module(load="immark")
|
#module(load="immark")
|
||||||
|
|
||||||
# Provides support for local system logging (e.g. via logger command).
|
# Provides support for local system logging (e.g. via logger command).
|
||||||
module(load="imuxsock")
|
module(load="imuxsock" SysSock.Name="/tmp/log")
|
||||||
|
|
||||||
# Nginx
|
# Nginx
|
||||||
$template rawFormat,"%msg:2:2048%\n"
|
$template rawFormat,"%msg:2:2048%\n"
|
||||||
|
|||||||
31
lua/api.lua
Normal file
31
lua/api.lua
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
local M = {}
|
||||||
|
local api_list = {}
|
||||||
|
|
||||||
|
api_list["^/ping$"] = function ()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
api_list["^/reload$"] = function ()
|
||||||
|
return os.execute("/usr/sbin/nginx -s reload") == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.is_api_call (api_uri)
|
||||||
|
if ngx.var.request_uri:sub(1, #api_uri) .. "/" == api_uri .. "/" then
|
||||||
|
for uri, code in pairs(api_list) do
|
||||||
|
if string.match(ngx.var.request_uri:sub(#api_uri + 1), uri) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.do_api_call (api_uri)
|
||||||
|
for uri, code in pairs(api_list) do
|
||||||
|
if string.match(ngx.var.request_uri:sub(#api_uri + 1), uri) then
|
||||||
|
return code()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
local M = {}
|
local M = {}
|
||||||
local resolver = require "resty.dns.resolver"
|
local resolver = require "resty.dns.resolver"
|
||||||
local resolvers = {%DNS_RESOLVERS%}
|
local resolvers = {%DNS_RESOLVERS%}
|
||||||
local ip = ngx.var.remote_addr
|
local ip = ngx.var.remote_addr
|
||||||
|
|
||||||
function M.get_reverse()
|
function M.get_reverse()
|
||||||
|
|||||||
94
prepare.sh
Normal file
94
prepare.sh
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# install dependencies
|
||||||
|
apk --no-cache add certbot libstdc++ libmaxminddb geoip pcre yajl fail2ban clamav apache2-utils rsyslog openssl lua libgd go jq mariadb-connector-c bash brotli
|
||||||
|
|
||||||
|
# temp fix ?
|
||||||
|
chmod 644 /usr/lib/python3.8/site-packages/fail2ban-*/*
|
||||||
|
|
||||||
|
# custom entrypoint
|
||||||
|
mkdir /opt/entrypoint.d
|
||||||
|
|
||||||
|
# prepare /www
|
||||||
|
mkdir /www
|
||||||
|
chown -R root:nginx /www
|
||||||
|
chmod -R 770 /www
|
||||||
|
|
||||||
|
# prepare /opt
|
||||||
|
chown -R root:nginx /opt
|
||||||
|
find /opt -type f -exec chmod 0740 {} \;
|
||||||
|
find /opt -type d -exec chmod 0750 {} \;
|
||||||
|
chmod ugo+x /opt/entrypoint/* /opt/scripts/*
|
||||||
|
chmod 770 /opt
|
||||||
|
|
||||||
|
# prepare /etc/nginx
|
||||||
|
chown -R root:nginx /etc/nginx
|
||||||
|
chmod -R 770 /etc/nginx
|
||||||
|
|
||||||
|
# prepare /var/log
|
||||||
|
rm -f /var/log/nginx/*
|
||||||
|
chown root:nginx /var/log/nginx
|
||||||
|
touch /var/log/nginx/error.log /var/log/nginx/modsec_audit.log /var/log/jobs.log
|
||||||
|
chown nginx:nginx /var/log/nginx/*
|
||||||
|
chmod -R 770 /var/log/nginx
|
||||||
|
touch /var/log/access.log /var/log/error.log /var/log/jobs.log /var/log/fail2ban.log
|
||||||
|
chown nginx:nginx /var/log/*.log
|
||||||
|
chmod 770 /var/log/*.log
|
||||||
|
mkdir /var/log/letsencrypt
|
||||||
|
chown nginx:nginx /var/log/letsencrypt
|
||||||
|
chmod 770 /var/log/letsencrypt
|
||||||
|
touch /var/log/clamav.log
|
||||||
|
chown root:nginx /var/log/clamav.log
|
||||||
|
chmod 770 /var/log/clamav.log
|
||||||
|
|
||||||
|
# prepare /acme-challenge
|
||||||
|
mkdir /acme-challenge
|
||||||
|
chown root:nginx /acme-challenge
|
||||||
|
chmod 770 /acme-challenge
|
||||||
|
|
||||||
|
# prepare /etc/letsencrypt
|
||||||
|
mkdir /etc/letsencrypt
|
||||||
|
chown root:nginx /etc/letsencrypt
|
||||||
|
chmod 770 /etc/letsencrypt
|
||||||
|
|
||||||
|
# prepare /var/lib/letsencrypt
|
||||||
|
mkdir /var/lib/letsencrypt
|
||||||
|
chown root:nginx /var/lib/letsencrypt
|
||||||
|
chmod 770 /var/lib/letsencrypt
|
||||||
|
|
||||||
|
# prepare /etc/fail2ban
|
||||||
|
rm -rf /etc/fail2ban/jail.d/*.conf
|
||||||
|
chown -R root:nginx /etc/fail2ban
|
||||||
|
find /etc/fail2ban -type f -exec chmod 0760 {} \;
|
||||||
|
find /etc/fail2ban -type d -exec chmod 0770 {} \;
|
||||||
|
|
||||||
|
# prepare /var/run/fail2ban and /var/lib/fail2ban
|
||||||
|
chown -R root:nginx /var/run/fail2ban /var/lib/fail2ban
|
||||||
|
chmod -R 770 /var/run/fail2ban /var/lib/fail2ban
|
||||||
|
|
||||||
|
# prepare /usr/local/lib/lua
|
||||||
|
chown root:nginx /usr/local/lib/lua
|
||||||
|
chmod 770 /usr/local/lib/lua
|
||||||
|
|
||||||
|
# prepare /cache
|
||||||
|
mkdir /cache
|
||||||
|
chown root:nginx /cache
|
||||||
|
chmod 770 /cache
|
||||||
|
|
||||||
|
# prepare misc files
|
||||||
|
chown root:nginx /etc/rsyslog.conf /etc/logrotate.conf
|
||||||
|
chmod 660 /etc/rsyslog.conf /etc/logrotate.conf
|
||||||
|
chown root:nginx /etc/rsyslog.conf
|
||||||
|
|
||||||
|
# prepare /etc/crontabs/nginx
|
||||||
|
touch /etc/crontabs/nginx
|
||||||
|
chown root:nginx /etc/crontabs/nginx
|
||||||
|
chmod 660 /etc/crontabs/nginx
|
||||||
|
|
||||||
|
# prepare /var/log/clamav
|
||||||
|
chown root:nginx /var/log/clamav
|
||||||
|
chmod 770 /var/log/clamav
|
||||||
|
|
||||||
|
# prepare /var/lib/clamav
|
||||||
|
chown root:nginx /var/lib/clamav
|
||||||
|
chmod 770 /var/lib/clamav
|
||||||
@@ -1,14 +1,51 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
echo "" > /etc/nginx/block-abusers.conf
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# copy old conf to cache
|
||||||
|
cp /etc/nginx/block-abusers.conf /cache
|
||||||
|
|
||||||
|
# if we are running nginx
|
||||||
|
if [ -f /tmp/nginx.pid ] ; then
|
||||||
|
RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1"
|
||||||
|
# if we are in autoconf
|
||||||
|
elif [ -S /tmp/autoconf.sock ] ; then
|
||||||
|
RELOAD="/opt/entrypoint/reload.py"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# generate the new conf
|
||||||
curl -s "https://iplists.firehol.org/files/firehol_abusers_30d.netset" | grep -v "^\#.*" |
|
curl -s "https://iplists.firehol.org/files/firehol_abusers_30d.netset" | grep -v "^\#.*" |
|
||||||
while read entry ; do
|
while read entry ; do
|
||||||
check=$(echo $entry | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/?[0-9]*$")
|
check=$(echo $entry | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/?[0-9]*$")
|
||||||
if [ "$check" != "" ] ; then
|
if [ "$check" != "" ] ; then
|
||||||
echo "deny ${entry};" >> /etc/nginx/block-abusers.conf
|
echo "deny ${entry};" >> /tmp/block-abusers.conf
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
cp /etc/nginx/block-abusers.conf /cache
|
|
||||||
if [ -f /tmp/nginx.pid ] ; then
|
# check if we have at least 1 line
|
||||||
/usr/sbin/nginx -s reload > /dev/null 2>&1
|
lines="$(wc -l /tmp/block-abusers.conf | cut -d ' ' -f 1)"
|
||||||
|
if [ "$lines" -gt 1 ] ; then
|
||||||
|
job_log "[BLACKLIST] abusers list updated ($lines entries)"
|
||||||
|
# reload nginx with the new config
|
||||||
|
mv /tmp/block-abusers.conf /etc/nginx/block-abusers.conf
|
||||||
|
if [ "$RELOAD" != "" ] ; then
|
||||||
|
$RELOAD
|
||||||
|
# new config is ok : save it in the cache
|
||||||
|
if [ "$?" -eq 0 ] ; then
|
||||||
|
cp /etc/nginx/block-abusers.conf /cache
|
||||||
|
job_log "[NGINX] successfull nginx reload after abusers list update"
|
||||||
|
else
|
||||||
|
job_log "[NGINX] failed nginx reload after abusers list update fallback to old list"
|
||||||
|
cp /cache/block-abusers.conf /etc/nginx
|
||||||
|
$RELOAD
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cp /etc/nginx/block-abusers.conf /cache
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
job_log "[BLACKLIST] can't update abusers list"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/block-abusers.conf 2> /dev/null
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
# generate certificate
|
# generate certificate
|
||||||
certbot certonly --webroot -w /acme-challenge -n -d "$1" --email "$2" --agree-tos
|
certbot certonly --webroot -w /acme-challenge -n -d "$1" --email "$2" --agree-tos
|
||||||
|
if [ "$?" -ne 0 ] ; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# fix rights
|
exit 0
|
||||||
chown -R root:nginx /etc/letsencrypt
|
|
||||||
chmod -R 740 /etc/letsencrypt
|
|
||||||
find /etc/letsencrypt -type d -exec chmod 750 {} \;
|
|
||||||
|
|||||||
24
scripts/certbot-renew-hook.sh
Normal file
24
scripts/certbot-renew-hook.sh
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
job_log "[CERTBOT] certificates have been renewed"
|
||||||
|
|
||||||
|
# if we are running nginx
|
||||||
|
if [ -f /tmp/nginx.pid ] ; then
|
||||||
|
RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1"
|
||||||
|
# if we are in autoconf
|
||||||
|
elif [ -S /tmp/autoconf.sock ] ; then
|
||||||
|
RELOAD="echo reload > /tmp/autoconf.sock"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# reload nginx
|
||||||
|
if [ "$RELOAD" != "" ] ; then
|
||||||
|
$RELOAD
|
||||||
|
if [ "$?" -eq 0 ] ; then
|
||||||
|
job_log "[NGINX] successfull nginx reload after certbot renew"
|
||||||
|
else
|
||||||
|
job_log "[NGINX] failed nginx reload after certbot renew"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
# ask new certificates if needed
|
# ask new certificates if needed
|
||||||
certbot renew
|
certbot renew --deploy-hook /opt/scripts/certbot-renew-hook.sh
|
||||||
|
|
||||||
# fix rights
|
if [ "$?" -eq 0 ] ; then
|
||||||
chown -R root:nginx /etc/letsencrypt
|
job_log "[CERTBOT] renew operation done"
|
||||||
chmod -R 740 /etc/letsencrypt
|
else
|
||||||
find /etc/letsencrypt -type d -exec chmod 750 {} \;
|
job_log "[CERTBOT] renew operation failed"
|
||||||
|
|
||||||
# reload nginx
|
|
||||||
if [ -f /tmp/nginx.pid ] ; then
|
|
||||||
/usr/sbin/nginx -s reload > /dev/null 2>&1
|
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,14 +1,51 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
echo "" > /etc/nginx/block-tor-exit-node.conf
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# copy old conf to cache
|
||||||
|
cp /etc/nginx/block-tor-exit-node.conf /cache
|
||||||
|
|
||||||
|
# if we are running nginx
|
||||||
|
if [ -f /tmp/nginx.pid ] ; then
|
||||||
|
RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1"
|
||||||
|
# if we are in autoconf
|
||||||
|
elif [ -S /tmp/autoconf.sock ] ; then
|
||||||
|
RELOAD="/opt/entrypoint/reload.py"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# generate the new conf
|
||||||
curl -s "https://iplists.firehol.org/files/tor_exits.ipset" | grep -v "^\#.*" |
|
curl -s "https://iplists.firehol.org/files/tor_exits.ipset" | grep -v "^\#.*" |
|
||||||
while read entry ; do
|
while read entry ; do
|
||||||
check=$(echo $entry | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/?[0-9]*$")
|
check=$(echo $entry | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/?[0-9]*$")
|
||||||
if [ "$check" != "" ] ; then
|
if [ "$check" != "" ] ; then
|
||||||
echo "deny ${entry};" >> /etc/nginx/block-tor-exit-node.conf
|
echo "deny ${entry};" >> /tmp/block-tor-exit-node.conf
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
cp /etc/nginx/block-tor-exit-node.conf /cache
|
|
||||||
if [ -f /tmp/nginx.pid ] ; then
|
# check if we have at least 1 line
|
||||||
/usr/sbin/nginx -s reload > /dev/null 2>&1
|
lines="$(wc -l /tmp/block-tor-exit-node.conf | cut -d ' ' -f 1)"
|
||||||
|
if [ "$lines" -gt 1 ] ; then
|
||||||
|
job_log "[BLACKLIST] TOR exit node list updated ($lines entries)"
|
||||||
|
# reload nginx with the new config
|
||||||
|
mv /tmp/block-tor-exit-node.conf /etc/nginx/block-tor-exit-node.conf
|
||||||
|
if [ "$RELOAD" != "" ] ; then
|
||||||
|
$RELOAD
|
||||||
|
# new config is ok : save it in the cache
|
||||||
|
if [ "$?" -eq 0 ] ; then
|
||||||
|
cp /etc/nginx/block-tor-exit-node.conf /cache
|
||||||
|
job_log "[NGINX] successfull nginx reload after TOR exit node list update"
|
||||||
|
else
|
||||||
|
job_log "[NGINX] failed nginx reload after TOR exit node list update fallback to old list"
|
||||||
|
cp /cache/block-tor-exit-node.conf /etc/nginx
|
||||||
|
$RELOAD
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cp /etc/nginx/block-tor-exit-node.conf /cache
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
job_log "[BLACKLIST] can't update TOR exit node list"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/block-tor-exit-node.conf 2> /dev/null
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,43 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# if we are running nginx
|
||||||
|
if [ -f /tmp/nginx.pid ] ; then
|
||||||
|
RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1"
|
||||||
|
# if we are in autoconf
|
||||||
|
elif [ -S /tmp/autoconf.sock ] ; then
|
||||||
|
RELOAD="/opt/entrypoint/reload.py"
|
||||||
|
fi
|
||||||
|
|
||||||
# MMDB from https://db-ip.com/db/download/ip-to-country-lite
|
# MMDB from https://db-ip.com/db/download/ip-to-country-lite
|
||||||
URL="https://download.db-ip.com/free/dbip-country-lite-$(date +%Y-%m).mmdb.gz"
|
URL="https://download.db-ip.com/free/dbip-country-lite-$(date +%Y-%m).mmdb.gz"
|
||||||
wget -O /etc/nginx/geoip.mmdb.gz "$URL" > /dev/null 2>&1
|
wget -O /tmp/geoip.mmdb.gz "$URL" > /dev/null 2>&1
|
||||||
if [ -f /etc/nginx/geoip.mmdb.gz ] ; then
|
if [ "$?" -eq 0 ] && [ -f /tmp/geoip.mmdb.gz ] ; then
|
||||||
gunzip -f /etc/nginx/geoip.mmdb.gz
|
gunzip -f /tmp/geoip.mmdb.gz > /dev/null 2>&1
|
||||||
cp /etc/nginx/geoip.mmdb /cache
|
if [ "$?" -ne 0 ] ; then
|
||||||
if [ -f /tmp/nginx.pid ] ; then
|
job_log "[GEOIP] can't extract DB from $URL"
|
||||||
/usr/sbin/nginx -s reload > /dev/null 2>&1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
mv /tmp/geoip.mmdb /etc/nginx
|
||||||
|
if [ "$RELOAD" != "" ] ; then
|
||||||
|
$RELOAD
|
||||||
|
if [ "$?" -eq 0 ] ; then
|
||||||
|
cp /etc/nginx/geoip.mmdb /cache
|
||||||
|
job_log "[NGINX] successfull nginx reload after GeoIP DB update"
|
||||||
|
else
|
||||||
|
job_log "[NGINX] failed nginx reload after GeoIP DB update"
|
||||||
|
if [ -f /cache/geoip.mmdb ] ; then
|
||||||
|
cp /cache/geoip.mmdb /etc/nginx/geoip.mmdb
|
||||||
|
$RELOAD
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cp /etc/nginx/geoip.mmdb /cache
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
job_log "[GEOIP] can't download DB from $URL"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/geoip* 2> /dev/null
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
logrotate -f /etc/logrotate.conf > /dev/null 2>&1
|
logrotate -f /etc/logrotate.conf > /dev/null 2>&1
|
||||||
|
|
||||||
pkill -HUP rsyslogd
|
pkill -HUP rsyslogd
|
||||||
@@ -7,5 +10,10 @@ pkill -HUP rsyslogd
|
|||||||
fail2ban-client flushlogs
|
fail2ban-client flushlogs
|
||||||
|
|
||||||
if [ -f /tmp/nginx.pid ] ; then
|
if [ -f /tmp/nginx.pid ] ; then
|
||||||
/usr/sbin/nginx -s reload > /dev/null 2>&1
|
/usr/sbin/nginx -s reload > /dev/null 2>&1
|
||||||
|
if [ "$?" -eq 0 ] ; then
|
||||||
|
job_log "[NGINX] successfull nginx reload after logrotate"
|
||||||
|
else
|
||||||
|
job_log "[NGINX] failed nginx reload after logrotate"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,14 +1,51 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
echo "" > /etc/nginx/block-proxies.conf
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# copy old conf to cache
|
||||||
|
cp /etc/nginx/block-proxies.conf /cache
|
||||||
|
|
||||||
|
# if we are running nginx
|
||||||
|
if [ -f /tmp/nginx.pid ] ; then
|
||||||
|
RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1"
|
||||||
|
# if we are in autoconf
|
||||||
|
elif [ -S /tmp/autoconf.sock ] ; then
|
||||||
|
RELOAD="/opt/entrypoint/reload.py"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# generate the new conf
|
||||||
curl -s "https://iplists.firehol.org/files/firehol_proxies.netset" | grep -v "^\#.*" |
|
curl -s "https://iplists.firehol.org/files/firehol_proxies.netset" | grep -v "^\#.*" |
|
||||||
while read entry ; do
|
while read entry ; do
|
||||||
check=$(echo $entry | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/?[0-9]*$")
|
check=$(echo $entry | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/?[0-9]*$")
|
||||||
if [ "$check" != "" ] ; then
|
if [ "$check" != "" ] ; then
|
||||||
echo "deny ${entry};" >> /etc/nginx/block-proxies.conf
|
echo "deny ${entry};" >> /tmp/block-proxies.conf
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
cp /etc/nginx/block-proxies.conf /cache
|
|
||||||
if [ -f /tmp/nginx.pid ] ; then
|
# check if we have at least 1 line
|
||||||
/usr/sbin/nginx -s reload > /dev/null 2>&1
|
lines="$(wc -l /tmp/block-proxies.conf | cut -d ' ' -f 1)"
|
||||||
|
if [ "$lines" -gt 1 ] ; then
|
||||||
|
job_log "[BLACKLIST] proxies list updated ($lines entries)"
|
||||||
|
# reload nginx with the new config
|
||||||
|
mv /tmp/block-proxies.conf /etc/nginx/block-proxies.conf
|
||||||
|
if [ "$RELOAD" != "" ] ; then
|
||||||
|
$RELOAD
|
||||||
|
# new config is ok : save it in the cache
|
||||||
|
if [ "$?" -eq 0 ] ; then
|
||||||
|
cp /etc/nginx/block-proxies.conf /cache
|
||||||
|
job_log "[NGINX] successfull nginx reload after proxies list update"
|
||||||
|
else
|
||||||
|
job_log "[NGINX] failed nginx reload after proxies list update fallback to old list"
|
||||||
|
cp /cache/block-proxies.conf /etc/nginx
|
||||||
|
$RELOAD
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cp /etc/nginx/block-proxies.conf /cache
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
job_log "[BLACKLIST] can't update proxies list"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/block-proxies.conf 2> /dev/null
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,51 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# save old conf
|
||||||
|
cp /etc/nginx/map-referrer.conf /cache
|
||||||
|
|
||||||
|
# if we are running nginx
|
||||||
|
if [ -f /tmp/nginx.pid ] ; then
|
||||||
|
RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1"
|
||||||
|
# if we are in autoconf
|
||||||
|
elif [ -S /tmp/autoconf.sock ] ; then
|
||||||
|
RELOAD="/opt/entrypoint/reload.py"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# generate new conf
|
||||||
BLACKLIST="$(curl -s https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/_generator_lists/bad-referrers.list)"
|
BLACKLIST="$(curl -s https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/_generator_lists/bad-referrers.list)"
|
||||||
|
if [ "$?" -ne 0 ] ; then
|
||||||
|
job_log "[BLACKLIST] can't update referrers list"
|
||||||
|
fi
|
||||||
DATA=""
|
DATA=""
|
||||||
IFS=$'\n'
|
IFS=$'\n'
|
||||||
for ref in $BLACKLIST ; do
|
for ref in $BLACKLIST ; do
|
||||||
DATA="${DATA}\"~${ref}\" yes;\n"
|
DATA="${DATA}\"~${ref}\" yes;\n"
|
||||||
done
|
done
|
||||||
|
echo -e "map \$http_referer \$bad_referrer { hostnames; default no; $DATA }" > /tmp/map-referrer.conf
|
||||||
|
|
||||||
echo -e "map \$http_referer \$bad_referrer { hostnames; default no; $DATA }" > /etc/nginx/map-referrer.conf
|
# check number of lines
|
||||||
cp /etc/nginx/map-referrer.conf /cache
|
lines="$(wc -l /tmp/map-referrer.conf | cut -d ' ' -f 1)"
|
||||||
|
if [ "$lines" -gt 1 ] ; then
|
||||||
if [ -f /tmp/nginx.pid ] ; then
|
mv /tmp/map-referrer.conf /etc/nginx/map-referrer.conf
|
||||||
/usr/sbin/nginx -s reload > /dev/null 2>&1
|
job_log "[BLACKLIST] referrers list updated ($lines entries)"
|
||||||
|
if [ "$RELOAD" != "" ] ; then
|
||||||
|
$RELOAD
|
||||||
|
if [ "$?" -eq 0 ] ; then
|
||||||
|
cp /etc/nginx/map-referrer.conf /cache
|
||||||
|
job_log "[NGINX] successfull nginx reload after referrers list update"
|
||||||
|
else
|
||||||
|
cp /cache/map-referrer.conf /etc/nginx
|
||||||
|
job_log "[NGINX] failed nginx reload after referrers list update fallback to old list"
|
||||||
|
$RELOAD
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cp /etc/nginx/map-referrer.conf /cache
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
job_log "[BLACKLIST] can't update referrers list"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/map-referrer.conf 2> /dev/null
|
||||||
|
|||||||
@@ -1,17 +1,53 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
# load some functions
|
||||||
|
. /opt/entrypoint/utils.sh
|
||||||
|
|
||||||
|
# save old conf
|
||||||
|
cp /etc/nginx/map-user-agent.conf /cache
|
||||||
|
|
||||||
|
# if we are running nginx
|
||||||
|
if [ -f /tmp/nginx.pid ] ; then
|
||||||
|
RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1"
|
||||||
|
# if we are in autoconf
|
||||||
|
elif [ -S /tmp/autoconf.sock ] ; then
|
||||||
|
RELOAD="/opt/entrypoint/reload.py"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# generate new conf
|
||||||
BLACKLIST="$(curl -s https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/_generator_lists/bad-user-agents.list)
|
BLACKLIST="$(curl -s https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/_generator_lists/bad-user-agents.list)
|
||||||
$(curl -s https://raw.githubusercontent.com/JayBizzle/Crawler-Detect/master/raw/Crawlers.txt)"
|
$(curl -s https://raw.githubusercontent.com/JayBizzle/Crawler-Detect/master/raw/Crawlers.txt)"
|
||||||
|
if [ "$?" -ne 0 ] ; then
|
||||||
|
job_log "[BLACKLIST] can't update user-agent list"
|
||||||
|
fi
|
||||||
DATA=""
|
DATA=""
|
||||||
IFS=$'\n'
|
IFS=$'\n'
|
||||||
for ua in $BLACKLIST ; do
|
for ua in $BLACKLIST ; do
|
||||||
DATA="${DATA}~*${ua} yes;\n"
|
DATA="${DATA}~*${ua} yes;\n"
|
||||||
done
|
done
|
||||||
DATA_ESCAPED=$(echo "$DATA" | sed 's: :\\\\ :g' | sed 's:\\\\ yes;: yes;:g' | sed 's:\\\\\\ :\\\\ :g')
|
DATA_ESCAPED=$(echo "$DATA" | sed 's: :\\\\ :g' | sed 's:\\\\ yes;: yes;:g' | sed 's:\\\\\\ :\\\\ :g')
|
||||||
|
echo -e "map \$http_user_agent \$bad_user_agent { default no; $DATA_ESCAPED }" > /tmp/map-user-agent.conf
|
||||||
|
|
||||||
echo -e "map \$http_user_agent \$bad_user_agent { default no; $DATA_ESCAPED }" > /etc/nginx/map-user-agent.conf
|
# check number of lines
|
||||||
cp /etc/nginx/map-user-agent.conf /cache
|
lines="$(wc -l /tmp/map-user-agent.conf | cut -d ' ' -f 1)"
|
||||||
|
if [ "$lines" -gt 1 ] ; then
|
||||||
if [ -f /tmp/nginx.pid ] ; then
|
mv /tmp/map-user-agent.conf /etc/nginx/map-user-agent.conf
|
||||||
/usr/sbin/nginx -s reload > /dev/null 2>&1
|
job_log "[BLACKLIST] user-agent list updated ($lines entries)"
|
||||||
|
if [ "$RELOAD" != "" ] ; then
|
||||||
|
$RELOAD
|
||||||
|
if [ "$?" -eq 0 ] ; then
|
||||||
|
cp /etc/nginx/map-user-agent.conf /cache
|
||||||
|
job_log "[NGINX] successfull nginx reload after user-agent list update"
|
||||||
|
else
|
||||||
|
cp /cache/map-user-agent.conf /etc/nginx
|
||||||
|
job_log "[NGINX] failed nginx reload after user-agent list update fallback to old list"
|
||||||
|
$RELOAD
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cp /etc/nginx/map-user-agent.conf /cache
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
job_log "[BLACKLIST] can't update user-agent list"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/map-user-agent.conf 2> /dev/null
|
||||||
|
|||||||
23
ui/Dockerfile
Normal file
23
ui/Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
RUN apk add py3-pip apache2-utils bash && \
|
||||||
|
pip3 install docker flask && \
|
||||||
|
mkdir /opt/entrypoint && \
|
||||||
|
mkdir -p /opt/confs/site && \
|
||||||
|
addgroup -g 101 nginx && \
|
||||||
|
adduser -h /var/cache/nginx -g nginx -s /sbin/nologin -G nginx -D -H -u 101 nginx && \
|
||||||
|
mkdir /etc/nginx && \
|
||||||
|
chown root:nginx /etc/nginx && \
|
||||||
|
chmod 770 /etc/nginx
|
||||||
|
|
||||||
|
|
||||||
|
COPY confs/site/ /opt/confs/site
|
||||||
|
COPY entrypoint/* /opt/entrypoint/
|
||||||
|
COPY ui/ /opt/entrypoint/
|
||||||
|
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh
|
||||||
|
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
WORKDIR /opt/entrypoint
|
||||||
|
ENV FLASK_APP entrypoint.py
|
||||||
|
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||||
19
ui/Dockerfile-amd64
Normal file
19
ui/Dockerfile-amd64
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
FROM amd64/alpine
|
||||||
|
|
||||||
|
RUN apk add py3-pip apache2-utils bash && \
|
||||||
|
pip3 install docker flask && \
|
||||||
|
mkdir /opt/entrypoint && \
|
||||||
|
mkdir -p /opt/confs/site
|
||||||
|
|
||||||
|
COPY confs/site/ /opt/confs/site
|
||||||
|
COPY entrypoint/* /opt/entrypoint/
|
||||||
|
COPY ui/ /opt/entrypoint/
|
||||||
|
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh
|
||||||
|
|
||||||
|
VOLUME /etc/nginx
|
||||||
|
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
WORKDIR /opt/entrypoint
|
||||||
|
ENV FLASK_APP entrypoint.py
|
||||||
|
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||||
26
ui/Dockerfile-arm32v7
Normal file
26
ui/Dockerfile-arm32v7
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
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
|
||||||
|
RUN apk add curl && curl -L ${QEMU_URL} | tar zxvf - -C . --strip-components 1
|
||||||
|
|
||||||
|
FROM arm32v7/alpine
|
||||||
|
|
||||||
|
COPY --from=builder qemu-arm-static /usr/bin
|
||||||
|
|
||||||
|
RUN apk add py3-pip apache2-utils bash && \
|
||||||
|
pip3 install docker flask && \
|
||||||
|
mkdir /opt/entrypoint && \
|
||||||
|
mkdir -p /opt/confs/site
|
||||||
|
|
||||||
|
COPY confs/site/ /opt/confs/site
|
||||||
|
COPY entrypoint/* /opt/entrypoint/
|
||||||
|
COPY ui/ /opt/entrypoint/
|
||||||
|
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh
|
||||||
|
|
||||||
|
VOLUME /etc/nginx
|
||||||
|
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
WORKDIR /opt/entrypoint
|
||||||
|
ENV FLASK_APP entrypoint.py
|
||||||
|
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||||
26
ui/Dockerfile-arm64v8
Normal file
26
ui/Dockerfile-arm64v8
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
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
|
||||||
|
RUN apk add curl && curl -L ${QEMU_URL} | tar zxvf - -C . --strip-components 1
|
||||||
|
|
||||||
|
FROM arm64v8/alpine
|
||||||
|
|
||||||
|
COPY --from=builder qemu-aarch64-static /usr/bin
|
||||||
|
|
||||||
|
RUN apk add py3-pip apache2-utils bash && \
|
||||||
|
pip3 install docker flask && \
|
||||||
|
mkdir /opt/entrypoint && \
|
||||||
|
mkdir -p /opt/confs/site
|
||||||
|
|
||||||
|
COPY confs/site/ /opt/confs/site
|
||||||
|
COPY entrypoint/* /opt/entrypoint/
|
||||||
|
COPY ui/ /opt/entrypoint/
|
||||||
|
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh
|
||||||
|
|
||||||
|
VOLUME /etc/nginx
|
||||||
|
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
WORKDIR /opt/entrypoint
|
||||||
|
ENV FLASK_APP entrypoint.py
|
||||||
|
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||||
19
ui/Dockerfile-i386
Normal file
19
ui/Dockerfile-i386
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
FROM i386/alpine
|
||||||
|
|
||||||
|
RUN apk add py3-pip apache2-utils bash && \
|
||||||
|
pip3 install docker flask && \
|
||||||
|
mkdir /opt/entrypoint && \
|
||||||
|
mkdir -p /opt/confs/site
|
||||||
|
|
||||||
|
COPY confs/site/ /opt/confs/site
|
||||||
|
COPY entrypoint/* /opt/entrypoint/
|
||||||
|
COPY ui/ /opt/entrypoint/
|
||||||
|
RUN chmod +x /opt/entrypoint/*.py /opt/entrypoint/*.sh
|
||||||
|
|
||||||
|
VOLUME /etc/nginx
|
||||||
|
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
WORKDIR /opt/entrypoint
|
||||||
|
ENV FLASK_APP entrypoint.py
|
||||||
|
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||||
833
ui/config.json
Normal file
833
ui/config.json
Normal file
@@ -0,0 +1,833 @@
|
|||||||
|
{
|
||||||
|
"Misc":{
|
||||||
|
"id":"misc",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Server name",
|
||||||
|
"env":"SERVER_NAME",
|
||||||
|
"regex":"^([a-z\\-0-9]+\\.?)+$",
|
||||||
|
"id":"server-name",
|
||||||
|
"default":"www.bunkerity.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Max client size",
|
||||||
|
"env":"MAX_CLIENT_SIZE",
|
||||||
|
"regex":"^[0-9]+(k|K|m|M|g|G)?$",
|
||||||
|
"id":"max-client-size",
|
||||||
|
"default":"10m"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Allowed methods",
|
||||||
|
"env":"ALLOWED_METHODS",
|
||||||
|
"regex":"^((GET|POST|HEAD|PUT|DELETE|CONNECT|OPTIONS|TRACE)\\|?)+$",
|
||||||
|
"id":"allowed-methods",
|
||||||
|
"default":"GET|POST|HEAD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Serve files",
|
||||||
|
"env":"SERVE_FILES",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"serve-files",
|
||||||
|
"default":"yes"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Info leak":{
|
||||||
|
"id":"info-leak",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Remove headers",
|
||||||
|
"env":"REMOVE_HEADERS",
|
||||||
|
"regex":"^([A-Za-z0-9\\-] ?)*$",
|
||||||
|
"id":"remove-headers",
|
||||||
|
"default":"Server X-Powered-By X-AspNet-Version X-AspNetMvc-Version"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Basic auth":{
|
||||||
|
"id":"auth-basic",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use auth basic",
|
||||||
|
"env":"USE_AUTH_BASIC",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-auth-basic",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Auth basic location",
|
||||||
|
"env":"AUTH_BASIC_LOCATION",
|
||||||
|
"regex":"^(sitewide|/[A-Za-z0-9/]*)$",
|
||||||
|
"id":"auth-basic-location",
|
||||||
|
"default":"sitewide"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Auth basic user",
|
||||||
|
"env":"AUTH_BASIC_USER",
|
||||||
|
"regex":"^([A-Za-z0-9\\-_]+)$",
|
||||||
|
"id":"auth-basic-user",
|
||||||
|
"default":"changeme"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Auth basic password",
|
||||||
|
"env":"AUTH_BASIC_PASSWORD",
|
||||||
|
"regex":"^([\\S]+)$",
|
||||||
|
"id":"auth-basic-password",
|
||||||
|
"default":"changeme"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Auth basic text",
|
||||||
|
"regex":"^([\\S ]+)$",
|
||||||
|
"env":"AUTH_BASIC_TEXT",
|
||||||
|
"id":"auth-basic-text",
|
||||||
|
"default":"Restricted area"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Reverse proxy":{
|
||||||
|
"id":"reverse-proxy",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use reverse proxy",
|
||||||
|
"env":"USE_REVERSE_PROXY",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-reverse-proxy",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"multiple",
|
||||||
|
"label":"Reverse proxy",
|
||||||
|
"id":"reverse-proxy-params",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Reverse proxy url",
|
||||||
|
"env":"REVERSE_PROXY_URL",
|
||||||
|
"regex":".*",
|
||||||
|
"id":"reverse-proxy-url",
|
||||||
|
"multiple":"Reverse proxy",
|
||||||
|
"default":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Reverse proxy host",
|
||||||
|
"env":"REVERSE_PROXY_HOST",
|
||||||
|
"regex":".*",
|
||||||
|
"id":"reverse-proxy-host",
|
||||||
|
"multiple":"Reverse proxy",
|
||||||
|
"default":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Reverse proxy ws",
|
||||||
|
"env":"REVERSE_PROXY_WS",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"reverse-proxy-ws",
|
||||||
|
"multiple":"Reverse proxy",
|
||||||
|
"default":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Reverse proxy custom headers",
|
||||||
|
"env":"REVERSE_PROXY_HEADERS",
|
||||||
|
"regex":".*",
|
||||||
|
"id":"reverse-proxy-headers",
|
||||||
|
"multiple":"Reverse proxy",
|
||||||
|
"default":""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Proxy real ip",
|
||||||
|
"env":"PROXY_REAL_IP",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"proxy-real-ip",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy real ip from",
|
||||||
|
"env":"PROXY_REAL_IP_FROM",
|
||||||
|
"regex":"^(\\d+.\\d+.\\d+.\\d+(/\\d+)? ?)*$",
|
||||||
|
"id":"proxy-real-ip-from",
|
||||||
|
"default":"192.168.0.0/16 172.16.0.0/12 10.0.0.0/8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy real ip header",
|
||||||
|
"env":"PROXY_REAL_IP_HEADER",
|
||||||
|
"regex":"^([A-Za-z0-9\\-])+$",
|
||||||
|
"id":"proxy-real-ip-header",
|
||||||
|
"default":"X-Forwarded-For"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy real ip recursive",
|
||||||
|
"env":"PROXY_REAL_IP_RECURSIVE",
|
||||||
|
"regex":"^(on|off)$",
|
||||||
|
"id":"proxy-real-ip-recursive",
|
||||||
|
"default":"on"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Compression":{
|
||||||
|
"id":"compression",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use gzip",
|
||||||
|
"env":"USE_GZIP",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-gzip",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Gzip comp level",
|
||||||
|
"env":"GZIP_COMP_LEVEL",
|
||||||
|
"regex":"^[1-9]$",
|
||||||
|
"id":"gzip-comp-level",
|
||||||
|
"default":"5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Gzip min length",
|
||||||
|
"env":"GZIP_MIN_LENGTH",
|
||||||
|
"regex":"^[0-9]+$",
|
||||||
|
"id":"gzip-min-length",
|
||||||
|
"default":"1000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Gzip types",
|
||||||
|
"env":"GZIP_TYPES",
|
||||||
|
"regex":"^([a-z/\\+\\-\\.] ?)*$",
|
||||||
|
"id":"gzip-types",
|
||||||
|
"default":"application/atom+xml application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use brotli",
|
||||||
|
"env":"USE_BROTLI",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-brotli",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Brotli comp level",
|
||||||
|
"env":"BROTLI_COMP_LEVEL",
|
||||||
|
"regex":"^[1-9]$",
|
||||||
|
"id":"brotli-comp-level",
|
||||||
|
"default":"6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Brotli min length",
|
||||||
|
"env":"BROTLI_MIN_LENGTH",
|
||||||
|
"regex":"^[0-9]+$",
|
||||||
|
"id":"brotli-min-length",
|
||||||
|
"default":"1000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Brotli types",
|
||||||
|
"env":"BROTLI_TYPES",
|
||||||
|
"regex":"^([a-z/\\+\\-\\.] ?)*$",
|
||||||
|
"id":"brotli-types",
|
||||||
|
"default":"application/atom+xml application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Cache":{
|
||||||
|
"id":"cache",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use client cache",
|
||||||
|
"env":"USE_CLIENT_CACHE",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-client-cache",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Client cache extensions",
|
||||||
|
"env":"CLIENT_CACHE_EXTENSIONS",
|
||||||
|
"regex":"^([a-z0-9]\\|?)*$",
|
||||||
|
"id":"client-cache-extensions",
|
||||||
|
"default":"jpg|jpeg|png|bmp|ico|svg|tif|css|js|otf|ttf|eot|woff|woff2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Client cache control",
|
||||||
|
"env":"CLIENT_CACHE_CONTROL",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"client-cache-control",
|
||||||
|
"default":"public, max-age=15552000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Client cache etag",
|
||||||
|
"env":"CLIENT_CACHE_ETAG",
|
||||||
|
"regex":"^(on|off)$",
|
||||||
|
"id":"client-cache-etag",
|
||||||
|
"default":"on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use open file cache",
|
||||||
|
"env":"USE_OPEN_FILE_CACHE",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-open-file-cache",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Open file cache",
|
||||||
|
"env":"OPEN_FILE_CACHE",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"open-file-cache",
|
||||||
|
"default":"max=1000 inactive=20s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Open file cache errors",
|
||||||
|
"env":"OPEN_FILE_CACHE_ERRORS",
|
||||||
|
"regex":"^(on|off)$",
|
||||||
|
"id":"open-file-cache-errors",
|
||||||
|
"default":"on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Open file cache min uses",
|
||||||
|
"env":"OPEN_FILE_CACHE_MIN_USES",
|
||||||
|
"regex":"^([1-9]+)$",
|
||||||
|
"id":"open-file-cache-min-uses",
|
||||||
|
"default":"2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Open file cache valid",
|
||||||
|
"env":"OPEN_FILE_CACHE_VALID",
|
||||||
|
"regex":"^\\d+(ms|s|m|h|d|w|M|y)$",
|
||||||
|
"id":"open-file-cache-valid",
|
||||||
|
"default":"30s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use proxy cache",
|
||||||
|
"env":"USE_PROXY_CACHE",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-proxy-cache",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy cache path zone size",
|
||||||
|
"env":"PROXY_CACHE_PATH_ZONE_SIZE",
|
||||||
|
"regex":"^[0-9]+(k|K|m|M|g|G)?$",
|
||||||
|
"id":"proxy-cache-path-zone-size",
|
||||||
|
"default":"10m"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy cache path params",
|
||||||
|
"env":"PROXY_CACHE_PATH_PARAMS",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"proxy-cache-path-params",
|
||||||
|
"default":"max_size=100m"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy cache methods",
|
||||||
|
"env":"PROXY_CACHE_METHODS",
|
||||||
|
"regex":"^((GET|POST|HEAD|PUT|DELETE|CONNECT|OPTIONS|TRACE) ?)+$",
|
||||||
|
"id":"proxy-cache-methods",
|
||||||
|
"default":"GET HEAD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy cache min uses",
|
||||||
|
"env":"PROXY_CACHE_MIN_USES",
|
||||||
|
"regex":"^([1-9]+)$",
|
||||||
|
"id":"proxy-cache-min-uses",
|
||||||
|
"default":"2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy cache key",
|
||||||
|
"env":"PROXY_CACHE_KEY",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"proxy-cache-key",
|
||||||
|
"default":"\\$scheme\\$host\\$request_uri"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy cache valid",
|
||||||
|
"env":"PROXY_CACHE_VALID",
|
||||||
|
"regex":"^(\\d{3}=\\d+(ms|s|m|h|d|w|M|y) ?)+$",
|
||||||
|
"id":"proxy-cache-valid",
|
||||||
|
"default":"200=10m 301=10m 302=1h"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy no cache",
|
||||||
|
"env":"PROXY_NO_CACHE",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"proxy-no-cache",
|
||||||
|
"default":"\\$http_authorization"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Proxy cache bypass",
|
||||||
|
"env":"PROXY_CACHE_BYPASS",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"proxy-cache-bypass",
|
||||||
|
"default":"\\$http_authorization"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"HTTPS":{
|
||||||
|
"id":"https",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Auto lets encrypt",
|
||||||
|
"env":"AUTO_LETS_ENCRYPT",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"auto-lets-encrypt",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Email lets encrypt",
|
||||||
|
"env":"EMAIL_LETS_ENCRYPT",
|
||||||
|
"regex":"^([a-z0-9\\-\\.]+@([a-z\\-0-9]+\\.?)|.{0})$",
|
||||||
|
"id":"email-lets-encrypt",
|
||||||
|
"default":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Redirect http to https",
|
||||||
|
"env":"REDIRECT_HTTP_TO_HTTPS",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"redirect-http-to-https",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"HTTP2",
|
||||||
|
"env":"HTTP2",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"http2",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"HTTPS protocols",
|
||||||
|
"env":"HTTPS_PROTOCOLS",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"https-protocols",
|
||||||
|
"default":"TLSv1.2 TLSv1.3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Listen http",
|
||||||
|
"env":"LISTEN_HTTP",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"listen-http",
|
||||||
|
"default":"yes"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ModSecurity":{
|
||||||
|
"id":"modsecurity",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use modsecurity",
|
||||||
|
"env":"USE_MODSECURITY",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-modsecurity",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use modsecurity crs",
|
||||||
|
"env":"USE_MODSECURITY_CRS",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-modsecurity-crs",
|
||||||
|
"default":"yes"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Headers":{
|
||||||
|
"id":"headers",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"X frame options",
|
||||||
|
"env":"X_FRAME_OPTIONS",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"x-frame-options",
|
||||||
|
"default":"DENY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"X xss protection",
|
||||||
|
"env":"X_XSS_PROTECTION",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"x-xss-protection",
|
||||||
|
"default":"1; mode=block"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"X content type options",
|
||||||
|
"env":"X_CONTENT_TYPE_OPTIONS",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"x-content-type-options",
|
||||||
|
"default":"nosniff"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Referrer policy",
|
||||||
|
"env":"REFERRER_POLICY",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"referrer-policy",
|
||||||
|
"default":"no-referrer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Feature policy",
|
||||||
|
"env":"FEATURE_POLICY",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"feature-policy",
|
||||||
|
"default":"accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; display-capture 'none'; document-domain 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; sync-xhr 'none'; usb 'none'; vibrate 'none'; vr 'none'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Permissions policy",
|
||||||
|
"env":"PERMISSIONS_POLICY",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"permissions-policy",
|
||||||
|
"default":"accelerometer=(), ambient-light-sensor=(), autoplay=(), camera=(), display-capture=(), document-domain=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), speaker=(), sync-xhr=(), usb=(), vibrate=(), vr=()"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Cookie flags",
|
||||||
|
"env":"COOKIE_FLAGS",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"cookie-flags",
|
||||||
|
"default":"* HttpOnly SameSite=Lax"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Cookie auto secure flag",
|
||||||
|
"env":"COOKIE_AUTO_SECURE_FLAG",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"cookie-auto-secure-flag",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Strict transport security",
|
||||||
|
"env":"STRICT_TRANSPORT_SECURITY",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"strict-transport-security",
|
||||||
|
"default":"max-age=31536000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Content security policy",
|
||||||
|
"env":"CONTENT_SECURITY_POLICY",
|
||||||
|
"regex":"^([\\S ]*)$",
|
||||||
|
"id":"content-security-policy",
|
||||||
|
"default":"object-src 'none'; frame-ancestors 'self'; form-action 'self'; block-all-mixed-content; sandbox allow-forms allow-same-origin allow-scripts allow-popups; base-uri 'self';"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Antibot":{
|
||||||
|
"id":"Antibot",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Use antibot",
|
||||||
|
"env":"USE_ANTIBOT",
|
||||||
|
"regex":"^(no|cookie|javascript|captcha|recaptcha)$",
|
||||||
|
"id":"use-antibot",
|
||||||
|
"default":"no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Antibot uri",
|
||||||
|
"env":"ANTIBOT_URI",
|
||||||
|
"regex":"^/([A-Za-z0-9\\-]/?)*$",
|
||||||
|
"id":"antibot-uri",
|
||||||
|
"default":"/challenge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Antibot session secret",
|
||||||
|
"env":"ANTIBOT_SESSION_SECRET",
|
||||||
|
"regex":"^([\\S]+)$",
|
||||||
|
"id":"antibot-session-secret",
|
||||||
|
"default":"random"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Antibot recaptcha score",
|
||||||
|
"env":"ANTIBOT_RECAPTCHA_SCORE",
|
||||||
|
"regex":"^0\\.\\d$",
|
||||||
|
"id":"antibot-recaptcha-score",
|
||||||
|
"default":"0.7"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Block":{
|
||||||
|
"id":"block",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Block user agent",
|
||||||
|
"env":"BLOCK_USER_AGENT",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"block-user-agent",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Block tor exit node",
|
||||||
|
"env":"BLOCK_TOR_EXIT_NODE",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"block-tor-exit-node",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Block proxies",
|
||||||
|
"env":"BLOCK_PROXIES",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"block-proxies",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Block abusers",
|
||||||
|
"env":"BLOCK_ABUSERS",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"block-abusers",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Block referrer",
|
||||||
|
"env":"BLOCK_REFERRER",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"block-referrer",
|
||||||
|
"default":"yes"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"DNSBL":{
|
||||||
|
"id":"dnsbl",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use dnsbl",
|
||||||
|
"env":"USE_DNSBL",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-dnsbl",
|
||||||
|
"default":"yes"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"CrowdSec":{
|
||||||
|
"id":"use-crowdsec",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use crowdsec",
|
||||||
|
"env":"USE_CROWDSEC",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-crowdsec",
|
||||||
|
"default":"no"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Whitelist":{
|
||||||
|
"id":"whitelist",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use whitelist ip",
|
||||||
|
"env":"USE_WHITELIST_IP",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-whitelist-ip",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use whitelist reverse",
|
||||||
|
"env":"USE_WHITELIST_REVERSE",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-whitelist-reverse",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Whitelist country",
|
||||||
|
"env":"WHITELIST_COUNTRY",
|
||||||
|
"regex":"^([A-Z]{2} ?)*$",
|
||||||
|
"id":"whitelist-country",
|
||||||
|
"default":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Whitelist user agent",
|
||||||
|
"env":"WHITELIST_USER_AGENT",
|
||||||
|
"regex":".*",
|
||||||
|
"id":"whitelist-user-agent",
|
||||||
|
"default":""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Blacklist":{
|
||||||
|
"id":"blacklist",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use blacklist ip",
|
||||||
|
"env":"USE_BLACKLIST_IP",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-blacklist-ip",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use blacklist reverse",
|
||||||
|
"env":"USE_BLACKLIST_REVERSE",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-blacklist-reverse",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Blacklist country",
|
||||||
|
"env":"BLACKLIST_COUNTRY",
|
||||||
|
"regex":"^([A-Z]{2} ?)*$",
|
||||||
|
"id":"blacklist-country",
|
||||||
|
"default":""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Limit conn":{
|
||||||
|
"id":"limit-conn",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use limit conn",
|
||||||
|
"env":"USE_LIMIT_CONN",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-limit-conn",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Limit conn max",
|
||||||
|
"env":"LIMIT_CONN_MAX",
|
||||||
|
"regex":"^\\d+$",
|
||||||
|
"id":"limit-conn-max",
|
||||||
|
"default":"40"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Limit req":{
|
||||||
|
"id":"limit-req",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use limit req",
|
||||||
|
"env":"USE_LIMIT_REQ",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-limit-req",
|
||||||
|
"default":"yes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Limit req rate",
|
||||||
|
"env":"LIMIT_REQ_RATE",
|
||||||
|
"regex":"^\\d+r/(ms|s|m|h|d)$",
|
||||||
|
"id":"limit-req-rate",
|
||||||
|
"default":"20r/s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Limit req burst",
|
||||||
|
"env":"LIMIT_REQ_BURST",
|
||||||
|
"regex":"^\\d+$",
|
||||||
|
"id":"limit-req-burst",
|
||||||
|
"default":"40"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PHP":{
|
||||||
|
"id":"php",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Remote php",
|
||||||
|
"env":"REMOTE_PHP",
|
||||||
|
"regex":"^([a-z\\-0-9]+\\.?)*$",
|
||||||
|
"id":"remote-php",
|
||||||
|
"default":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"label":"Remote php path",
|
||||||
|
"env":"REMOTE_PHP_PATH",
|
||||||
|
"regex":"^/([A-Za-z0-9\\-]/?)*$",
|
||||||
|
"id":"remote-php-path",
|
||||||
|
"default":"/app"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Fail2ban":{
|
||||||
|
"id":"fail2ban",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use fail2ban",
|
||||||
|
"env":"USE_FAIL2BAN",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-fail2ban",
|
||||||
|
"default":"yes"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ClamAV":{
|
||||||
|
"id":"clamav",
|
||||||
|
"params":[
|
||||||
|
{
|
||||||
|
"type":"checkbox",
|
||||||
|
"label":"Use clamav upload",
|
||||||
|
"env":"USE_CLAMAV_UPLOAD",
|
||||||
|
"regex":"^(yes|no)$",
|
||||||
|
"id":"use-clamav-upload",
|
||||||
|
"default":"yes"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
123
ui/entrypoint.py
Normal file
123
ui/entrypoint.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
from flask import Flask, render_template, current_app, request
|
||||||
|
|
||||||
|
import wrappers, utils
|
||||||
|
import os, json, re
|
||||||
|
|
||||||
|
app = Flask(__name__, static_url_path="/", static_folder="static", template_folder="templates")
|
||||||
|
ABSOLUTE_URI = ""
|
||||||
|
if "ABSOLUTE_URI" in os.environ :
|
||||||
|
ABSOLUTE_URI = os.environ["ABSOLUTE_URI"]
|
||||||
|
app.config["ABSOLUTE_URI"] = ABSOLUTE_URI
|
||||||
|
with open("/opt/entrypoint/config.json", "r") as f :
|
||||||
|
app.config["CONFIG"] = json.loads(f.read())
|
||||||
|
app.jinja_env.globals.update(env_to_summary_class=utils.env_to_summary_class)
|
||||||
|
app.jinja_env.globals.update(form_service_gen=utils.form_service_gen)
|
||||||
|
app.jinja_env.globals.update(form_service_gen_multiple=utils.form_service_gen_multiple)
|
||||||
|
app.jinja_env.globals.update(form_service_gen_multiple_values=utils.form_service_gen_multiple_values)
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
@app.route('/home')
|
||||||
|
def home():
|
||||||
|
check, client = wrappers.get_client()
|
||||||
|
if not check :
|
||||||
|
return render_template("error.html", title="Error", error=client)
|
||||||
|
check, instances = wrappers.get_instances(client)
|
||||||
|
if not check :
|
||||||
|
return render_template("error.html", title="Error", error=instances)
|
||||||
|
check, services = wrappers.get_services()
|
||||||
|
if not check :
|
||||||
|
return render_template("error.html", title="Error", error=services)
|
||||||
|
return render_template("home.html", title="Home", instances_number=len(instances), services_number=len(services))
|
||||||
|
|
||||||
|
@app.route('/instances', methods=["GET", "POST"])
|
||||||
|
def instances():
|
||||||
|
|
||||||
|
# Get the client
|
||||||
|
check, client = wrappers.get_client()
|
||||||
|
if not check :
|
||||||
|
return render_template("error.html", title="Error", error=client)
|
||||||
|
|
||||||
|
# Manage instances
|
||||||
|
operation = ""
|
||||||
|
if request.method == "POST" :
|
||||||
|
|
||||||
|
# Check operation
|
||||||
|
if not "operation" in request.form or not request.form["operation"] in ["reload", "start", "stop", "restart", "delete"] :
|
||||||
|
return render_template("error.html", title="Error", error="Missing operation parameter on /instances.")
|
||||||
|
|
||||||
|
# Check that all fields are present
|
||||||
|
if not "INSTANCE_ID" in request.form :
|
||||||
|
return render_template("error.html", title="Error", error="Missing INSTANCE_ID parameter.")
|
||||||
|
|
||||||
|
# Do the operation
|
||||||
|
check, operation = wrappers.operation_instance(client, request.form)
|
||||||
|
if not check :
|
||||||
|
return render_template("error.html", title="Error", error=operation)
|
||||||
|
|
||||||
|
# Display instances
|
||||||
|
check, instances = wrappers.get_instances(client)
|
||||||
|
if not check :
|
||||||
|
return render_template("error.html", title="Error", error=instances)
|
||||||
|
return render_template("instances.html", title="Instances", instances=instances, operation=operation)
|
||||||
|
|
||||||
|
@app.route('/services', methods=["GET", "POST"])
|
||||||
|
def services():
|
||||||
|
|
||||||
|
# Get the client
|
||||||
|
check, client = wrappers.get_client()
|
||||||
|
if not check :
|
||||||
|
return render_template("error.html", title="Error", error=client)
|
||||||
|
|
||||||
|
# Manage services
|
||||||
|
operation = ""
|
||||||
|
if request.method == "POST" :
|
||||||
|
|
||||||
|
# Check operation
|
||||||
|
if not "operation" in request.form or not request.form["operation"] in ["new", "edit", "delete"] :
|
||||||
|
return render_template("error.html", title="Error", error="Missing operation parameter on /services.")
|
||||||
|
|
||||||
|
# Check that all fields are present and they match the corresponding regex
|
||||||
|
env = {}
|
||||||
|
env["MULTISITE"] = "yes"
|
||||||
|
if request.form["operation"] in ["new", "edit"] :
|
||||||
|
for category in current_app.config["CONFIG"] :
|
||||||
|
for param in current_app.config["CONFIG"][category]["params"] :
|
||||||
|
if param["type"] == "multiple" :
|
||||||
|
for param_user in request.form :
|
||||||
|
if param_user.startswith(param["params"][0]["env"]) :
|
||||||
|
suffix = param_user.replace(param["params"][0]["env"], "")
|
||||||
|
for param_multiple in param["params"] :
|
||||||
|
if not param_multiple["env"] + suffix in request.form :
|
||||||
|
return render_template("error.html", title="Error", error="Missing " + param["env"] + " parameter.")
|
||||||
|
if not re.search(param_multiple["regex"], request.form[param_multiple["env"] + suffix]) :
|
||||||
|
return render_template("error.html", title="Error", error="Parameter " + param["env"] + " doesn't match regex.")
|
||||||
|
env[param_multiple["env"] + suffix] = request.form[param_multiple["env"] + suffix]
|
||||||
|
else :
|
||||||
|
if not param["env"] in request.form :
|
||||||
|
return render_template("error.html", title="Error", error="Missing " + param["env"] + " parameter.")
|
||||||
|
if not re.search(param["regex"], request.form[param["env"]]) :
|
||||||
|
return render_template("error.html", title="Error", error="Parameter " + param["env"] + " doesn't match regex.")
|
||||||
|
env[param["env"]] = request.form[param["env"]]
|
||||||
|
if request.form["operation"] == "edit" :
|
||||||
|
if not "OLD_SERVER_NAME" in request.form :
|
||||||
|
return render_template("error.html", title="Error", error="Missing OLD_SERVER_NAME parameter.")
|
||||||
|
if not re.search("^([a-z\-0-9]+\.?)+$", request.form["OLD_SERVER_NAME"]) :
|
||||||
|
return render_template("error.html", title="Error", error="Parameter OLD_SERVER_NAME doesn't match regex.")
|
||||||
|
elif request.form["operation"] == "delete" :
|
||||||
|
if not "SERVER_NAME" in request.form :
|
||||||
|
return render_template("error.html", title="Error", error="Missing SERVER_NAME parameter.")
|
||||||
|
if not re.search("^([a-z\-0-9]+\.?)+$", request.form["SERVER_NAME"]) :
|
||||||
|
return render_template("error.html", title="Error", error="Parameter SERVER_NAME doesn't match regex.")
|
||||||
|
|
||||||
|
# Do the operation
|
||||||
|
check, operation = wrappers.operation_service(client, request.form, env)
|
||||||
|
if not check :
|
||||||
|
render_template("error.html", title="Error", error=operation)
|
||||||
|
|
||||||
|
# Display services
|
||||||
|
check, services = wrappers.get_services()
|
||||||
|
if not check :
|
||||||
|
return render_template("error.html", title="Error", error=services)
|
||||||
|
return render_template("services.html", title="Services", services=services, operation=operation)
|
||||||
12
ui/hooks/post_push
Normal file
12
ui/hooks/post_push
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
curl -Lo manifest-tool https://github.com/estesp/manifest-tool/releases/download/v1.0.3/manifest-tool-linux-amd64
|
||||||
|
chmod +x manifest-tool
|
||||||
|
|
||||||
|
VERSION=$(cat VERSION | tr -d '\n')
|
||||||
|
if [ "$SOURCE_BRANCH" = "dev" ] ; then
|
||||||
|
./manifest-tool push from-args --ignore-missing --platforms linux/amd64,linux/386,linux/arm/v7,linux/arm64/v8 --template bunkerity/bunkerized-nginx-ui:dev-ARCHVARIANT --target bunkerity/bunkerized-nginx-ui:dev
|
||||||
|
elif [ "$SOURCE_BRANCH" = "master" ] ; then
|
||||||
|
./manifest-tool push from-args --ignore-missing --platforms linux/amd64,linux/386,linux/arm/v7,linux/arm64/v8 --template bunkerity/bunkerized-nginx-ui:ARCHVARIANT --target bunkerity/bunkerized-nginx-ui:${VERSION}
|
||||||
|
./manifest-tool push from-args --ignore-missing --platforms linux/amd64,linux/386,linux/arm/v7,linux/arm64/v8 --template bunkerity/bunkerized-nginx-ui:ARCHVARIANT --target bunkerity/bunkerized-nginx-ui:latest
|
||||||
|
fi
|
||||||
5
ui/hooks/pre_build
Normal file
5
ui/hooks/pre_build
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Register qemu-*-static for all supported processors except the
|
||||||
|
# current one, but also remove all registered binfmt_misc before
|
||||||
|
docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||||
6
ui/static/css/bootstrap.min.css
vendored
Normal file
6
ui/static/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
17
ui/static/css/custom.css
Normal file
17
ui/static/css/custom.css
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
.bd-placeholder-img {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
text-anchor: middle;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.bd-placeholder-img-lg {
|
||||||
|
font-size: 3.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main > .container {
|
||||||
|
padding: 100px 15px 0;
|
||||||
|
}
|
||||||
5
ui/static/css/fa.min.css
vendored
Normal file
5
ui/static/css/fa.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
ui/static/img/logo.png
Normal file
BIN
ui/static/img/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
6
ui/static/js/bootstrap.bundle.min.js
vendored
Normal file
6
ui/static/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user