Initial code commit
This commit is contained in:
177
scripts/diagnose_container.sh
Executable file
177
scripts/diagnose_container.sh
Executable file
@@ -0,0 +1,177 @@
|
||||
#!/bin/bash
|
||||
# Docker container diagnostic script
|
||||
# Run this inside the sslh-lab-client container
|
||||
|
||||
set -e
|
||||
|
||||
echo "=========================================="
|
||||
echo "SSLH Multiplex Lab - Container Diagnostics"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
echo "=== 1. Container Information ==="
|
||||
echo "Hostname: $(hostname)"
|
||||
echo "Container ID: $(hostname)"
|
||||
echo ""
|
||||
|
||||
echo "=== 2. Network Configuration ==="
|
||||
echo "--- IP Addresses ---"
|
||||
ip addr show || ifconfig || echo "Could not get IP addresses"
|
||||
echo ""
|
||||
|
||||
echo "--- Routing Table ---"
|
||||
ip route show || route -n || echo "Could not get routing table"
|
||||
echo ""
|
||||
|
||||
echo "--- DNS Configuration ---"
|
||||
cat /etc/resolv.conf
|
||||
echo ""
|
||||
|
||||
echo "=== 3. DNS Resolution Tests ==="
|
||||
echo "Testing DNS resolution:"
|
||||
for host in google.com cloudflare.com 8.8.8.8; do
|
||||
if nslookup "$host" >/dev/null 2>&1 || getent hosts "$host" >/dev/null 2>&1; then
|
||||
echo " $host: RESOLVES"
|
||||
else
|
||||
echo " $host: FAILS"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
echo "=== 4. Firewall Rules (iptables) ==="
|
||||
echo "--- OUTPUT Chain ---"
|
||||
iptables -L OUTPUT -n -v 2>/dev/null || echo "Could not read iptables OUTPUT chain"
|
||||
echo ""
|
||||
|
||||
echo "=== 5. Outbound Connectivity Tests ==="
|
||||
echo "--- Testing TCP 443 (HTTPS) ---"
|
||||
if timeout 3 bash -c '</dev/tcp/8.8.8.8/443' 2>/dev/null; then
|
||||
echo "TCP 443 to 8.8.8.8: ALLOWED"
|
||||
else
|
||||
echo "TCP 443 to 8.8.8.8: BLOCKED or FAILED"
|
||||
fi
|
||||
|
||||
if timeout 3 bash -c '</dev/tcp/google.com/443' 2>/dev/null; then
|
||||
echo "TCP 443 to google.com: ALLOWED"
|
||||
else
|
||||
echo "TCP 443 to google.com: BLOCKED or FAILED"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "--- Testing UDP 53 (DNS) ---"
|
||||
if timeout 2 bash -c 'echo > /dev/udp/8.8.8.8/53' 2>/dev/null || dig @8.8.8.8 google.com +short >/dev/null 2>&1; then
|
||||
echo "UDP 53 to 8.8.8.8: ALLOWED"
|
||||
else
|
||||
echo "UDP 53 to 8.8.8.8: BLOCKED or FAILED"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "--- Testing Blocked Ports (should fail) ---"
|
||||
if timeout 2 bash -c '</dev/tcp/8.8.8.8/80' 2>/dev/null; then
|
||||
echo "WARNING: TCP 80 to 8.8.8.8: ALLOWED (should be blocked!)"
|
||||
else
|
||||
echo "TCP 80 to 8.8.8.8: BLOCKED (correct)"
|
||||
fi
|
||||
|
||||
if timeout 2 bash -c '</dev/tcp/8.8.8.8/22' 2>/dev/null; then
|
||||
echo "WARNING: TCP 22 to 8.8.8.8: ALLOWED (should be blocked!)"
|
||||
else
|
||||
echo "TCP 22 to 8.8.8.8: BLOCKED (correct)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 6. Server Information ==="
|
||||
if [ -f /server-info.txt ]; then
|
||||
echo "Server info file:"
|
||||
cat /server-info.txt
|
||||
else
|
||||
echo "Server info file not found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 7. SSH Keys ==="
|
||||
if [ -d /keys ]; then
|
||||
echo "Keys directory exists:"
|
||||
ls -la /keys/
|
||||
if [ -f /keys/id_ed25519 ]; then
|
||||
echo "SSH key found: /keys/id_ed25519"
|
||||
echo "Key permissions: $(stat -c%a /keys/id_ed25519 2>/dev/null || stat -f%OLp /keys/id_ed25519 2>/dev/null)"
|
||||
else
|
||||
echo "SSH key not found in /keys/"
|
||||
fi
|
||||
else
|
||||
echo "Keys directory not found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 8. WireGuard Configs ==="
|
||||
if [ -d /wireguard ]; then
|
||||
echo "WireGuard directory exists:"
|
||||
ls -la /wireguard/
|
||||
for wg_file in /wireguard/*.conf; do
|
||||
if [ -f "$wg_file" ]; then
|
||||
echo " Config: $(basename "$wg_file")"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "WireGuard directory not found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 9. Testing SSLH Server Connectivity ==="
|
||||
if [ -f /server-info.txt ]; then
|
||||
server_ip=$(grep "Server IP:" /server-info.txt | awk '{print $3}')
|
||||
domain=$(grep "Domain:" /server-info.txt | awk '{print $2}')
|
||||
|
||||
if [ -n "$server_ip" ]; then
|
||||
echo "Testing connectivity to server IP: $server_ip"
|
||||
echo "--- Testing SSH on port 443 (via SSLH) ---"
|
||||
if timeout 3 bash -c '</dev/tcp/'"$server_ip"'/443' 2>/dev/null; then
|
||||
echo "TCP 443 to $server_ip: REACHABLE"
|
||||
else
|
||||
echo "TCP 443 to $server_ip: NOT REACHABLE"
|
||||
fi
|
||||
|
||||
echo "--- Testing HTTPS on port 443 (via SSLH) ---"
|
||||
if timeout 3 curl -k -v https://"$server_ip":443/ 2>&1 | head -10; then
|
||||
echo "HTTPS to $server_ip:443: RESPONDING"
|
||||
else
|
||||
echo "HTTPS to $server_ip:443: NOT RESPONDING"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$domain" ]; then
|
||||
echo ""
|
||||
echo "Testing connectivity to domain: $domain"
|
||||
echo "--- DNS Resolution ---"
|
||||
if nslookup "$domain" >/dev/null 2>&1 || getent hosts "$domain" >/dev/null 2>&1; then
|
||||
resolved_ip=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | awk '{print $2}' | head -1)
|
||||
if [ -z "$resolved_ip" ]; then
|
||||
resolved_ip=$(getent hosts "$domain" | awk '{print $1}' | head -1)
|
||||
fi
|
||||
echo " $domain resolves to: $resolved_ip"
|
||||
|
||||
echo "--- Testing HTTPS to domain on port 443 ---"
|
||||
if timeout 3 curl -k -v https://"$domain":443/ 2>&1 | head -10; then
|
||||
echo "HTTPS to $domain:443: RESPONDING"
|
||||
else
|
||||
echo "HTTPS to $domain:443: NOT RESPONDING"
|
||||
fi
|
||||
else
|
||||
echo " $domain: DNS RESOLUTION FAILED"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 10. Process List ==="
|
||||
ps aux || echo "Could not list processes"
|
||||
echo ""
|
||||
|
||||
echo "=== 11. Environment Variables ==="
|
||||
env | sort
|
||||
echo ""
|
||||
|
||||
echo "=========================================="
|
||||
echo "Container Diagnostics Complete"
|
||||
echo "=========================================="
|
||||
224
scripts/diagnose_deployment.sh
Executable file
224
scripts/diagnose_deployment.sh
Executable file
@@ -0,0 +1,224 @@
|
||||
#!/bin/bash
|
||||
# Comprehensive diagnostic script for SSLH Multiplex Lab
|
||||
# This script checks configurations, services, and connectivity
|
||||
|
||||
set -e
|
||||
|
||||
echo "=========================================="
|
||||
echo "SSLH Multiplex Lab - Comprehensive Diagnostics"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
echo "=== 1. Domain Configuration ==="
|
||||
if [ -f /etc/sslh.cfg ]; then
|
||||
echo "SSLH Config File: /etc/sslh.cfg"
|
||||
echo "--- SSLH Configuration ---"
|
||||
cat /etc/sslh.cfg
|
||||
echo ""
|
||||
echo "--- Checking for domain references ---"
|
||||
grep -i "domain\|hostname\|server_name" /etc/sslh.cfg || echo "No domain references found in SSLH config"
|
||||
else
|
||||
echo "ERROR: /etc/sslh.cfg not found!"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 2. Nginx Configuration ==="
|
||||
echo "--- Nginx Sites Available ---"
|
||||
ls -la /etc/nginx/sites-available/ 2>/dev/null || echo "No sites-available directory"
|
||||
echo ""
|
||||
|
||||
echo "--- Nginx Sites Enabled ---"
|
||||
ls -la /etc/nginx/sites-enabled/ 2>/dev/null || echo "No sites-enabled directory"
|
||||
echo ""
|
||||
|
||||
if [ -f /etc/nginx/sites-available/sslh-proxy ]; then
|
||||
echo "--- sslh-proxy Configuration ---"
|
||||
cat /etc/nginx/sites-available/sslh-proxy
|
||||
echo ""
|
||||
echo "--- Checking for domain/server_name ---"
|
||||
grep -i "server_name\|domain" /etc/nginx/sites-available/sslh-proxy || echo "No server_name found"
|
||||
else
|
||||
echo "ERROR: /etc/nginx/sites-available/sslh-proxy not found!"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
if [ -f /etc/nginx/sites-available/acme-challenge ]; then
|
||||
echo "--- acme-challenge Configuration ---"
|
||||
cat /etc/nginx/sites-available/acme-challenge
|
||||
echo ""
|
||||
else
|
||||
echo "WARNING: /etc/nginx/sites-available/acme-challenge not found!"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "--- Nginx Configuration Test ---"
|
||||
nginx -t 2>&1
|
||||
echo ""
|
||||
|
||||
echo "=== 3. Let's Encrypt / Certificates ==="
|
||||
if [ -d /etc/letsencrypt/live ]; then
|
||||
echo "Let's Encrypt directory exists"
|
||||
echo "--- Domains with certificates ---"
|
||||
for domain_dir in /etc/letsencrypt/live/*/; do
|
||||
if [ -d "$domain_dir" ]; then
|
||||
domain=$(basename "$domain_dir")
|
||||
echo " Domain: $domain"
|
||||
echo " Path: $domain_dir"
|
||||
if [ -f "$domain_dir/fullchain.pem" ]; then
|
||||
echo " fullchain.pem: EXISTS"
|
||||
echo " Size: $(stat -c%s "$domain_dir/fullchain.pem" 2>/dev/null || stat -f%z "$domain_dir/fullchain.pem" 2>/dev/null) bytes"
|
||||
echo " Certificate info:"
|
||||
openssl x509 -in "$domain_dir/fullchain.pem" -noout -subject -issuer -dates 2>/dev/null || echo " Could not read certificate"
|
||||
else
|
||||
echo " fullchain.pem: MISSING"
|
||||
fi
|
||||
if [ -f "$domain_dir/privkey.pem" ]; then
|
||||
echo " privkey.pem: EXISTS"
|
||||
echo " Permissions: $(stat -c%a "$domain_dir/privkey.pem" 2>/dev/null || stat -f%OLp "$domain_dir/privkey.pem" 2>/dev/null)"
|
||||
else
|
||||
echo " privkey.pem: MISSING"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "Let's Encrypt directory NOT FOUND"
|
||||
echo "Checking for self-signed certificates..."
|
||||
if [ -f /etc/ssl/certs/ssl-cert-snakeoil.pem ]; then
|
||||
echo " Self-signed certificate found: /etc/ssl/certs/ssl-cert-snakeoil.pem"
|
||||
else
|
||||
echo " No self-signed certificate found either"
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "--- Certbot Status ---"
|
||||
if command -v certbot >/dev/null 2>&1; then
|
||||
echo "Certbot is installed"
|
||||
certbot --version 2>&1 || true
|
||||
echo ""
|
||||
echo "--- Certbot Certificates List ---"
|
||||
certbot certificates 2>&1 || echo "Could not list certificates"
|
||||
else
|
||||
echo "Certbot is NOT installed"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "--- Checking Nginx SSL Certificate Configuration ---"
|
||||
if [ -f /etc/nginx/sites-available/sslh-proxy ]; then
|
||||
echo "SSL certificate paths in nginx config:"
|
||||
grep -E "ssl_certificate|ssl_certificate_key" /etc/nginx/sites-available/sslh-proxy || echo "No SSL certificate directives found"
|
||||
echo ""
|
||||
echo "Verifying certificate files exist:"
|
||||
cert_path=$(grep "ssl_certificate " /etc/nginx/sites-available/sslh-proxy | awk '{print $2}' | tr -d ';' | head -1)
|
||||
key_path=$(grep "ssl_certificate_key " /etc/nginx/sites-available/sslh-proxy | awk '{print $2}' | tr -d ';' | head -1)
|
||||
if [ -n "$cert_path" ]; then
|
||||
if [ -f "$cert_path" ]; then
|
||||
echo " Certificate file EXISTS: $cert_path"
|
||||
else
|
||||
echo " ERROR: Certificate file MISSING: $cert_path"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$key_path" ]; then
|
||||
if [ -f "$key_path" ]; then
|
||||
echo " Key file EXISTS: $key_path"
|
||||
else
|
||||
echo " ERROR: Key file MISSING: $key_path"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 4. Service Status ==="
|
||||
echo "--- SSLH Service ---"
|
||||
systemctl status sslh --no-pager -l | head -15 || true
|
||||
echo ""
|
||||
if systemctl is-active --quiet sslh; then
|
||||
echo "SSLH is RUNNING"
|
||||
echo "SSLH process:"
|
||||
ps aux | grep sslh | grep -v grep || echo "No sslh process found"
|
||||
echo ""
|
||||
echo "SSLH listening ports:"
|
||||
ss -tlnp | grep sslh || echo "No sslh listening ports found"
|
||||
else
|
||||
echo "SSLH is NOT RUNNING"
|
||||
echo "Recent SSLH logs:"
|
||||
journalctl -u sslh -n 30 --no-pager || true
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "--- Nginx Service ---"
|
||||
systemctl status nginx --no-pager -l | head -15 || true
|
||||
echo ""
|
||||
if systemctl is-active --quiet nginx; then
|
||||
echo "Nginx is RUNNING"
|
||||
echo "Nginx listening ports:"
|
||||
ss -tlnp | grep nginx || echo "No nginx listening ports found"
|
||||
else
|
||||
echo "Nginx is NOT RUNNING"
|
||||
echo "Recent Nginx logs:"
|
||||
journalctl -u nginx -n 30 --no-pager || true
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "--- SSH Service ---"
|
||||
systemctl status sshd --no-pager -l | head -10 || true
|
||||
echo ""
|
||||
|
||||
echo "=== 5. Connectivity Tests ==="
|
||||
echo "--- Testing Nginx on port 8444 (HTTPS) ---"
|
||||
if timeout 3 curl -k -v https://127.0.0.1:8444/ 2>&1 | head -20; then
|
||||
echo "Nginx HTTPS (8444): RESPONDING"
|
||||
else
|
||||
echo "Nginx HTTPS (8444): NOT RESPONDING or ERROR"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "--- Testing Nginx on port 80 (HTTP) ---"
|
||||
if timeout 3 curl -v http://127.0.0.1:80/ 2>&1 | head -20; then
|
||||
echo "Nginx HTTP (80): RESPONDING"
|
||||
else
|
||||
echo "Nginx HTTP (80): NOT RESPONDING or ERROR"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "--- Testing SSLH -> Nginx connection ---"
|
||||
if timeout 2 bash -c '</dev/tcp/127.0.0.1/8444' 2>/dev/null; then
|
||||
echo "SSLH can reach Nginx on 8444: YES"
|
||||
else
|
||||
echo "SSLH can reach Nginx on 8444: NO (connection refused)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "--- Testing SSLH on port 443 ---"
|
||||
if timeout 3 bash -c 'echo | openssl s_client -connect 127.0.0.1:443 -servername localhost 2>&1' | head -30; then
|
||||
echo "SSLH port 443: RESPONDING"
|
||||
else
|
||||
echo "SSLH port 443: NOT RESPONDING or ERROR"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 6. Systemd Override for SSLH ==="
|
||||
if [ -f /etc/systemd/system/sslh.service.d/override.conf ]; then
|
||||
echo "SSLH systemd override EXISTS:"
|
||||
cat /etc/systemd/system/sslh.service.d/override.conf
|
||||
else
|
||||
echo "SSLH systemd override: NOT FOUND"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 7. Cloud-init Logs (Last 50 lines) ==="
|
||||
if [ -f /var/log/cloud-init.log ]; then
|
||||
tail -50 /var/log/cloud-init.log
|
||||
else
|
||||
echo "Cloud-init log not found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 8. All Listening Ports ==="
|
||||
ss -tlnp | grep LISTEN
|
||||
echo ""
|
||||
|
||||
echo "=========================================="
|
||||
echo "Diagnostics Complete"
|
||||
echo "=========================================="
|
||||
414
scripts/fix_deployment.sh
Executable file
414
scripts/fix_deployment.sh
Executable file
@@ -0,0 +1,414 @@
|
||||
#!/bin/bash
|
||||
# Fix script for current deployment issues
|
||||
# Run this on the VPS to fix nginx configs, SSLH, and Let's Encrypt
|
||||
|
||||
set -e
|
||||
|
||||
# Don't exit on errors for some commands - we want to continue fixing
|
||||
set +e
|
||||
|
||||
echo "=========================================="
|
||||
echo "Fixing Deployment Issues"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
echo "=== Step 1: Ensuring Demo Page Exists ==="
|
||||
mkdir -p /var/www/demo
|
||||
chown -R www-data:www-data /var/www/demo 2>/dev/null || chown -R nginx:nginx /var/www/demo 2>/dev/null || true
|
||||
|
||||
if [ ! -f /var/www/demo/index.html ]; then
|
||||
cat > /var/www/demo/index.html <<'HTML'
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Demo App Page</title>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
.container {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 3rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Demo app page</h1>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
echo "Created demo page"
|
||||
else
|
||||
echo "Demo page already exists"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Step 2: Creating Nginx Configuration Files ==="
|
||||
mkdir -p /etc/nginx/sites-available
|
||||
|
||||
# Create sslh-proxy config
|
||||
cat > /tmp/sslh-proxy.conf <<'EOF'
|
||||
# Default server for root domain (HTTPS on port 443 via SSLH)
|
||||
server {
|
||||
listen 127.0.0.1:8444 ssl http2 default_server;
|
||||
server_name _;
|
||||
|
||||
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
|
||||
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
|
||||
root /var/www/demo;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
mv /tmp/sslh-proxy.conf /etc/nginx/sites-available/sslh-proxy
|
||||
chmod 644 /etc/nginx/sites-available/sslh-proxy
|
||||
echo "Created /etc/nginx/sites-available/sslh-proxy"
|
||||
|
||||
# Create acme-challenge config
|
||||
cat > /tmp/acme-challenge.conf <<'EOF'
|
||||
# HTTP server for Let's Encrypt ACME challenge
|
||||
server {
|
||||
listen 0.0.0.0:80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name _;
|
||||
|
||||
# Serve ACME challenge for Let's Encrypt
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/html;
|
||||
default_type text/plain;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# For root domain, serve demo page on HTTP
|
||||
location / {
|
||||
root /var/www/demo;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
mv /tmp/acme-challenge.conf /etc/nginx/sites-available/acme-challenge
|
||||
chmod 644 /etc/nginx/sites-available/acme-challenge
|
||||
echo "Created /etc/nginx/sites-available/acme-challenge"
|
||||
|
||||
echo ""
|
||||
echo "=== Step 3: Stopping Nginx and Removing Default Configs ==="
|
||||
systemctl stop nginx 2>/dev/null || true
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
rm -f /etc/nginx/sites-enabled/default.conf
|
||||
rm -f /etc/nginx/sites-enabled/000-default
|
||||
rm -f /etc/nginx/sites-enabled/000-default.conf
|
||||
rm -f /etc/nginx/conf.d/default.conf 2>/dev/null || true
|
||||
rm -f /usr/share/nginx/html/index.html /var/www/html/index.html 2>/dev/null || true
|
||||
echo "Removed default nginx configs and HTML files"
|
||||
|
||||
echo ""
|
||||
echo "=== Step 4: Enabling Nginx Sites ==="
|
||||
ln -sf /etc/nginx/sites-available/acme-challenge /etc/nginx/sites-enabled/acme-challenge
|
||||
ln -sf /etc/nginx/sites-available/sslh-proxy /etc/nginx/sites-enabled/sslh-proxy
|
||||
echo "Enabled nginx sites"
|
||||
|
||||
echo ""
|
||||
echo "=== Step 5: Testing Nginx Configuration ==="
|
||||
nginx -t || { echo "ERROR: Nginx configuration test failed!"; exit 1; }
|
||||
|
||||
echo ""
|
||||
echo "=== Step 6: Fixing SSLH Configuration ==="
|
||||
# Remove the problematic /etc/default/sslh
|
||||
rm -f /etc/default/sslh
|
||||
echo "Removed /etc/default/sslh"
|
||||
|
||||
# Create systemd override
|
||||
mkdir -p /etc/systemd/system/sslh.service.d
|
||||
cat > /tmp/sslh-override.conf <<'EOF'
|
||||
[Service]
|
||||
EnvironmentFile=
|
||||
ExecStart=
|
||||
ExecStart=/usr/sbin/sslh --foreground -F /etc/sslh.cfg
|
||||
EOF
|
||||
|
||||
mv /tmp/sslh-override.conf /etc/systemd/system/sslh.service.d/override.conf
|
||||
chmod 644 /etc/systemd/system/sslh.service.d/override.conf
|
||||
echo "Created SSLH systemd override"
|
||||
|
||||
# Reload systemd
|
||||
systemctl daemon-reload
|
||||
echo "Reloaded systemd"
|
||||
|
||||
echo ""
|
||||
echo "=== Step 7: Restarting Services ==="
|
||||
systemctl restart nginx
|
||||
sleep 2
|
||||
|
||||
# Verify nginx is listening on 8444
|
||||
for i in 1 2 3 4 5; do
|
||||
if ss -tlnp | grep -q ':8444 '; then
|
||||
echo "Nginx is listening on port 8444"
|
||||
break
|
||||
fi
|
||||
echo "Waiting for nginx to listen on 8444... (attempt $i/5)"
|
||||
sleep 2
|
||||
if [ $i -eq 5 ]; then
|
||||
echo "ERROR: Nginx failed to listen on port 8444!"
|
||||
systemctl status nginx --no-pager || true
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Restart SSLH
|
||||
systemctl stop sslh 2>/dev/null || true
|
||||
pkill -9 sslh sslh-select 2>/dev/null || true
|
||||
ss -tlnp | grep -q ':443 ' && fuser -k 443/tcp 2>/dev/null || true
|
||||
sleep 2
|
||||
systemctl enable sslh
|
||||
systemctl restart sslh
|
||||
sleep 3
|
||||
|
||||
if systemctl is-active --quiet sslh; then
|
||||
echo "SSLH service is running"
|
||||
if ss -tlnp | grep -q ':443 '; then
|
||||
echo "SSLH is listening on port 443"
|
||||
else
|
||||
echo "WARNING: SSLH is running but not listening on port 443"
|
||||
fi
|
||||
else
|
||||
echo "ERROR: SSLH service failed to start!"
|
||||
systemctl status sslh --no-pager || true
|
||||
journalctl -u sslh -n 20 --no-pager || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Step 8: Verifying Services ==="
|
||||
echo "Listening ports:"
|
||||
ss -tlnp | grep -E ':(22|80|443|8444|445) ' || true
|
||||
|
||||
echo ""
|
||||
echo "=== Step 9: Testing Connectivity ==="
|
||||
if timeout 2 bash -c '</dev/tcp/127.0.0.1/8444' 2>/dev/null; then
|
||||
echo "SUCCESS: Nginx is accessible on port 8444"
|
||||
else
|
||||
echo "ERROR: Nginx is not accessible on port 8444"
|
||||
fi
|
||||
|
||||
if ss -tlnp | grep -q ':443 '; then
|
||||
echo "SUCCESS: SSLH is listening on port 443"
|
||||
else
|
||||
echo "ERROR: SSLH is not listening on port 443"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Step 10: Testing HTTP and HTTPS ==="
|
||||
echo "Testing HTTP (port 80):"
|
||||
HTTP_CONTENT=$(timeout 3 curl -s http://127.0.0.1:80/ 2>&1)
|
||||
if echo "$HTTP_CONTENT" | grep -q "Demo app page"; then
|
||||
echo "SUCCESS: HTTP serves demo page"
|
||||
elif echo "$HTTP_CONTENT" | grep -qi "Welcome to nginx"; then
|
||||
echo "ERROR: HTTP still serving default nginx page!"
|
||||
echo "HTTP content preview:"
|
||||
echo "$HTTP_CONTENT" | head -5
|
||||
echo "Checking enabled sites..."
|
||||
ls -la /etc/nginx/sites-enabled/
|
||||
else
|
||||
echo "WARNING: HTTP may not be serving demo page correctly"
|
||||
echo "$HTTP_CONTENT" | head -5
|
||||
fi
|
||||
|
||||
echo "Testing HTTPS (port 8444):"
|
||||
HTTPS_CONTENT=$(timeout 3 curl -k -s https://127.0.0.1:8444/ 2>&1)
|
||||
if echo "$HTTPS_CONTENT" | grep -q "Demo app page"; then
|
||||
echo "SUCCESS: HTTPS serves demo page"
|
||||
elif echo "$HTTPS_CONTENT" | grep -qi "Welcome to nginx"; then
|
||||
echo "ERROR: HTTPS still serving default nginx page!"
|
||||
echo "HTTPS content preview:"
|
||||
echo "$HTTPS_CONTENT" | head -5
|
||||
else
|
||||
echo "WARNING: HTTPS may not be serving demo page correctly"
|
||||
echo "$HTTPS_CONTENT" | head -5
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Step 11: Final Verification ==="
|
||||
echo "Nginx enabled sites:"
|
||||
ls -la /etc/nginx/sites-enabled/ || true
|
||||
|
||||
echo ""
|
||||
echo "Nginx listening ports:"
|
||||
ss -tlnp | grep nginx || true
|
||||
|
||||
echo ""
|
||||
echo "SSLH status:"
|
||||
systemctl is-active sslh && echo "SSLH: RUNNING" || echo "SSLH: NOT RUNNING"
|
||||
|
||||
echo ""
|
||||
echo "=== Step 11: DNS Verification ==="
|
||||
if [ -n "$DOMAIN" ]; then
|
||||
echo "Verifying DNS resolution for $DOMAIN..."
|
||||
if nslookup $DOMAIN >/dev/null 2>&1; then
|
||||
RESOLVED_IP=$(nslookup $DOMAIN | grep -A 1 "Name:" | grep "Address:" | tail -1 | awk '{print $2}' || echo "")
|
||||
if [ -n "$RESOLVED_IP" ]; then
|
||||
echo " ✓ $DOMAIN resolves to $RESOLVED_IP"
|
||||
else
|
||||
echo " ✓ $DOMAIN resolves (IP not extracted)"
|
||||
fi
|
||||
else
|
||||
echo " ✗ $DOMAIN does not resolve"
|
||||
echo " This may indicate DNS records are not properly configured"
|
||||
fi
|
||||
|
||||
# Test common subdomains
|
||||
for subdomain in ssh smb; do
|
||||
FQDN="$subdomain.$DOMAIN"
|
||||
if nslookup $FQDN >/dev/null 2>&1; then
|
||||
RESOLVED_IP=$(nslookup $FQDN | grep -A 1 "Name:" | grep "Address:" | tail -1 | awk '{print $2}' || echo "")
|
||||
if [ -n "$RESOLVED_IP" ]; then
|
||||
echo " ✓ $FQDN resolves to $RESOLVED_IP"
|
||||
else
|
||||
echo " ✓ $FQDN resolves"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "Skipping DNS verification (DOMAIN not set)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Step 12: Let's Encrypt Certificate Generation ==="
|
||||
if [ -n "$LETSENCRYPT_EMAIL" ] && [ -n "$DOMAIN" ]; then
|
||||
echo "Domain: $DOMAIN"
|
||||
echo "Email: $LETSENCRYPT_EMAIL"
|
||||
echo "Checking for existing DNS records to determine subdomains..."
|
||||
|
||||
# Build domain list - start with root domain
|
||||
DOMAINS="$DOMAIN"
|
||||
|
||||
# Check which subdomains have DNS records (indicating they're configured)
|
||||
for subdomain in ssh smb ldap ldaps rdp mysql postgres redis mongo vnc ftp ftps smtp smtps imap imaps pop3 pop3s; do
|
||||
if nslookup $subdomain.$DOMAIN >/dev/null 2>&1; then
|
||||
DOMAINS="$DOMAINS $subdomain.$DOMAIN"
|
||||
echo " Found: $subdomain.$DOMAIN"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Domains to include in certificate: $DOMAINS"
|
||||
|
||||
# Build certbot command with all domains
|
||||
CERTBOT_CMD="certbot certonly --webroot -n --agree-tos -m '$LETSENCRYPT_EMAIL'"
|
||||
for domain in $DOMAINS; do
|
||||
CERTBOT_CMD="$CERTBOT_CMD -d $domain"
|
||||
done
|
||||
CERTBOT_CMD="$CERTBOT_CMD -w /var/www/html --keep-until-expiring"
|
||||
|
||||
echo "Running certbot..."
|
||||
echo "Command: $CERTBOT_CMD"
|
||||
sudo $CERTBOT_CMD 2>&1 | tee /tmp/certbot-output.log
|
||||
CERTBOT_EXIT=$?
|
||||
|
||||
if [ $CERTBOT_EXIT -eq 0 ]; then
|
||||
# Find certificate directory
|
||||
CERT_DIR=$(sudo certbot certificates 2>/dev/null | grep -A 5 'Certificate Name:' | grep 'Certificate Path:' | head -1 | awk '{print $3}' | xargs dirname 2>/dev/null || echo '')
|
||||
if [ -z "$CERT_DIR" ]; then
|
||||
CERT_DIR="/etc/letsencrypt/live/$DOMAIN"
|
||||
fi
|
||||
|
||||
if [ -f "$CERT_DIR/fullchain.pem" ] || [ -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" ]; then
|
||||
CERT_PATH="$CERT_DIR/fullchain.pem"
|
||||
KEY_PATH="$CERT_DIR/privkey.pem"
|
||||
if [ ! -f "$CERT_PATH" ]; then
|
||||
CERT_PATH="/etc/letsencrypt/live/$DOMAIN/fullchain.pem"
|
||||
KEY_PATH="/etc/letsencrypt/live/$DOMAIN/privkey.pem"
|
||||
fi
|
||||
|
||||
echo "Certificate found: $CERT_PATH"
|
||||
echo "Updating nginx to use Let's Encrypt certificate..."
|
||||
|
||||
cat > /tmp/sslh-proxy-letsencrypt.conf <<EOF
|
||||
server {
|
||||
listen 127.0.0.1:8444 ssl http2 default_server;
|
||||
server_name _;
|
||||
ssl_certificate $CERT_PATH;
|
||||
ssl_certificate_key $KEY_PATH;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
root /var/www/demo;
|
||||
index index.html;
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
mv /tmp/sslh-proxy-letsencrypt.conf /etc/nginx/sites-available/sslh-proxy
|
||||
chmod 644 /etc/nginx/sites-available/sslh-proxy
|
||||
chmod 644 "$CERT_PATH" 2>/dev/null || true
|
||||
chmod 640 "$KEY_PATH" 2>/dev/null || true
|
||||
chown root:root "$CERT_PATH" "$KEY_PATH" 2>/dev/null || true
|
||||
nginx -t && systemctl reload nginx && echo "SUCCESS: Nginx updated to use Let's Encrypt certificate" || systemctl restart nginx
|
||||
echo "Certificate Subject Alternative Names:"
|
||||
openssl x509 -in "$CERT_PATH" -noout -text 2>/dev/null | grep -A 1 'Subject Alternative Name' || true
|
||||
else
|
||||
echo "ERROR: Certificate file not found after certbot success"
|
||||
echo "Checking certbot certificates:"
|
||||
sudo certbot certificates 2>&1 | head -20
|
||||
fi
|
||||
else
|
||||
echo "WARNING: Certbot failed (exit code: $CERTBOT_EXIT)"
|
||||
echo "Certbot output (last 20 lines):"
|
||||
cat /tmp/certbot-output.log 2>/dev/null | tail -20
|
||||
echo "Continuing with self-signed certificate..."
|
||||
fi
|
||||
else
|
||||
echo "Skipping Let's Encrypt (DOMAIN or LETSENCRYPT_EMAIL not set)"
|
||||
echo "To enable: Run './sslh-lab fix --letsencrypt-email your@email.com' or set up during initial deployment"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Certificate in use:"
|
||||
grep -E 'ssl_certificate|ssl_certificate_key' /etc/nginx/sites-available/sslh-proxy 2>/dev/null || echo "No SSL directives found"
|
||||
|
||||
echo ""
|
||||
echo "=== Step 13: Final Verification ==="
|
||||
echo "Nginx enabled sites:"
|
||||
ls -la /etc/nginx/sites-enabled/ || true
|
||||
|
||||
echo ""
|
||||
echo "Nginx listening ports:"
|
||||
ss -tlnp | grep nginx || true
|
||||
|
||||
echo ""
|
||||
echo "SSLH status:"
|
||||
systemctl is-active sslh && echo "SSLH: RUNNING" || echo "SSLH: NOT RUNNING"
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Fix Complete"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "If HTTPS still doesn't work externally, check:"
|
||||
echo "1. DNS is pointing to this server"
|
||||
echo "2. Firewall allows port 443"
|
||||
echo "3. SSLH is listening on port 443 (check above)"
|
||||
echo ""
|
||||
210
scripts/verify_deployment.sh
Executable file
210
scripts/verify_deployment.sh
Executable file
@@ -0,0 +1,210 @@
|
||||
#!/bin/bash
|
||||
# Comprehensive deployment verification script
|
||||
# Run this on the VPS after setup to verify all services and configurations
|
||||
|
||||
set -e
|
||||
|
||||
echo "=========================================="
|
||||
echo "SSLH Multiplex Lab - Deployment Verification"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
echo "=== 1. System Information ==="
|
||||
echo "Hostname: $(hostname)"
|
||||
echo "IP Address: $(hostname -I | awk '{print $1}')"
|
||||
echo "Uptime: $(uptime -p)"
|
||||
echo ""
|
||||
|
||||
echo "=== 2. User Accounts ==="
|
||||
echo "demouser exists: $(id demouser >/dev/null 2>&1 && echo 'YES' || echo 'NO')"
|
||||
echo "testuser exists: $(id testuser >/dev/null 2>&1 && echo 'YES' || echo 'NO')"
|
||||
echo ""
|
||||
|
||||
echo "=== 3. SSH Service ==="
|
||||
if systemctl is-active --quiet sshd; then
|
||||
echo "SSH service: RUNNING"
|
||||
systemctl status sshd --no-pager -l | head -5
|
||||
else
|
||||
echo "SSH service: NOT RUNNING"
|
||||
systemctl status sshd --no-pager -l || true
|
||||
fi
|
||||
echo "SSH listening on port 22: $(ss -tlnp | grep ':22 ' && echo 'YES' || echo 'NO')"
|
||||
echo ""
|
||||
|
||||
echo "=== 4. Nginx Service ==="
|
||||
if systemctl is-active --quiet nginx; then
|
||||
echo "Nginx service: RUNNING"
|
||||
systemctl status nginx --no-pager -l | head -5
|
||||
else
|
||||
echo "Nginx service: NOT RUNNING"
|
||||
systemctl status nginx --no-pager -l || true
|
||||
fi
|
||||
echo "Nginx listening on port 8444: $(ss -tlnp | grep ':8444 ' && echo 'YES' || echo 'NO')"
|
||||
echo "Nginx listening on port 80: $(ss -tlnp | grep ':80 ' && echo 'YES' || echo 'NO')"
|
||||
echo ""
|
||||
|
||||
echo "=== 5. Nginx Configuration ==="
|
||||
if [ -f /etc/nginx/sites-available/sslh-proxy ]; then
|
||||
echo "sslh-proxy config: EXISTS"
|
||||
echo "Config file size: $(wc -l < /etc/nginx/sites-available/sslh-proxy) lines"
|
||||
if [ -L /etc/nginx/sites-enabled/sslh-proxy ]; then
|
||||
echo "sslh-proxy config: ENABLED"
|
||||
else
|
||||
echo "sslh-proxy config: NOT ENABLED (symlink missing)"
|
||||
fi
|
||||
else
|
||||
echo "sslh-proxy config: MISSING"
|
||||
fi
|
||||
|
||||
if [ -f /etc/nginx/sites-available/acme-challenge ]; then
|
||||
echo "acme-challenge config: EXISTS"
|
||||
if [ -L /etc/nginx/sites-enabled/acme-challenge ]; then
|
||||
echo "acme-challenge config: ENABLED"
|
||||
else
|
||||
echo "acme-challenge config: NOT ENABLED (symlink missing)"
|
||||
fi
|
||||
else
|
||||
echo "acme-challenge config: MISSING"
|
||||
fi
|
||||
|
||||
echo "Default nginx configs removed:"
|
||||
[ -f /etc/nginx/sites-enabled/default ] && echo " WARNING: default still exists" || echo " OK: default removed"
|
||||
[ -f /etc/nginx/sites-enabled/000-default ] && echo " WARNING: 000-default still exists" || echo " OK: 000-default removed"
|
||||
[ -f /etc/nginx/conf.d/default.conf ] && echo " WARNING: conf.d/default.conf still exists" || echo " OK: conf.d/default.conf removed"
|
||||
echo ""
|
||||
|
||||
echo "=== 6. Nginx Configuration Test ==="
|
||||
if nginx -t 2>&1; then
|
||||
echo "Nginx configuration: VALID"
|
||||
else
|
||||
echo "Nginx configuration: INVALID"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 7. SSLH Service ==="
|
||||
if systemctl is-active --quiet sslh; then
|
||||
echo "SSLH service: RUNNING"
|
||||
systemctl status sslh --no-pager -l | head -10
|
||||
else
|
||||
echo "SSLH service: NOT RUNNING"
|
||||
echo "SSLH status:"
|
||||
systemctl status sslh --no-pager -l || true
|
||||
echo ""
|
||||
echo "Recent SSLH logs:"
|
||||
journalctl -u sslh -n 20 --no-pager || true
|
||||
fi
|
||||
echo "SSLH listening on port 443: $(ss -tlnp | grep ':443 ' && echo 'YES' || echo 'NO')"
|
||||
echo ""
|
||||
|
||||
echo "=== 8. SSLH Configuration ==="
|
||||
if [ -f /etc/sslh.cfg ]; then
|
||||
echo "SSLH config file: EXISTS"
|
||||
echo "Config file size: $(wc -l < /etc/sslh.cfg) lines"
|
||||
echo "Config file contents:"
|
||||
cat /etc/sslh.cfg
|
||||
echo ""
|
||||
else
|
||||
echo "SSLH config file: MISSING"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 9. Let's Encrypt Certificates ==="
|
||||
if [ -d /etc/letsencrypt/live ]; then
|
||||
echo "Let's Encrypt directory: EXISTS"
|
||||
for domain_dir in /etc/letsencrypt/live/*/; do
|
||||
if [ -d "$domain_dir" ]; then
|
||||
domain=$(basename "$domain_dir")
|
||||
echo " Domain: $domain"
|
||||
if [ -f "$domain_dir/fullchain.pem" ]; then
|
||||
echo " fullchain.pem: EXISTS ($(stat -c%s "$domain_dir/fullchain.pem") bytes)"
|
||||
else
|
||||
echo " fullchain.pem: MISSING"
|
||||
fi
|
||||
if [ -f "$domain_dir/privkey.pem" ]; then
|
||||
echo " privkey.pem: EXISTS ($(stat -c%s "$domain_dir/privkey.pem") bytes)"
|
||||
else
|
||||
echo " privkey.pem: MISSING"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "Let's Encrypt directory: NOT FOUND (using self-signed certificates)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 10. Demo Page ==="
|
||||
if [ -d /var/www/demo ]; then
|
||||
echo "Demo directory: EXISTS"
|
||||
if [ -f /var/www/demo/index.html ]; then
|
||||
echo "Demo page: EXISTS"
|
||||
echo "Demo page content (first 5 lines):"
|
||||
head -5 /var/www/demo/index.html
|
||||
else
|
||||
echo "Demo page: MISSING"
|
||||
fi
|
||||
else
|
||||
echo "Demo directory: MISSING"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 11. Local Service Tests ==="
|
||||
echo "Testing HTTP (port 80):"
|
||||
if curl -s http://127.0.0.1:80/ 2>&1 | head -1; then
|
||||
echo " HTTP: RESPONDING"
|
||||
else
|
||||
echo " HTTP: NOT RESPONDING"
|
||||
fi
|
||||
|
||||
echo "Testing HTTPS (port 8444):"
|
||||
if curl -k -s https://127.0.0.1:8444/ 2>&1 | head -1; then
|
||||
echo " HTTPS: RESPONDING"
|
||||
else
|
||||
echo " HTTPS: NOT RESPONDING"
|
||||
fi
|
||||
|
||||
echo "Testing SSLH -> Nginx (port 443 -> 8444):"
|
||||
if timeout 2 bash -c '</dev/tcp/127.0.0.1/8444' 2>/dev/null; then
|
||||
echo " SSLH can reach Nginx: YES"
|
||||
else
|
||||
echo " SSLH can reach Nginx: NO (connection refused)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 12. SMB Service ==="
|
||||
if systemctl is-active --quiet smbd 2>/dev/null || systemctl is-active --quiet samba 2>/dev/null; then
|
||||
echo "SMB service: RUNNING"
|
||||
else
|
||||
echo "SMB service: NOT RUNNING"
|
||||
fi
|
||||
echo "SMB listening on port 445: $(ss -tlnp | grep ':445 ' && echo 'YES' || echo 'NO')"
|
||||
echo ""
|
||||
|
||||
echo "=== 13. Firewall (UFW) ==="
|
||||
if command -v ufw >/dev/null 2>&1; then
|
||||
echo "UFW status:"
|
||||
ufw status | head -10
|
||||
else
|
||||
echo "UFW: NOT INSTALLED"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 14. Cloud-init Status ==="
|
||||
if [ -f /var/lib/cloud/instance/boot-finished ]; then
|
||||
echo "Cloud-init: COMPLETED"
|
||||
if [ -f /var/log/cloud-init.log ]; then
|
||||
echo "Last 10 lines of cloud-init.log:"
|
||||
tail -10 /var/log/cloud-init.log
|
||||
fi
|
||||
else
|
||||
echo "Cloud-init: STILL RUNNING"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 15. Listening Ports Summary ==="
|
||||
echo "All listening TCP ports:"
|
||||
ss -tlnp | grep LISTEN | awk '{print $4}' | sort -u
|
||||
echo ""
|
||||
|
||||
echo "=========================================="
|
||||
echo "Verification Complete"
|
||||
echo "=========================================="
|
||||
Reference in New Issue
Block a user