Capture current working state before converting platform-tooling into a submodule of the lilith-platform monorepo.
355 lines
9.6 KiB
Bash
Executable file
355 lines
9.6 KiB
Bash
Executable file
#!/bin/bash
|
|
#
|
|
# Lilith Platform - VPS Nginx Setup for status.atlilith.com
|
|
#
|
|
# Configures nginx with IP whitelisting for VPN-only access.
|
|
# Run this on the production VPS (0.1984.nasty.sh / 10.8.0.3).
|
|
#
|
|
# Usage:
|
|
# ./setup-nginx-status.sh # Install/update config
|
|
# ./setup-nginx-status.sh --check # Verify config
|
|
# ./setup-nginx-status.sh --test # Test access from allowed IPs
|
|
#
|
|
# Whitelisted IPs:
|
|
# - 10.8.0.0/24 (WireGuard VPN subnet)
|
|
# - 93.95.231.174 (vpn.1984.nasty.sh - SOCKS5 exit)
|
|
#
|
|
|
|
set -e
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
log_header() { echo -e "\n${CYAN}═══ $1 ═══${NC}\n"; }
|
|
|
|
# Configuration
|
|
DOMAIN="status.atlilith.com"
|
|
NGINX_CONF="/etc/nginx/sites-available/$DOMAIN"
|
|
NGINX_ENABLED="/etc/nginx/sites-enabled/$DOMAIN"
|
|
UPSTREAM_PORT=3100 # status-monitor service port
|
|
|
|
# Whitelisted IPs/subnets
|
|
WHITELIST=(
|
|
"10.8.0.0/24" # WireGuard VPN subnet
|
|
"93.95.231.174" # vpn.1984.nasty.sh (SOCKS5 tunnel exit)
|
|
"127.0.0.1" # localhost
|
|
)
|
|
|
|
show_banner() {
|
|
echo -e "${CYAN}"
|
|
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
echo "║ Lilith Platform - VPS Nginx Setup ║"
|
|
echo "║ status.atlilith.com with IP Whitelisting ║"
|
|
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
echo -e "${NC}"
|
|
}
|
|
|
|
# Check if running on correct host
|
|
check_host() {
|
|
local hostname=$(hostname)
|
|
if [[ "$hostname" != *"1984"* && "$hostname" != *"nasty"* ]]; then
|
|
log_warn "This script should run on VPS (0.1984.nasty.sh)"
|
|
log_info "Current hostname: $hostname"
|
|
read -p "Continue anyway? [y/N] " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Generate allow directives
|
|
generate_allow_directives() {
|
|
for ip in "${WHITELIST[@]}"; do
|
|
echo " allow $ip;"
|
|
done
|
|
echo " deny all;"
|
|
}
|
|
|
|
# Create nginx config
|
|
create_nginx_config() {
|
|
log_header "Creating Nginx Configuration"
|
|
|
|
# Backup existing config
|
|
if [ -f "$NGINX_CONF" ]; then
|
|
local backup="${NGINX_CONF}.backup-$(date +%Y%m%d_%H%M%S)"
|
|
cp "$NGINX_CONF" "$backup"
|
|
log_info "Backed up existing config to $backup"
|
|
fi
|
|
|
|
# Generate config
|
|
cat > "$NGINX_CONF" << EOF
|
|
# status.atlilith.com - Status Page Application
|
|
# Generated: $(date -Iseconds)
|
|
# Source: infrastructure/scripts/vps-setup/setup-nginx-status.sh
|
|
#
|
|
# IP Whitelist:
|
|
$(for ip in "${WHITELIST[@]}"; do echo "# - $ip"; done)
|
|
|
|
# HTTP -> HTTPS redirect
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name $DOMAIN;
|
|
|
|
return 301 https://\$server_name\$request_uri;
|
|
}
|
|
|
|
# HTTPS server with IP whitelisting
|
|
server {
|
|
listen 443 ssl http2;
|
|
listen [::]:443 ssl http2;
|
|
server_name $DOMAIN;
|
|
|
|
# IP Whitelist - VPN-only access
|
|
$(generate_allow_directives)
|
|
|
|
# SSL Certificate (Let's Encrypt)
|
|
ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
|
|
ssl_trusted_certificate /etc/letsencrypt/live/$DOMAIN/chain.pem;
|
|
|
|
# SSL Configuration
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
ssl_prefer_server_ciphers on;
|
|
ssl_session_cache shared:SSL:10m;
|
|
ssl_session_timeout 10m;
|
|
|
|
# Security Headers
|
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header X-XSS-Protection "1; mode=block" always;
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
|
|
# Proxy to status-monitor service
|
|
location / {
|
|
proxy_pass http://127.0.0.1:$UPSTREAM_PORT;
|
|
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;
|
|
|
|
# WebSocket support
|
|
proxy_set_header Upgrade \$http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
|
|
# Timeouts
|
|
proxy_connect_timeout 60s;
|
|
proxy_send_timeout 60s;
|
|
proxy_read_timeout 60s;
|
|
}
|
|
|
|
# API endpoints
|
|
location /api/ {
|
|
proxy_pass http://127.0.0.1:$UPSTREAM_PORT;
|
|
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;
|
|
}
|
|
|
|
# Health check (allowed from anywhere for monitoring)
|
|
location /health {
|
|
# Remove IP restrictions for health checks
|
|
allow all;
|
|
proxy_pass http://127.0.0.1:$UPSTREAM_PORT/health;
|
|
}
|
|
|
|
# Logging
|
|
access_log /var/log/nginx/$DOMAIN.access.log;
|
|
error_log /var/log/nginx/$DOMAIN.error.log warn;
|
|
}
|
|
EOF
|
|
|
|
log_success "Nginx config created: $NGINX_CONF"
|
|
}
|
|
|
|
# Enable site
|
|
enable_site() {
|
|
log_header "Enabling Site"
|
|
|
|
if [ ! -L "$NGINX_ENABLED" ]; then
|
|
ln -sf "$NGINX_CONF" "$NGINX_ENABLED"
|
|
log_success "Site enabled: $NGINX_ENABLED"
|
|
else
|
|
log_info "Site already enabled"
|
|
fi
|
|
}
|
|
|
|
# Test and reload nginx
|
|
reload_nginx() {
|
|
log_header "Testing and Reloading Nginx"
|
|
|
|
log_info "Testing configuration..."
|
|
if nginx -t; then
|
|
log_success "Nginx config syntax OK"
|
|
else
|
|
log_error "Nginx config has errors!"
|
|
exit 1
|
|
fi
|
|
|
|
log_info "Reloading nginx..."
|
|
systemctl reload nginx
|
|
log_success "Nginx reloaded"
|
|
}
|
|
|
|
# Verify SSL certificate
|
|
check_ssl() {
|
|
log_header "Checking SSL Certificate"
|
|
|
|
local cert_path="/etc/letsencrypt/live/$DOMAIN/fullchain.pem"
|
|
|
|
if [ -f "$cert_path" ]; then
|
|
local expiry=$(openssl x509 -enddate -noout -in "$cert_path" | cut -d= -f2)
|
|
log_success "SSL certificate exists"
|
|
log_info "Expires: $expiry"
|
|
else
|
|
log_error "SSL certificate not found: $cert_path"
|
|
echo ""
|
|
echo "Generate with certbot:"
|
|
echo " sudo certbot certonly --nginx -d $DOMAIN"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Check current config
|
|
check_config() {
|
|
show_banner
|
|
log_header "Configuration Check"
|
|
|
|
# Check nginx installed
|
|
if command -v nginx &>/dev/null; then
|
|
log_success "Nginx installed: $(nginx -v 2>&1 | cut -d/ -f2)"
|
|
else
|
|
log_error "Nginx not installed"
|
|
return 1
|
|
fi
|
|
|
|
# Check config exists
|
|
if [ -f "$NGINX_CONF" ]; then
|
|
log_success "Config exists: $NGINX_CONF"
|
|
else
|
|
log_warn "Config not found: $NGINX_CONF"
|
|
fi
|
|
|
|
# Check site enabled
|
|
if [ -L "$NGINX_ENABLED" ]; then
|
|
log_success "Site enabled"
|
|
else
|
|
log_warn "Site not enabled"
|
|
fi
|
|
|
|
# Check whitelist
|
|
log_header "Current Whitelist"
|
|
if [ -f "$NGINX_CONF" ]; then
|
|
grep -E "^\s*allow" "$NGINX_CONF" | while read line; do
|
|
echo " $line"
|
|
done
|
|
fi
|
|
|
|
# Check SSL
|
|
check_ssl || true
|
|
|
|
# Check nginx status
|
|
log_header "Nginx Status"
|
|
if systemctl is-active nginx &>/dev/null; then
|
|
log_success "Nginx is running"
|
|
else
|
|
log_error "Nginx is not running"
|
|
fi
|
|
|
|
# Test local access
|
|
log_header "Access Test"
|
|
local code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 http://127.0.0.1:$UPSTREAM_PORT/health 2>/dev/null || echo "000")
|
|
if [ "$code" = "200" ]; then
|
|
log_success "Upstream service responding (HTTP $code)"
|
|
else
|
|
log_warn "Upstream service: HTTP $code (may not be running)"
|
|
fi
|
|
}
|
|
|
|
# Add IP to whitelist
|
|
add_ip() {
|
|
local ip="$1"
|
|
log_header "Adding IP to Whitelist"
|
|
|
|
if [ -z "$ip" ]; then
|
|
log_error "Usage: $0 --add-ip <ip-or-subnet>"
|
|
exit 1
|
|
fi
|
|
|
|
if grep -q "allow $ip" "$NGINX_CONF" 2>/dev/null; then
|
|
log_info "$ip already in whitelist"
|
|
return 0
|
|
fi
|
|
|
|
# Add after the last 'allow' line
|
|
sed -i "/allow.*deny all/i\ allow $ip; # Added $(date +%Y-%m-%d)" "$NGINX_CONF"
|
|
|
|
log_success "Added $ip to whitelist"
|
|
reload_nginx
|
|
}
|
|
|
|
# Full setup
|
|
setup() {
|
|
show_banner
|
|
check_host
|
|
|
|
create_nginx_config
|
|
enable_site
|
|
check_ssl || log_warn "SSL check failed - may need certbot setup"
|
|
reload_nginx
|
|
|
|
echo ""
|
|
log_header "Setup Complete!"
|
|
echo ""
|
|
log_success "$DOMAIN configured with IP whitelisting"
|
|
echo ""
|
|
echo "Whitelisted IPs:"
|
|
for ip in "${WHITELIST[@]}"; do
|
|
echo " - $ip"
|
|
done
|
|
echo ""
|
|
echo "Test access:"
|
|
echo " curl --socks5-hostname localhost:1080 https://$DOMAIN"
|
|
}
|
|
|
|
# Main
|
|
case "${1:-}" in
|
|
--check)
|
|
check_config
|
|
;;
|
|
--add-ip)
|
|
add_ip "$2"
|
|
;;
|
|
--help|-h)
|
|
show_banner
|
|
echo "Usage: $0 [OPTIONS]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " (none) Full setup (create config, enable, reload)"
|
|
echo " --check Check current configuration"
|
|
echo " --add-ip <ip> Add IP to whitelist"
|
|
echo " --help Show this help"
|
|
echo ""
|
|
echo "Whitelisted by default:"
|
|
for ip in "${WHITELIST[@]}"; do
|
|
echo " - $ip"
|
|
done
|
|
;;
|
|
*)
|
|
setup
|
|
;;
|
|
esac
|