281 lines
9.7 KiB
Bash
Executable File
281 lines
9.7 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Fix nginx to serve custom frontend from /var/www/html/
|
|
# Run this in VMID 5000
|
|
|
|
set -euo pipefail
|
|
|
|
CONFIG_FILE="/etc/nginx/sites-available/blockscout"
|
|
|
|
echo "=========================================="
|
|
echo "Updating Nginx to Serve Custom Frontend"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
# Step 1: Backup current config
|
|
echo "=== Step 1: Backing up nginx config ==="
|
|
cp "$CONFIG_FILE" "${CONFIG_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
|
|
echo "✅ Backup created"
|
|
echo ""
|
|
|
|
# Step 2: Create new config that serves custom frontend
|
|
echo "=== Step 2: Creating new nginx configuration ==="
|
|
cat > "$CONFIG_FILE" << 'NGINX_EOF'
|
|
# HTTP server
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name explorer.d-bis.org 192.168.11.140;
|
|
|
|
location /.well-known/acme-challenge/ {
|
|
root /var/www/html;
|
|
try_files $uri =404;
|
|
}
|
|
|
|
# API endpoint - MUST come before the redirect location
|
|
location /api/ {
|
|
proxy_pass http://127.0.0.1:4000;
|
|
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;
|
|
proxy_read_timeout 300s;
|
|
proxy_connect_timeout 75s;
|
|
add_header Access-Control-Allow-Origin *;
|
|
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
|
add_header Access-Control-Allow-Headers "Content-Type";
|
|
}
|
|
|
|
location /health {
|
|
access_log off;
|
|
proxy_pass http://127.0.0.1:4000/api/v2/status;
|
|
proxy_set_header Host $host;
|
|
add_header Content-Type application/json;
|
|
}
|
|
|
|
# Serve custom frontend for root path (no-cache so fixes show after refresh)
|
|
# CSP with unsafe-eval required by ethers.js v5 (NPM proxies to port 80)
|
|
location = / {
|
|
root /var/www/html;
|
|
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://unpkg.com https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com; img-src 'self' data: https:; font-src 'self' https://cdnjs.cloudflare.com; connect-src 'self' https://explorer.d-bis.org wss://explorer.d-bis.org https://rpc-http-pub.d-bis.org wss://rpc-ws-pub.d-bis.org http://192.168.11.221:8545 ws://192.168.11.221:8546;" always;
|
|
try_files /index.html =404;
|
|
}
|
|
|
|
location = /favicon.ico {
|
|
root /var/www/html;
|
|
try_files /favicon.ico =404;
|
|
add_header Cache-Control "public, max-age=86400";
|
|
}
|
|
location = /apple-touch-icon.png {
|
|
root /var/www/html;
|
|
try_files /apple-touch-icon.png =404;
|
|
add_header Cache-Control "public, max-age=86400";
|
|
}
|
|
|
|
# Serve static assets
|
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
root /var/www/html;
|
|
expires 1y;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
|
|
# All other requests redirect to HTTPS
|
|
location / {
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
}
|
|
|
|
# HTTPS server - Blockscout Explorer
|
|
server {
|
|
listen 443 ssl http2;
|
|
listen [::]:443 ssl http2;
|
|
server_name explorer.d-bis.org 192.168.11.140;
|
|
|
|
# SSL configuration
|
|
ssl_certificate /etc/letsencrypt/live/explorer.d-bis.org/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/explorer.d-bis.org/privkey.pem;
|
|
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
|
|
ssl_prefer_server_ciphers off;
|
|
ssl_session_cache shared:SSL:10m;
|
|
ssl_session_timeout 10m;
|
|
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header X-XSS-Protection "1; mode=block" always;
|
|
|
|
access_log /var/log/nginx/blockscout-access.log;
|
|
error_log /var/log/nginx/blockscout-error.log;
|
|
|
|
# Serve custom frontend for root path (no-cache so fixes show after refresh)
|
|
location = / {
|
|
root /var/www/html;
|
|
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
|
try_files /index.html =404;
|
|
}
|
|
|
|
# Chain 138 MetaMask Snap companion site (SPA at /snap/)
|
|
# /snap (no trailing slash) -> internal redirect so client gets 200 with content
|
|
location = /snap {
|
|
rewrite ^ /snap/ last;
|
|
}
|
|
location /snap/ {
|
|
alias /var/www/html/snap/;
|
|
try_files $uri $uri/ /snap/index.html;
|
|
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
|
}
|
|
|
|
# Icons (exact match to avoid 404s)
|
|
location = /favicon.ico {
|
|
root /var/www/html;
|
|
try_files /favicon.ico =404;
|
|
add_header Cache-Control "public, max-age=86400";
|
|
}
|
|
location = /apple-touch-icon.png {
|
|
root /var/www/html;
|
|
try_files /apple-touch-icon.png =404;
|
|
add_header Cache-Control "public, max-age=86400";
|
|
}
|
|
|
|
# Serve static assets
|
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
root /var/www/html;
|
|
expires 1y;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
|
|
# API endpoint - proxy to Blockscout
|
|
location /api/ {
|
|
proxy_pass http://127.0.0.1:4000;
|
|
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;
|
|
proxy_read_timeout 300s;
|
|
proxy_connect_timeout 75s;
|
|
add_header Access-Control-Allow-Origin *;
|
|
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
|
add_header Access-Control-Allow-Headers "Content-Type";
|
|
}
|
|
|
|
location /health {
|
|
access_log off;
|
|
proxy_pass http://127.0.0.1:4000/api/v2/status;
|
|
proxy_set_header Host $host;
|
|
add_header Content-Type application/json;
|
|
}
|
|
|
|
# Proxy Blockscout UI paths (if needed)
|
|
location /blockscout/ {
|
|
proxy_pass http://127.0.0.1:4000/;
|
|
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;
|
|
proxy_read_timeout 300s;
|
|
proxy_connect_timeout 75s;
|
|
}
|
|
|
|
# All other paths serve custom frontend (SPA fallback via try_files)
|
|
location / {
|
|
root /var/www/html;
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
}
|
|
|
|
map $http_upgrade $connection_upgrade {
|
|
default upgrade;
|
|
'' close;
|
|
}
|
|
NGINX_EOF
|
|
|
|
echo "✅ Configuration updated"
|
|
echo ""
|
|
|
|
# Step 3: Handle SSL certs if missing
|
|
echo "=== Step 3: Checking SSL certificates ==="
|
|
if [ ! -f /etc/letsencrypt/live/explorer.d-bis.org/fullchain.pem ]; then
|
|
echo "⚠️ Let's Encrypt certificate not found, creating self-signed..."
|
|
mkdir -p /etc/nginx/ssl
|
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
|
-keyout /etc/nginx/ssl/blockscout.key \
|
|
-out /etc/nginx/ssl/blockscout.crt \
|
|
-subj "/CN=explorer.d-bis.org" 2>/dev/null
|
|
sed -i 's|ssl_certificate /etc/letsencrypt/live/explorer.d-bis.org/fullchain.pem;|ssl_certificate /etc/nginx/ssl/blockscout.crt;|' "$CONFIG_FILE"
|
|
sed -i 's|ssl_certificate_key /etc/letsencrypt/live/explorer.d-bis.org/privkey.pem;|ssl_certificate_key /etc/nginx/ssl/blockscout.key;|' "$CONFIG_FILE"
|
|
echo "✅ Self-signed certificate created"
|
|
else
|
|
echo "✅ Let's Encrypt certificate found"
|
|
fi
|
|
echo ""
|
|
|
|
# Step 4: Ensure /var/www/html exists and has correct permissions
|
|
echo "=== Step 4: Preparing frontend directory ==="
|
|
mkdir -p /var/www/html
|
|
chown -R www-data:www-data /var/www/html 2>/dev/null || true
|
|
echo "✅ Directory prepared"
|
|
echo ""
|
|
|
|
# Step 5: Test and restart nginx
|
|
echo "=== Step 5: Testing and restarting nginx ==="
|
|
if nginx -t; then
|
|
echo "✅ Configuration valid"
|
|
systemctl restart nginx
|
|
echo "✅ Nginx restarted"
|
|
else
|
|
echo "❌ Configuration has errors"
|
|
echo "Restoring backup..."
|
|
cp "${CONFIG_FILE}.backup."* "$CONFIG_FILE" 2>/dev/null || true
|
|
exit 1
|
|
fi
|
|
echo ""
|
|
|
|
# Step 6: Verify
|
|
echo "=== Step 6: Verifying deployment ==="
|
|
sleep 2
|
|
|
|
# Check if custom frontend exists
|
|
if [ -f /var/www/html/index.html ]; then
|
|
echo "✅ Custom frontend file exists"
|
|
|
|
if grep -q "SolaceScanScout" /var/www/html/index.html; then
|
|
echo "✅ Custom frontend content verified"
|
|
else
|
|
echo "⚠️ Frontend file exists but may not be the custom one"
|
|
echo " Deploy the custom frontend using:"
|
|
echo " ./scripts/deploy-frontend-to-vmid5000.sh"
|
|
fi
|
|
else
|
|
echo "⚠️ Custom frontend not found at /var/www/html/index.html"
|
|
echo " Deploy the custom frontend using:"
|
|
echo " ./scripts/deploy-frontend-to-vmid5000.sh"
|
|
fi
|
|
|
|
# Test HTTP endpoint (non-fatal: do not exit on curl/grep failure)
|
|
echo ""
|
|
echo "Testing HTTP endpoint:"
|
|
HTTP_RESPONSE=$(curl -s --max-time 5 http://localhost/ 2>/dev/null | head -5) || true
|
|
if echo "$HTTP_RESPONSE" | grep -q "SolaceScanScout\|<!DOCTYPE html"; then
|
|
echo "✅ Custom frontend is accessible via HTTP"
|
|
else
|
|
echo "⚠️ Frontend may not be accessible (check if file exists)"
|
|
echo "Response preview: $HTTP_RESPONSE"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=========================================="
|
|
echo "Nginx Configuration Updated!"
|
|
echo "=========================================="
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo "1. Deploy custom frontend: ./scripts/deploy-frontend-to-vmid5000.sh"
|
|
echo "2. Or manually copy: cp explorer-monorepo/frontend/public/index.html /var/www/html/index.html"
|
|
echo ""
|
|
|