Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
322704c
Update Webmin conf script to also write IPv6 rules
JedMeister May 13, 2026
2fe4e01
Enable HSTS, redirect HTTP => HTTPS and note disabling TLSv1.2 in future
JedMeister May 14, 2026
492ed75
Update logging and merge into conf/turnkey.d/webmin-conf; rename webm…
JedMeister May 15, 2026
4d2690c
Bugfix webmin-conf-logging
JedMeister May 19, 2026
b654e3e
Work around bash script race condition (process substitution directly…
JedMeister May 19, 2026
dcee63f
Update fail2ban defaults; longer 'findtime' to 10min (hardened); incr…
JedMeister May 20, 2026
f92d4d5
Webmin conf - Force ssl/tls and hsts; 30 min session timeout
JedMeister May 20, 2026
6904555
Don't install webmin-net by default - works around #2118
JedMeister May 20, 2026
aaf1c4d
Install iptables-persistent - resolves issue enabling/disabling firew…
JedMeister May 20, 2026
20f20bd
Update firewall rule generation for use with 'iptables-persistent' pa…
JedMeister May 20, 2026
748dc54
Update TurnKey webmin patch to disable Webmin Let's Encrypt
JedMeister May 20, 2026
58c6ebc
Fail if Webmin LE patch doesn't apply cleanly
JedMeister May 20, 2026
3cbcbce
Configure adminer specific logging for all supported webservers - con…
JedMeister May 20, 2026
4421794
Rotate Adminer log files (webserver agnostic)
JedMeister May 20, 2026
d974c0e
Add Adminer fail2ban conf
JedMeister May 20, 2026
6f98b9b
Bugfix sed command (extended regex without '-E')
JedMeister May 20, 2026
f1557fe
Remove redundant bugfix
JedMeister May 22, 2026
9236516
Remove another redundant bugfix
JedMeister May 22, 2026
9d730ca
Remove invalid lighty conf (removed in v1.4.56 - Trixie has v1.4.79)
JedMeister May 22, 2026
0afd939
Enable TKL default ciphers
JedMeister May 22, 2026
550cd12
Lighty doesn't appear to support aliases, so replace config with syml…
JedMeister May 22, 2026
586a6bd
Lighty fails if www-data can't write to logs
JedMeister May 22, 2026
91fc88f
Default root ownership of /etc/adminer - www-data only needs access t…
JedMeister May 22, 2026
ef7669d
Fix nginx adminer config
JedMeister May 22, 2026
9591229
Enable php-fpm by default and split http & https blocks
JedMeister May 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion conf/adminer
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,26 @@ ln -sf $ADMINER_DIR/designs/nette/adminer.css $STATIC_DIR/default.css

ln -sf /etc/adminer/adminer.css /usr/share/adminer/adminer/adminer.css

# ensure www-data has read access to php files in /etc/adminer
# Ensure www-data has read access to php files in /etc/adminer
chown -R root:adm /etc/adminer
chown root:www-data /etc/adminer /etc/adminer/tkl-*.php /etc/adminer/adminer.css
chmod 755 /etc/adminer
chmod 644 /etc/adminer/tkl-*.php /etc/adminer/adminer.css

# Set up custom Adminer specific logging (config in relevant webserver vhosts)
mkdir -p /var/log/adminer
touch /var/log/adminer/{access.log,error.log}
chown -R www-data:www-data /var/log/adminer
chmod 755 /var/log/adminer
chmod 644 /var/log/adminer/*.log

# Configure fail2ban protection for Adminer
cat >> /etc/fail2ban/jail.local <<EOF

[adminer-auth]
enabled = true
port = 12322
action = iptables[name=adminer, port=12322, protocol=tcp]
filter = adminer-auth
maxretry = 3
EOF
6 changes: 5 additions & 1 deletion conf/adminer-lighttpd
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#!/bin/bash -ex

# Ensure redirection is enabled
sed -i 's|^[[:space:]]*#([[:space:]]*"mod_redirect".*)|\1|' /etc/lighttpd/lighttpd.conf
sed -Ei 's|^[[:space:]]*#([[:space:]]*"mod_redirect".*)|\1|' /etc/lighttpd/lighttpd.conf

# Link conf file to available-sites, and enable it
ln -s /etc/adminer/lighttpd.conf /etc/lighttpd/conf-available/50-adminer.conf
lighty-enable-mod adminer || true
lighty-enable-mod accesslog

# Lighty doesn't support aliases, so we need to symlink tkl-index
ln -sf /etc/adminer/tkl-index.php /usr/share/adminer/adminer/tkl-index.php
30 changes: 0 additions & 30 deletions conf/turnkey.d/fail2ban-fixes
Original file line number Diff line number Diff line change
@@ -1,35 +1,5 @@
#!/bin/bash -e

# explictly allow ipv6 - see Debian bug #1024305:
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1024305

CONF=/etc/fail2ban/fail2ban.conf
if ! grep -q '^allowipv6' $CONF; then
sed -i '\|^\[Definition\]|a \\nallowipv6 = auto' $CONF
fi

# ensure that fail2ban blocks known users with incorrect key - see Debian
# Bug #1038779 - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1038779

cat > fail2ban.patch <<EOF
--- /etc/fail2ban/filter.d/sshd.conf.orig
+++ /etc/fail2ban/filter.d/sshd.conf
@@ -97,9 +97,9 @@
# consider failed publickey for invalid users only:
cmnfailre-failed-pub-invalid = ^Failed publickey for invalid user <F-USER>(?P<cond_user>\S+)|(?:(?! from ).)*?</F-USER> from <HOST>%(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$)
# consider failed publickey for valid users too (don't need RE, see cmnfailed):
-cmnfailre-failed-pub-any =
+cmnfailre-failed-pub-any = ^Failed publickey for <F-USER>(?P<cond_user>\S+)|(?:(?! from ).)*?</F-USER> from <HOST>%(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$)
# same as invalid, but consider failed publickey for valid users too, just as no failure (helper to get IP and user-name only, see cmnfailed):
-cmnfailre-failed-pub-nofail = <cmnfailre-failed-pub-invalid>
+cmnfailre-failed-pub-nofail = <cmnfailre-failed-pub-any>
# don't consider failed publickey as failures (don't need RE, see cmnfailed):
cmnfailre-failed-pub-ignore =

EOF
git apply fail2ban.patch
rm fail2ban.patch

cat > /etc/cron.weekly/fail2ban <<EOF
#!/bin/sh
#
Expand Down
28 changes: 0 additions & 28 deletions conf/turnkey.d/webmin-conf

This file was deleted.

51 changes: 51 additions & 0 deletions conf/turnkey.d/webmin-conf-logging
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash -e

CONF=/etc/webmin/miniserv.conf
LOG_DIR=/var/log/webmin

update_or_add() {
key=$1
value=$2
if grep -q "$key" "$CONF"; then
sed -i "s|$key=.*|$key=$value|" "$CONF"
else
echo "$key=$value" >> "$CONF"
fi
}

update_or_add port 12321
update_or_add listen 12321
update_or_add keyfile /etc/ssl/private/cert.pem
update_or_add certfile
update_or_add cipher_list_def 0
update_or_add error_handler_401 401.cgi
update_or_add error_handler_404 404.cgi
update_or_add error_handler_403 403.cgi
update_or_add nolog '\/stats\.cgi\?xhr\-stats\=general'
update_or_add no_tls1 1
update_or_add no_tls1_1 1
# TODO: Disable TLSv1.2 in a future release (i.e. append '1': 'no_tls1_2 1')
update_or_add no_tls1_2
update_or_add extracas
update_or_add ssl_hsts 1
update_or_add ssl_enforce 2 # force with hsts - '1' forces ssl but not hsts
update_or_add ssl_redirect 1
update_or_add session_timeout 1800 # 30 minutes
# update logfile location
update_or_add logfile "$LOG_DIR/miniserv.log"
update_or_add errorlog "$LOG_DIR/miniserv.error"

# Note: Updating Webmin config for it's own log file as below does not actually
# work (continues to log to /var/webmin/webmin.log) but we'll work around that
# via symlinks and update the config file to point to the actual log file
# anyway.
CONF=/etc/webmin/config
update_or_add logfile "$LOG_DIR/webmin.log"

# Prime log files and set permissions
mkdir -p "$LOG_DIR"
touch "$LOG_DIR"/{miniserv.log,miniserv.error,webmin.log}
chmod 750 "$LOG_DIR"
chmod 640 "$LOG_DIR"/*.log
rm -f /var/webmin/webmin.log
ln -sf /var/log/webmin/webmin.log /var/webmin/webmin.log
77 changes: 54 additions & 23 deletions conf/turnkey.d/webmin-fw
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
#!/bin/sh -e
#!/bin/bash -e

set ${WEBMIN_FW_TCP_INCOMING:=22 80 443 12321}
# TODO: drop use of iptables-legacy and use nftables directly

CONF=/etc/iptables.up.rules
set "${WEBMIN_FW_TCP_INCOMING:=22 80 443 12321}"

cat > $CONF <<EOF
# Read into an array of sorted unique values
# Note: lastpipe is enabled to work around race condition when combining
# readarray directly with process substitution in bash scripts (job control
# must be off)
shopt -s lastpipe

tr ' ' '\n' <<<"$WEBMIN_FW_TCP_INCOMING" \
| sort -un \
| readarray -t WEBMIN_FW_TCP_INCOMING

# Disable lastpipe again to ensure no unexpected behavior later...
shopt -u lastpipe

# iptables-persistent package compatible config
for conf in /etc/iptables/rules.v4 /etc/iptables/rules.v6; do
if [[ "$conf" == *"rules.v6" ]]; then
# IPv6 should all accept all ICMPv6 types, not just echo-request
# ICMPv6 is essential for neighbour discovery (NDP), router
# advertisements, and path MTU - blocking it breaks IPv6 networking
# in ways that aren't obvious.
ICMP="-A INPUT -p ipv6-icmp -j ACCEPT"
else
ICMP="-A INPUT -p icmp -m icmp --icmp-type echo-request -j ACCEPT"
fi
cat > "$conf" <<EOF
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
Expand All @@ -24,31 +48,38 @@ COMMIT
:INPUT DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type echo-request -j ACCEPT
$ICMP
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
EOF

for port in $WEBMIN_FW_TCP_INCOMING; do
echo "-A INPUT -p tcp -m tcp --dport $port -j ACCEPT" >> $CONF
done

if [ "$WEBMIN_FW_UDP_INCOMING" ]; then
for port in $WEBMIN_FW_UDP_INCOMING; do
echo "-A INPUT -p udp -m udp --dport $port -j ACCEPT" >> $CONF
for port in "${WEBMIN_FW_TCP_INCOMING[@]}"; do
echo "-A INPUT -p tcp -m tcp --dport $port -j ACCEPT" >> "$conf"
done
fi

if [ "$WEBMIN_FW_TCP_INCOMING_REJECT" ]; then
for port in $WEBMIN_FW_TCP_INCOMING_REJECT; do
echo "-A INPUT -p tcp -m tcp --dport $port -j REJECT" >> $CONF
done
fi
if [[ "$WEBMIN_FW_UDP_INCOMING" ]]; then
readarray -t WEBMIN_FW_UDP_INCOMING \
< <(tr ' ' '\n' <<< "$WEBMIN_FW_UDP_INCOMING" | sort -un)
for port in "${WEBMIN_FW_UDP_INCOMING[@]}"; do
echo "-A INPUT -p udp -m udp --dport $port -j ACCEPT" >> "$conf"
done
fi

echo "COMMIT" >> $CONF
if [ "$WEBMIN_FW_TCP_INCOMING_REJECT" ]; then
readarray -t WEBMIN_FW_TCP_INCOMING_REJECT \
< <(tr ' ' '\n' <<< "$WEBMIN_FW_TCP_INCOMING_REJECT" | sort -un)
for port in "${WEBMIN_FW_TCP_INCOMING_REJECT[@]}"; do
echo "-A INPUT -p tcp -m tcp --dport $port -j REJECT" >> "$conf"
done
fi

sed -i "/^$/d" $CONF
echo "COMMIT" >> "$conf"
sed -i "/^$/d" "$conf"
done

# As of Buster, Debian uses nftables for firewall; but webmin only supports legacy
# iptables - see https://github.com/webmin/webmin/issues/1097
# Debian has been using nftables for firewall for some time; but historically
# Webmin only supported legacy iptables. Webmin now supports nftables so as per
# TODO at top of this file TKL should migrate to nftables, but for now we'll
# continue to leverage legacy iptables functionality via 'iptables-legacy'.
#
# See https://github.com/webmin/webmin/issues/1097
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
13 changes: 0 additions & 13 deletions conf/turnkey.d/webmin-handy-log

This file was deleted.

2 changes: 2 additions & 0 deletions conf/turnkey.d/webmin-lets-enc
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
# Disable Webmin Let's Encrypt config - via patch

cd /usr/share/webmin/webmin
# test patch first; --check exits non-zero if doesn't apply cleanly
git apply --check /usr/local/src/webmin.patch
git apply /usr/local/src/webmin.patch
rm /usr/local/src/webmin.patch
3 changes: 3 additions & 0 deletions overlays/adminer/etc/adminer/apache.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
Alias /adminer/static /usr/share/adminer/adminer/static
Alias /externals /usr/share/adminer/externals
Alias /editor /usr/share/adminer/editor

CustomLog /var/log/adminer/access.log combined
ErrorLog /var/log/adminer/error.log
</VirtualHost>

<Directory /etc/adminer>
Expand Down
23 changes: 8 additions & 15 deletions overlays/adminer/etc/adminer/lighttpd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,26 @@ var.alias_redirects = (
"/externals/" => "/usr/share/adminer/externals/"
)

# Map tkl-index.php URL to the actual file in /etc/adminer/
$HTTP["url"] == "/tkl-index.php" {
fastcgi.server = (
".php" => ((
"socket" => "/run/php/php-fpm.sock", # may need adjustment?
"check-local" => "disable",
"bin-environment" => (
"SCRIPT_FILENAME" => "/etc/adminer/tkl-index.php"
)
))
)
}

index-file.names += ( "tkl-index.php" )

# IPv4
$SERVER["socket"] == "0.0.0.0:12322" {
ssl.engine = "enable"
server.document-root = "/usr/share/adminer/adminer/"
index-file.names = ( "tkl-index.php", "index.php" )
alias.url = alias_redirects
follow-symlink = "enable"

accesslog.filename = "/var/log/adminer/access.log"
server.errorlog = "/var/log/adminer/error.log"
}

# IPv6
$SERVER["socket"] == "[::]:12322" {
ssl.engine = "enable"
server.document-root = "/usr/share/adminer/adminer/"
index-file.names = ( "tkl-index.php", "index.php" )
alias.url = alias_redirects
follow-symlink = "enable"

accesslog.filename = "/var/log/adminer/access.log"
server.errorlog = "/var/log/adminer/error.log"
}
7 changes: 5 additions & 2 deletions overlays/adminer/etc/adminer/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ server {
listen [::]:12322 ssl;
include /etc/nginx/snippets/ssl.conf;
root /usr/share/adminer/adminer/;
error_log /var/log/nginx/adminer-error.log;

access_log /var/log/adminer/access.log;
error_log /var/log/adminer/error.log;

location / {
index tkl-index.php index.php;
Expand All @@ -14,9 +16,10 @@ server {

# Route tkl-index.php to /etc/adminer/
location = /tkl-index.php {
include /etc/nginx/snippets/fastcgi-php.conf;
fastcgi_param HTTPS on;
fastcgi_param SCRIPT_FILENAME /etc/adminer/tkl-index.php;
include /etc/nginx/snippets/php-fpm.conf;
fastcgi_pass unix:/run/php/php-fpm.sock;
}

location ~ \.php$ {
Expand Down
12 changes: 12 additions & 0 deletions overlays/adminer/etc/fail2ban/filter.d/adminer-auth.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Fail2Ban filter for adminer
#
# Provided by TurnKey GNU/Linux
# Works for Apache2, LigHTTPd & Nginx access logs

[INCLUDES]
before = common.conf

[Definition]
failregex = ^<HOST> .* "POST /adminer\.php.*" (200|302) .*$

ignoreregex =
23 changes: 23 additions & 0 deletions overlays/adminer/etc/logrotate.d/adminer
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/var/log/adminer/access.log
/var/log/adminer/error.log {
weekly
rotate 4
compress
missingok
notifempty
sharedscripts
postrotate
# Apache
if systemctl is-active --quiet apache2; then
systemctl reload apache2
fi
# Nginx
if systemctl is-active --quiet nginx; then
systemctl reload nginx
fi
# Lighttpd
if systemctl is-active --quiet lighttpd; then
systemctl reload lighttpd
fi
endscript
}
Loading