diff --git a/llm_team_ui.py b/llm_team_ui.py index f901f25..8551bd0 100644 --- a/llm_team_ui.py +++ b/llm_team_ui.py @@ -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) diff --git a/server/fail2ban-jail.local b/server/fail2ban-jail.local new file mode 100644 index 0000000..05184a7 --- /dev/null +++ b/server/fail2ban-jail.local @@ -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 diff --git a/server/llm-team-ui.service b/server/llm-team-ui.service new file mode 100644 index 0000000..71971c9 --- /dev/null +++ b/server/llm-team-ui.service @@ -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 diff --git a/server/nginx-kb.conf b/server/nginx-kb.conf new file mode 100644 index 0000000..62a08ab --- /dev/null +++ b/server/nginx-kb.conf @@ -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; + } +} diff --git a/server/nginx-llms3.conf b/server/nginx-llms3.conf new file mode 100644 index 0000000..527dc7b --- /dev/null +++ b/server/nginx-llms3.conf @@ -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; + } +} diff --git a/server/setup.sh b/server/setup.sh new file mode 100755 index 0000000..a36e446 --- /dev/null +++ b/server/setup.sh @@ -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@" +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" diff --git a/server/sshd_config b/server/sshd_config new file mode 100644 index 0000000..65b2668 --- /dev/null +++ b/server/sshd_config @@ -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 diff --git a/server/sysctl-security.conf b/server/sysctl-security.conf new file mode 100644 index 0000000..3e42320 --- /dev/null +++ b/server/sysctl-security.conf @@ -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 diff --git a/server/ufw-rules.txt b/server/ufw-rules.txt new file mode 100644 index 0000000..993760d --- /dev/null +++ b/server/ufw-rules.txt @@ -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 +