Add server security configs and setup script

- Nginx configs with security headers (X-Frame-Options, CSP, etc.)
- fail2ban jails for nginx (botsearch, bad-request, forbidden)
- Kernel hardening via sysctl (rp_filter, no redirects, log martians)
- SSH hardening (no root, max 3 attempts, no X11)
- UFW rules export
- Idempotent setup.sh to restore all configs on fresh install
- Flask bound to 127.0.0.1 (nginx-only access)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
root 2026-03-25 04:47:54 -05:00
parent 0d00ced622
commit 6ea457d01d
9 changed files with 365 additions and 1 deletions

View File

@ -3958,4 +3958,4 @@ def run_extract(config):
if __name__ == "__main__":
print("\n LLM Team UI running at http://localhost:5000\n")
app.run(host="0.0.0.0", port=5000, debug=False)
app.run(host="127.0.0.1", port=5000, debug=False)

View File

@ -0,0 +1,45 @@
[DEFAULT]
bantime = 3600
maxretry = 3
findtime = 600
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
backend = systemd
[samba]
enabled = true
port = 139,445
filter = samba
logpath = /var/log/samba/log.smbd
maxretry = 5
bantime = 3600
[nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
[nginx-bad-request]
enabled = true
port = http,https
filter = nginx-bad-request
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
[nginx-forbidden]
enabled = true
port = http,https
filter = nginx-forbidden
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600

View File

@ -0,0 +1,14 @@
[Unit]
Description=LLM Team UI - Multi-model team web interface
After=network.target ollama.service
[Service]
Type=simple
User=root
WorkingDirectory=/root
ExecStart=/usr/bin/python3 /root/llm_team_ui.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

26
server/nginx-kb.conf Normal file
View File

@ -0,0 +1,26 @@
server {
listen 80;
listen 8080;
server_name island37.com www.island37.com;
root /var/www/html;
index index.html;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-XSS-Protection "1; mode=block" always;
location /api/ {
proxy_pass http://localhost:3031/api/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
add_header Access-Control-Allow-Origin "https://island37.com" always;
}
location / {
try_files $uri $uri/ /index.html;
}
}

26
server/nginx-llms3.conf Normal file
View File

@ -0,0 +1,26 @@
server {
listen 80 default_server;
server_name llms3.com www.llms3.com 192.168.1.176;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header X-XSS-Protection "1; mode=block" always;
location ^~ /.well-known/ {
root /var/www/html/llms3;
default_type "text/plain";
try_files $uri =404;
}
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

73
server/setup.sh Executable file
View File

@ -0,0 +1,73 @@
#!/bin/bash
# Server security setup for LLM Team UI (brain / island37.com)
# Run as root. Idempotent — safe to re-run.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo "=== LLM Team UI Server Setup ==="
# --- Nginx ---
echo "[1/6] Installing nginx configs..."
cp "$SCRIPT_DIR/nginx-llms3.conf" /etc/nginx/sites-available/llms3
cp "$SCRIPT_DIR/nginx-kb.conf" /etc/nginx/sites-available/kb
ln -sf /etc/nginx/sites-available/llms3 /etc/nginx/sites-enabled/llms3
ln -sf /etc/nginx/sites-available/kb /etc/nginx/sites-enabled/kb
nginx -t && systemctl reload nginx
echo " nginx OK"
# --- Systemd ---
echo "[2/6] Installing systemd unit..."
cp "$SCRIPT_DIR/llm-team-ui.service" /etc/systemd/system/llm-team-ui.service
systemctl daemon-reload
systemctl enable llm-team-ui
echo " systemd OK"
# --- Fail2ban ---
echo "[3/6] Installing fail2ban config..."
cp "$SCRIPT_DIR/fail2ban-jail.local" /etc/fail2ban/jail.local
systemctl restart fail2ban
echo " fail2ban OK"
# --- Sysctl ---
echo "[4/6] Installing kernel security settings..."
cp "$SCRIPT_DIR/sysctl-security.conf" /etc/sysctl.d/99-security.conf
sysctl --system > /dev/null 2>&1
echo " sysctl OK"
# --- SSH ---
echo "[5/6] Installing SSH config..."
cp "$SCRIPT_DIR/sshd_config" /etc/ssh/sshd_config
sshd -t && systemctl reload sshd
echo " sshd OK"
# --- UFW ---
echo "[6/6] Configuring firewall..."
ufw --force enable
ufw default deny incoming
ufw default allow outgoing
# SSH
ufw allow 22/tcp
# HTTP/HTTPS
ufw allow 80/tcp comment "HTTP web server"
ufw allow 443/tcp comment "HTTPS web server"
# LAN services
ufw allow from 192.168.1.0/24 to any port 139,445 proto tcp
ufw allow from 192.168.1.0/24 to any port 137,138 proto udp
ufw allow from 192.168.1.0/24 to any port 5000 comment "LLM Team UI"
ufw allow from 192.168.1.0/24 to any port 9000 comment "MinIO LAN only"
ufw deny 9000 comment "Block MinIO external"
ufw allow from 192.168.1.0/24 to any port 11434 comment "Ollama internal"
ufw allow from 192.168.1.0/24 to any port 18789 comment "OpenClaw brain"
# llms3.com Bun app
ufw allow 3030/tcp
echo " ufw OK"
echo ""
echo "=== Setup complete ==="
echo "Remaining manual steps:"
echo " 1. Add SSH public key: ssh-copy-id profit@<this-host>"
echo " 2. Then set PasswordAuthentication no in /etc/ssh/sshd_config"
echo " 3. Update DNS to point to this server, then run:"
echo " certbot --nginx -d llms3.com -d www.llms3.com"

135
server/sshd_config Normal file
View File

@ -0,0 +1,135 @@
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Include /etc/ssh/sshd_config.d/*.conf
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to "no" here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
# Change to "yes" to enable keyboard-interactive authentication. Depending on
# the system's configuration, this may involve passwords, challenge-response,
# one-time passwords or some combination of these and other methods.
# Beware issues with some PAM modules and threads.
KbdInteractiveAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the KbdInteractiveAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via KbdInteractiveAuthentication may bypass
# the setting of "PermitRootLogin prohibit-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and KbdInteractiveAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
#X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale and color environment variables
AcceptEnv LANG LC_* COLORTERM NO_COLOR
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
# Added by Failover - 2026-02-18 (partial hardening, awaiting J's SSH key)
PermitRootLogin no
MaxAuthTries 3
MaxSessions 2
Banner /etc/ssh/banner
X11Forwarding no
PermitEmptyPasswords no
ClientAliveInterval 300
ClientAliveCountMax 2
LoginGraceTime 60

View File

@ -0,0 +1,21 @@
# Reverse path filtering - drop packets with spoofed source IPs
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Don't send ICMP redirects (not a router)
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Don't accept ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# Don't accept source-routed packets
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# Log martian packets (spoofed, source-routed, redirect)
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

24
server/ufw-rules.txt Normal file
View File

@ -0,0 +1,24 @@
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
139,445/tcp ALLOW IN 192.168.1.0/24
137,138/udp ALLOW IN 192.168.1.0/24
3030/tcp ALLOW IN Anywhere
11434 ALLOW IN 192.168.1.0/24 # Ollama internal
18789 ALLOW IN 192.168.1.0/24 # OpenClaw brain
80/tcp ALLOW IN Anywhere # HTTP web server
443/tcp ALLOW IN Anywhere # HTTPS web server
5000 ALLOW IN 192.168.1.0/24 # LLM Team UI
9000 ALLOW IN 192.168.1.0/24 # MinIO LAN only
9000 DENY IN Anywhere # Block MinIO external
22/tcp (v6) ALLOW IN Anywhere (v6)
3030/tcp (v6) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6) # HTTP web server
443/tcp (v6) ALLOW IN Anywhere (v6) # HTTPS web server
9000 (v6) DENY IN Anywhere (v6) # Block MinIO external