1083 lines
25 KiB
Markdown
1083 lines
25 KiB
Markdown
|
|
# Complete Deployment Guide - LXC + Nginx + Cloudflare
|
||
|
|
|
||
|
|
This guide provides step-by-step instructions for deploying the ChainID 138 Explorer Platform using LXC containers, Nginx reverse proxy, Cloudflare DNS, SSL, and Cloudflare Tunnel.
|
||
|
|
|
||
|
|
## Table of Contents
|
||
|
|
|
||
|
|
1. [Prerequisites](#prerequisites)
|
||
|
|
2. [LXC Container Setup](#lxc-container-setup)
|
||
|
|
3. [Application Installation](#application-installation)
|
||
|
|
4. [Database Setup](#database-setup)
|
||
|
|
5. [Nginx Configuration](#nginx-configuration)
|
||
|
|
6. [Cloudflare DNS Configuration](#cloudflare-dns-configuration)
|
||
|
|
7. [SSL Certificate Setup](#ssl-certificate-setup)
|
||
|
|
8. [Cloudflare Tunnel Setup](#cloudflare-tunnel-setup)
|
||
|
|
9. [Security Hardening](#security-hardening)
|
||
|
|
10. [Monitoring & Maintenance](#monitoring--maintenance)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Prerequisites
|
||
|
|
|
||
|
|
### Required Tools
|
||
|
|
- ✅ Proxmox VE with LXC support
|
||
|
|
- ✅ Cloudflare account with domain
|
||
|
|
- ✅ SSH access to Proxmox host
|
||
|
|
- ✅ Cloudflare API token (with DNS edit permissions)
|
||
|
|
|
||
|
|
### Domain Requirements
|
||
|
|
- ✅ Domain registered with Cloudflare
|
||
|
|
- ✅ DNS managed by Cloudflare
|
||
|
|
|
||
|
|
### System Requirements
|
||
|
|
- **LXC Container**: Ubuntu 22.04 LTS (recommended)
|
||
|
|
- **Resources**:
|
||
|
|
- CPU: 4+ cores
|
||
|
|
- RAM: 8GB minimum (16GB recommended)
|
||
|
|
- Storage: 100GB+ SSD
|
||
|
|
- Network: Public IP or Cloudflare Tunnel
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Task List Overview
|
||
|
|
|
||
|
|
### Phase 1: LXC Container Setup
|
||
|
|
- [ ] Create LXC container
|
||
|
|
- [ ] Configure container resources
|
||
|
|
- [ ] Set up networking
|
||
|
|
- [ ] Install base packages
|
||
|
|
- [ ] Configure firewall
|
||
|
|
|
||
|
|
### Phase 2: Application Installation
|
||
|
|
- [ ] Install Go 1.21+
|
||
|
|
- [ ] Install Node.js 20+
|
||
|
|
- [ ] Install Docker & Docker Compose
|
||
|
|
- [ ] Clone repository
|
||
|
|
- [ ] Install dependencies
|
||
|
|
- [ ] Build applications
|
||
|
|
|
||
|
|
### Phase 3: Database Setup
|
||
|
|
- [ ] Install PostgreSQL with TimescaleDB
|
||
|
|
- [ ] Create database and user
|
||
|
|
- [ ] Run migrations
|
||
|
|
- [ ] Configure backups
|
||
|
|
|
||
|
|
### Phase 4: Infrastructure Services
|
||
|
|
- [ ] Deploy Elasticsearch/OpenSearch
|
||
|
|
- [ ] Deploy Redis
|
||
|
|
- [ ] Configure message queue (optional)
|
||
|
|
|
||
|
|
### Phase 5: Application Services
|
||
|
|
- [ ] Configure environment variables
|
||
|
|
- [ ] Set up systemd services
|
||
|
|
- [ ] Start indexer service
|
||
|
|
- [ ] Start API service
|
||
|
|
- [ ] Start frontend service
|
||
|
|
|
||
|
|
### Phase 6: Nginx Reverse Proxy
|
||
|
|
- [ ] Install Nginx
|
||
|
|
- [ ] Configure SSL certificates
|
||
|
|
- [ ] Set up reverse proxy config
|
||
|
|
- [ ] Configure rate limiting
|
||
|
|
- [ ] Set up caching
|
||
|
|
- [ ] Enable security headers
|
||
|
|
|
||
|
|
### Phase 7: Cloudflare Configuration
|
||
|
|
- [ ] Set up Cloudflare DNS records
|
||
|
|
- [ ] Configure Cloudflare Tunnel
|
||
|
|
- [ ] Set up SSL/TLS mode
|
||
|
|
- [ ] Configure WAF rules
|
||
|
|
- [ ] Set up DDoS protection
|
||
|
|
- [ ] Configure caching rules
|
||
|
|
|
||
|
|
### Phase 8: Security Hardening
|
||
|
|
- [ ] Configure firewall rules
|
||
|
|
- [ ] Set up fail2ban
|
||
|
|
- [ ] Configure automatic updates
|
||
|
|
- [ ] Set up log rotation
|
||
|
|
- [ ] Configure backup strategy
|
||
|
|
|
||
|
|
### Phase 9: Monitoring
|
||
|
|
- [ ] Set up health checks
|
||
|
|
- [ ] Configure log aggregation
|
||
|
|
- [ ] Set up alerting
|
||
|
|
- [ ] Configure uptime monitoring
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Phase 1: LXC Container Setup
|
||
|
|
|
||
|
|
### Task 1.1: Create LXC Container
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# On Proxmox host
|
||
|
|
pct create 100 \
|
||
|
|
local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst \
|
||
|
|
--hostname explorer-prod \
|
||
|
|
--memory 16384 \
|
||
|
|
--cores 4 \
|
||
|
|
--swap 4096 \
|
||
|
|
--storage local-lvm \
|
||
|
|
--rootfs local-lvm:100 \
|
||
|
|
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
|
||
|
|
--unprivileged 0 \
|
||
|
|
--features nesting=1
|
||
|
|
```
|
||
|
|
|
||
|
|
**Parameters:**
|
||
|
|
- Container ID: 100 (change as needed)
|
||
|
|
- Template: Ubuntu 22.04
|
||
|
|
- Memory: 16GB
|
||
|
|
- CPU Cores: 4
|
||
|
|
- Storage: 100GB on local-lvm
|
||
|
|
- Network: DHCP on vmbr0
|
||
|
|
- Features: Enable nesting for Docker
|
||
|
|
|
||
|
|
### Task 1.2: Start Container
|
||
|
|
|
||
|
|
```bash
|
||
|
|
pct start 100
|
||
|
|
pct enter 100
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 1.3: Initial Container Configuration
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Update system
|
||
|
|
apt update && apt upgrade -y
|
||
|
|
|
||
|
|
# Install essential packages
|
||
|
|
apt install -y curl wget git vim net-tools ufw fail2ban \
|
||
|
|
unattended-upgrades apt-transport-https ca-certificates \
|
||
|
|
gnupg lsb-release
|
||
|
|
|
||
|
|
# Set timezone
|
||
|
|
timedatectl set-timezone UTC
|
||
|
|
|
||
|
|
# Configure hostname
|
||
|
|
hostnamectl set-hostname explorer-prod
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 1.4: Create Deployment User
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Create deployment user
|
||
|
|
adduser explorer
|
||
|
|
usermod -aG sudo explorer
|
||
|
|
usermod -aG docker explorer
|
||
|
|
|
||
|
|
# Configure SSH (disable root login)
|
||
|
|
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
|
||
|
|
systemctl restart sshd
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Phase 2: Application Installation
|
||
|
|
|
||
|
|
### Task 2.1: Install Go 1.21+
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Download Go
|
||
|
|
cd /tmp
|
||
|
|
wget https://go.dev/dl/go1.21.6.linux-amd64.tar.gz
|
||
|
|
|
||
|
|
# Install Go
|
||
|
|
rm -rf /usr/local/go
|
||
|
|
tar -C /usr/local -xzf go1.21.6.linux-amd64.tar.gz
|
||
|
|
|
||
|
|
# Add to PATH
|
||
|
|
echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile
|
||
|
|
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
|
||
|
|
source ~/.bashrc
|
||
|
|
|
||
|
|
# Verify
|
||
|
|
go version
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 2.2: Install Node.js 20+
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Install Node.js via NodeSource
|
||
|
|
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
||
|
|
apt install -y nodejs
|
||
|
|
|
||
|
|
# Verify
|
||
|
|
node --version
|
||
|
|
npm --version
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 2.3: Install Docker & Docker Compose
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Add Docker GPG key
|
||
|
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||
|
|
|
||
|
|
# Add Docker repository
|
||
|
|
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||
|
|
|
||
|
|
# Install Docker
|
||
|
|
apt update
|
||
|
|
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||
|
|
|
||
|
|
# Start Docker
|
||
|
|
systemctl enable docker
|
||
|
|
systemctl start docker
|
||
|
|
|
||
|
|
# Verify
|
||
|
|
docker --version
|
||
|
|
docker compose version
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 2.4: Clone Repository
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Switch to deployment user
|
||
|
|
su - explorer
|
||
|
|
|
||
|
|
# Clone repository
|
||
|
|
cd /home/explorer
|
||
|
|
git clone <repository-url> explorer-monorepo
|
||
|
|
cd explorer-monorepo
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 2.5: Install Dependencies
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Backend dependencies
|
||
|
|
cd backend
|
||
|
|
go mod download
|
||
|
|
|
||
|
|
# Frontend dependencies
|
||
|
|
cd ../frontend
|
||
|
|
npm ci --production
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 2.6: Build Applications
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Build backend
|
||
|
|
cd /home/explorer/explorer-monorepo/backend
|
||
|
|
go build -o /usr/local/bin/explorer-indexer ./indexer/main.go
|
||
|
|
go build -o /usr/local/bin/explorer-api ./api/rest/main.go
|
||
|
|
go build -o /usr/local/bin/explorer-gateway ./api/gateway/main.go
|
||
|
|
go build -o /usr/local/bin/explorer-search ./api/search/main.go
|
||
|
|
|
||
|
|
# Build frontend
|
||
|
|
cd /home/explorer/explorer-monorepo/frontend
|
||
|
|
npm run build
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Phase 3: Database Setup
|
||
|
|
|
||
|
|
### Task 3.1: Install PostgreSQL with TimescaleDB
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Add PostgreSQL repository
|
||
|
|
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||
|
|
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
|
||
|
|
apt update
|
||
|
|
|
||
|
|
# Install PostgreSQL 16
|
||
|
|
apt install -y postgresql-16 postgresql-contrib-16
|
||
|
|
|
||
|
|
# Add TimescaleDB repository
|
||
|
|
echo "deb https://packagecloud.io/timescale/timescaledb/ubuntu/ $(lsb_release -c -s) main" > /etc/apt/sources.list.d/timescaledb.list
|
||
|
|
wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | apt-key add -
|
||
|
|
apt update
|
||
|
|
|
||
|
|
# Install TimescaleDB
|
||
|
|
apt install -y timescaledb-2-postgresql-16
|
||
|
|
|
||
|
|
# Tune PostgreSQL for TimescaleDB
|
||
|
|
timescaledb-tune --quiet --yes
|
||
|
|
|
||
|
|
# Restart PostgreSQL
|
||
|
|
systemctl restart postgresql
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 3.2: Create Database and User
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Switch to postgres user
|
||
|
|
su - postgres
|
||
|
|
|
||
|
|
# Create database and user
|
||
|
|
psql << EOF
|
||
|
|
CREATE USER explorer WITH PASSWORD 'CHANGE_THIS_PASSWORD';
|
||
|
|
CREATE DATABASE explorer OWNER explorer;
|
||
|
|
\c explorer
|
||
|
|
CREATE EXTENSION IF NOT EXISTS timescaledb;
|
||
|
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||
|
|
GRANT ALL PRIVILEGES ON DATABASE explorer TO explorer;
|
||
|
|
EOF
|
||
|
|
|
||
|
|
exit
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 3.3: Run Migrations
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/explorer/explorer-monorepo/backend
|
||
|
|
go run database/migrations/migrate.go
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 3.4: Configure PostgreSQL
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Edit postgresql.conf
|
||
|
|
vim /etc/postgresql/16/main/postgresql.conf
|
||
|
|
|
||
|
|
# Recommended settings:
|
||
|
|
# max_connections = 100
|
||
|
|
# shared_buffers = 4GB
|
||
|
|
# effective_cache_size = 12GB
|
||
|
|
# maintenance_work_mem = 1GB
|
||
|
|
# checkpoint_completion_target = 0.9
|
||
|
|
# wal_buffers = 16MB
|
||
|
|
# default_statistics_target = 100
|
||
|
|
# random_page_cost = 1.1
|
||
|
|
# effective_io_concurrency = 200
|
||
|
|
# work_mem = 20MB
|
||
|
|
# min_wal_size = 1GB
|
||
|
|
# max_wal_size = 4GB
|
||
|
|
|
||
|
|
# Edit pg_hba.conf for local connections
|
||
|
|
vim /etc/postgresql/16/main/pg_hba.conf
|
||
|
|
|
||
|
|
# Restart PostgreSQL
|
||
|
|
systemctl restart postgresql
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Phase 4: Infrastructure Services
|
||
|
|
|
||
|
|
### Task 4.1: Deploy Elasticsearch/OpenSearch
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Create docker-compose for infrastructure
|
||
|
|
cd /home/explorer/explorer-monorepo/deployment
|
||
|
|
docker compose -f docker-compose.yml up -d elasticsearch redis
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 4.2: Verify Services
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Check Elasticsearch
|
||
|
|
curl http://localhost:9200
|
||
|
|
|
||
|
|
# Check Redis
|
||
|
|
redis-cli ping
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Phase 5: Application Services
|
||
|
|
|
||
|
|
### Task 5.1: Create Environment Configuration
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Create production .env file
|
||
|
|
cd /home/explorer/explorer-monorepo
|
||
|
|
cp .env.example .env
|
||
|
|
vim .env
|
||
|
|
```
|
||
|
|
|
||
|
|
**Required Environment Variables:**
|
||
|
|
```env
|
||
|
|
# Database
|
||
|
|
DB_HOST=localhost
|
||
|
|
DB_PORT=5432
|
||
|
|
DB_USER=explorer
|
||
|
|
DB_PASSWORD=<SECURE_PASSWORD>
|
||
|
|
DB_NAME=explorer
|
||
|
|
DB_MAX_CONNECTIONS=50
|
||
|
|
|
||
|
|
# RPC
|
||
|
|
# Public RPC Endpoints (ChainID 138) - Internal IP Addresses
|
||
|
|
# Using internal IP for direct connection (no proxy overhead)
|
||
|
|
RPC_URL=http://192.168.11.221:8545
|
||
|
|
WS_URL=ws://192.168.11.221:8546
|
||
|
|
CHAIN_ID=138
|
||
|
|
# Alternative: Private RPC endpoints available at http://192.168.11.211:8545 (internal) or https://rpc-http-prv.d-bis.org (public)
|
||
|
|
|
||
|
|
# Search
|
||
|
|
SEARCH_URL=http://localhost:9200
|
||
|
|
SEARCH_INDEX_PREFIX=explorer-prod
|
||
|
|
|
||
|
|
# API
|
||
|
|
PORT=8080
|
||
|
|
API_GATEWAY_PORT=8081
|
||
|
|
CHAIN_ID=138
|
||
|
|
|
||
|
|
# Frontend
|
||
|
|
NEXT_PUBLIC_API_URL=https://explorer.d-bis.org/api
|
||
|
|
NEXT_PUBLIC_CHAIN_ID=138
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 5.2: Create Systemd Service Files
|
||
|
|
|
||
|
|
#### Indexer Service
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cat > /etc/systemd/system/explorer-indexer.service << 'EOF'
|
||
|
|
[Unit]
|
||
|
|
Description=Explorer Indexer Service
|
||
|
|
After=network.target postgresql.service
|
||
|
|
Requires=postgresql.service
|
||
|
|
|
||
|
|
[Service]
|
||
|
|
Type=simple
|
||
|
|
User=explorer
|
||
|
|
Group=explorer
|
||
|
|
WorkingDirectory=/home/explorer/explorer-monorepo/backend
|
||
|
|
EnvironmentFile=/home/explorer/explorer-monorepo/.env
|
||
|
|
ExecStart=/usr/local/bin/explorer-indexer
|
||
|
|
Restart=always
|
||
|
|
RestartSec=10
|
||
|
|
StandardOutput=journal
|
||
|
|
StandardError=journal
|
||
|
|
SyslogIdentifier=explorer-indexer
|
||
|
|
|
||
|
|
[Install]
|
||
|
|
WantedBy=multi-user.target
|
||
|
|
EOF
|
||
|
|
```
|
||
|
|
|
||
|
|
#### API Service
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cat > /etc/systemd/system/explorer-api.service << 'EOF'
|
||
|
|
[Unit]
|
||
|
|
Description=Explorer API Service
|
||
|
|
After=network.target postgresql.service
|
||
|
|
Requires=postgresql.service
|
||
|
|
|
||
|
|
[Service]
|
||
|
|
Type=simple
|
||
|
|
User=explorer
|
||
|
|
Group=explorer
|
||
|
|
WorkingDirectory=/home/explorer/explorer-monorepo/backend
|
||
|
|
EnvironmentFile=/home/explorer/explorer-monorepo/.env
|
||
|
|
ExecStart=/usr/local/bin/explorer-api
|
||
|
|
Restart=always
|
||
|
|
RestartSec=10
|
||
|
|
StandardOutput=journal
|
||
|
|
StandardError=journal
|
||
|
|
SyslogIdentifier=explorer-api
|
||
|
|
|
||
|
|
[Install]
|
||
|
|
WantedBy=multi-user.target
|
||
|
|
EOF
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Frontend Service
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cat > /etc/systemd/system/explorer-frontend.service << 'EOF'
|
||
|
|
[Unit]
|
||
|
|
Description=Explorer Frontend Service
|
||
|
|
After=network.target explorer-api.service
|
||
|
|
Requires=explorer-api.service
|
||
|
|
|
||
|
|
[Service]
|
||
|
|
Type=simple
|
||
|
|
User=explorer
|
||
|
|
Group=explorer
|
||
|
|
WorkingDirectory=/home/explorer/explorer-monorepo/frontend
|
||
|
|
EnvironmentFile=/home/explorer/explorer-monorepo/.env
|
||
|
|
ExecStart=/usr/bin/npm start
|
||
|
|
Restart=always
|
||
|
|
RestartSec=10
|
||
|
|
StandardOutput=journal
|
||
|
|
StandardError=journal
|
||
|
|
SyslogIdentifier=explorer-frontend
|
||
|
|
|
||
|
|
[Install]
|
||
|
|
WantedBy=multi-user.target
|
||
|
|
EOF
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 5.3: Enable and Start Services
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Reload systemd
|
||
|
|
systemctl daemon-reload
|
||
|
|
|
||
|
|
# Enable services
|
||
|
|
systemctl enable explorer-indexer
|
||
|
|
systemctl enable explorer-api
|
||
|
|
systemctl enable explorer-frontend
|
||
|
|
|
||
|
|
# Start services
|
||
|
|
systemctl start explorer-indexer
|
||
|
|
systemctl start explorer-api
|
||
|
|
systemctl start explorer-frontend
|
||
|
|
|
||
|
|
# Check status
|
||
|
|
systemctl status explorer-indexer
|
||
|
|
systemctl status explorer-api
|
||
|
|
systemctl status explorer-frontend
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Phase 6: Nginx Reverse Proxy
|
||
|
|
|
||
|
|
### Task 6.1: Install Nginx
|
||
|
|
|
||
|
|
```bash
|
||
|
|
apt install -y nginx
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 6.2: Install Certbot for SSL
|
||
|
|
|
||
|
|
```bash
|
||
|
|
apt install -y certbot python3-certbot-nginx
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 6.3: Configure Nginx
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cat > /etc/nginx/sites-available/explorer << 'EOF'
|
||
|
|
# Rate limiting zones
|
||
|
|
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
||
|
|
limit_req_zone $binary_remote_addr zone=general_limit:10m rate=50r/s;
|
||
|
|
|
||
|
|
# Upstream servers
|
||
|
|
upstream explorer_api {
|
||
|
|
server 127.0.0.1:8080;
|
||
|
|
keepalive 32;
|
||
|
|
}
|
||
|
|
|
||
|
|
upstream explorer_frontend {
|
||
|
|
server 127.0.0.1:3000;
|
||
|
|
keepalive 32;
|
||
|
|
}
|
||
|
|
|
||
|
|
# Redirect HTTP to HTTPS
|
||
|
|
server {
|
||
|
|
listen 80;
|
||
|
|
listen [::]:80;
|
||
|
|
server_name explorer.d-bis.org www.explorer.d-bis.org;
|
||
|
|
|
||
|
|
location /.well-known/acme-challenge/ {
|
||
|
|
root /var/www/html;
|
||
|
|
}
|
||
|
|
|
||
|
|
location / {
|
||
|
|
return 301 https://$server_name$request_uri;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Main HTTPS server
|
||
|
|
server {
|
||
|
|
listen 443 ssl http2;
|
||
|
|
listen [::]:443 ssl http2;
|
||
|
|
server_name explorer.d-bis.org www.explorer.d-bis.org;
|
||
|
|
|
||
|
|
# SSL Configuration (Cloudflare will handle SSL)
|
||
|
|
# Certificates managed by Cloudflare Tunnel
|
||
|
|
|
||
|
|
# Security headers
|
||
|
|
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;
|
||
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||
|
|
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';" always;
|
||
|
|
|
||
|
|
# Logging
|
||
|
|
access_log /var/log/nginx/explorer-access.log;
|
||
|
|
error_log /var/log/nginx/explorer-error.log;
|
||
|
|
|
||
|
|
# Gzip compression
|
||
|
|
gzip on;
|
||
|
|
gzip_vary on;
|
||
|
|
gzip_min_length 1024;
|
||
|
|
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript;
|
||
|
|
|
||
|
|
# Frontend
|
||
|
|
location / {
|
||
|
|
limit_req zone=general_limit burst=20 nodelay;
|
||
|
|
proxy_pass http://explorer_frontend;
|
||
|
|
proxy_http_version 1.1;
|
||
|
|
proxy_set_header Upgrade $http_upgrade;
|
||
|
|
proxy_set_header Connection 'upgrade';
|
||
|
|
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_cache_bypass $http_upgrade;
|
||
|
|
proxy_read_timeout 300s;
|
||
|
|
proxy_connect_timeout 75s;
|
||
|
|
}
|
||
|
|
|
||
|
|
# API endpoints
|
||
|
|
location /api/ {
|
||
|
|
limit_req zone=api_limit burst=20 nodelay;
|
||
|
|
proxy_pass http://explorer_api;
|
||
|
|
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;
|
||
|
|
|
||
|
|
# CORS headers (if needed before Cloudflare)
|
||
|
|
add_header Access-Control-Allow-Origin "*" always;
|
||
|
|
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
|
||
|
|
add_header Access-Control-Allow-Headers "Content-Type, X-API-Key" always;
|
||
|
|
}
|
||
|
|
|
||
|
|
# WebSocket support
|
||
|
|
location /ws {
|
||
|
|
proxy_pass http://explorer_api;
|
||
|
|
proxy_http_version 1.1;
|
||
|
|
proxy_set_header Upgrade $http_upgrade;
|
||
|
|
proxy_set_header Connection "upgrade";
|
||
|
|
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_read_timeout 86400s;
|
||
|
|
}
|
||
|
|
|
||
|
|
# Static files caching
|
||
|
|
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
|
||
|
|
expires 1y;
|
||
|
|
add_header Cache-Control "public, immutable";
|
||
|
|
access_log off;
|
||
|
|
}
|
||
|
|
|
||
|
|
# Health check endpoint (internal)
|
||
|
|
location /health {
|
||
|
|
access_log off;
|
||
|
|
proxy_pass http://explorer_api/health;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Enable site
|
||
|
|
ln -s /etc/nginx/sites-available/explorer /etc/nginx/sites-enabled/
|
||
|
|
rm /etc/nginx/sites-enabled/default
|
||
|
|
|
||
|
|
# Test configuration
|
||
|
|
nginx -t
|
||
|
|
|
||
|
|
# Reload Nginx
|
||
|
|
systemctl reload nginx
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Phase 7: Cloudflare Configuration
|
||
|
|
|
||
|
|
### Task 7.1: Set Up Cloudflare DNS Records
|
||
|
|
|
||
|
|
1. **Login to Cloudflare Dashboard**
|
||
|
|
- Go to https://dash.cloudflare.com
|
||
|
|
- Select your domain
|
||
|
|
|
||
|
|
2. **Add DNS Records**
|
||
|
|
- **A Record** (if using direct connection):
|
||
|
|
- Type: A
|
||
|
|
- Name: explorer (or @)
|
||
|
|
- IPv4: [Your server IP]
|
||
|
|
- Proxy: Proxied (orange cloud)
|
||
|
|
- TTL: Auto
|
||
|
|
|
||
|
|
- **CNAME Record** (for www):
|
||
|
|
- Type: CNAME
|
||
|
|
- Name: www
|
||
|
|
- Target: explorer.d-bis.org
|
||
|
|
- Proxy: Proxied
|
||
|
|
- TTL: Auto
|
||
|
|
|
||
|
|
### Task 7.2: Configure Cloudflare SSL/TLS
|
||
|
|
|
||
|
|
1. **Go to SSL/TLS Settings**
|
||
|
|
- Dashboard → SSL/TLS → Overview
|
||
|
|
|
||
|
|
2. **Set SSL/TLS Encryption Mode**
|
||
|
|
- Select: **Full (strict)**
|
||
|
|
- This ensures end-to-end encryption
|
||
|
|
|
||
|
|
3. **Configure SSL/TLS Options**
|
||
|
|
- Enable: Always Use HTTPS
|
||
|
|
- Enable: Automatic HTTPS Rewrites
|
||
|
|
- Enable: Opportunistic Encryption
|
||
|
|
- Enable: TLS 1.3
|
||
|
|
- Enable: Automatic Certificate Management
|
||
|
|
|
||
|
|
### Task 7.3: Set Up Cloudflare Tunnel
|
||
|
|
|
||
|
|
#### Option A: Cloudflare Tunnel (Recommended for no public IP)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Install cloudflared
|
||
|
|
cd /tmp
|
||
|
|
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
|
||
|
|
dpkg -i cloudflared-linux-amd64.deb
|
||
|
|
|
||
|
|
# Authenticate with Cloudflare
|
||
|
|
cloudflared tunnel login
|
||
|
|
|
||
|
|
# Create tunnel
|
||
|
|
cloudflared tunnel create explorer-tunnel
|
||
|
|
|
||
|
|
# Get tunnel ID
|
||
|
|
cloudflared tunnel list
|
||
|
|
|
||
|
|
# Create config file
|
||
|
|
mkdir -p /etc/cloudflared
|
||
|
|
cat > /etc/cloudflared/config.yml << EOF
|
||
|
|
tunnel: <TUNNEL_ID>
|
||
|
|
credentials-file: /etc/cloudflared/<TUNNEL_ID>.json
|
||
|
|
|
||
|
|
ingress:
|
||
|
|
- hostname: explorer.d-bis.org
|
||
|
|
service: http://localhost:80
|
||
|
|
- hostname: www.explorer.d-bis.org
|
||
|
|
service: http://localhost:80
|
||
|
|
- service: http_status:404
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Run tunnel
|
||
|
|
cloudflared tunnel --config /etc/cloudflared/config.yml run
|
||
|
|
|
||
|
|
# Create systemd service
|
||
|
|
cloudflared service install
|
||
|
|
|
||
|
|
# Start tunnel service
|
||
|
|
systemctl enable cloudflared
|
||
|
|
systemctl start cloudflared
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Option B: Direct Connection (If public IP available)
|
||
|
|
|
||
|
|
1. **Update DNS Records** (from Task 7.1)
|
||
|
|
- Set A record to your public IP
|
||
|
|
- Ensure proxy is enabled (orange cloud)
|
||
|
|
|
||
|
|
2. **Configure Cloudflare Page Rules** (Optional)
|
||
|
|
- Cache static assets
|
||
|
|
- Bypass cache for API endpoints
|
||
|
|
|
||
|
|
### Task 7.4: Configure Cloudflare WAF
|
||
|
|
|
||
|
|
1. **Go to Security → WAF**
|
||
|
|
- Enable Cloudflare Managed Ruleset
|
||
|
|
- Enable OWASP Core Ruleset
|
||
|
|
- Configure custom rules as needed
|
||
|
|
|
||
|
|
2. **Rate Limiting Rules**
|
||
|
|
- Create rule: API rate limiting
|
||
|
|
- Action: Challenge or Block
|
||
|
|
- Rate: 100 requests per minute per IP
|
||
|
|
|
||
|
|
### Task 7.5: Configure Cloudflare Caching
|
||
|
|
|
||
|
|
1. **Go to Caching → Configuration**
|
||
|
|
- Caching Level: Standard
|
||
|
|
- Browser Cache TTL: Respect Existing Headers
|
||
|
|
|
||
|
|
2. **Create Cache Rules**
|
||
|
|
- **Static Assets**: Cache everything, Edge TTL: 1 year
|
||
|
|
- **API Endpoints**: Bypass cache
|
||
|
|
- **Frontend Pages**: Cache HTML for 5 minutes
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Phase 8: Security Hardening
|
||
|
|
|
||
|
|
### Task 8.1: Configure Firewall (UFW)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Enable UFW
|
||
|
|
ufw --force enable
|
||
|
|
|
||
|
|
# Allow SSH
|
||
|
|
ufw allow 22/tcp
|
||
|
|
|
||
|
|
# Allow HTTP/HTTPS (if direct connection)
|
||
|
|
ufw allow 80/tcp
|
||
|
|
ufw allow 443/tcp
|
||
|
|
|
||
|
|
# Allow Cloudflare Tunnel (if using)
|
||
|
|
ufw allow from 173.245.48.0/20
|
||
|
|
ufw allow from 103.21.244.0/22
|
||
|
|
ufw allow from 103.22.200.0/22
|
||
|
|
ufw allow from 103.31.4.0/22
|
||
|
|
ufw allow from 141.101.64.0/18
|
||
|
|
ufw allow from 108.162.192.0/18
|
||
|
|
ufw allow from 190.93.240.0/20
|
||
|
|
ufw allow from 188.114.96.0/20
|
||
|
|
ufw allow from 197.234.240.0/22
|
||
|
|
ufw allow from 198.41.128.0/17
|
||
|
|
ufw allow from 162.158.0.0/15
|
||
|
|
ufw allow from 104.16.0.0/13
|
||
|
|
ufw allow from 104.24.0.0/14
|
||
|
|
ufw allow from 172.64.0.0/13
|
||
|
|
ufw allow from 131.0.72.0/22
|
||
|
|
|
||
|
|
# Check status
|
||
|
|
ufw status verbose
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 8.2: Configure Fail2ban
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Create Nginx jail
|
||
|
|
cat > /etc/fail2ban/jail.d/nginx.conf << 'EOF'
|
||
|
|
[nginx-limit-req]
|
||
|
|
enabled = true
|
||
|
|
port = http,https
|
||
|
|
logpath = /var/log/nginx/explorer-error.log
|
||
|
|
maxretry = 10
|
||
|
|
findtime = 600
|
||
|
|
bantime = 3600
|
||
|
|
|
||
|
|
[nginx-botsearch]
|
||
|
|
enabled = true
|
||
|
|
port = http,https
|
||
|
|
logpath = /var/log/nginx/explorer-access.log
|
||
|
|
maxretry = 2
|
||
|
|
findtime = 600
|
||
|
|
bantime = 86400
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Restart fail2ban
|
||
|
|
systemctl restart fail2ban
|
||
|
|
fail2ban-client status
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 8.3: Configure Automatic Updates
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Configure unattended-upgrades
|
||
|
|
cat > /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF'
|
||
|
|
Unattended-Upgrade::Allowed-Origins {
|
||
|
|
"${distro_id}:${distro_codename}-security";
|
||
|
|
"${distro_id}ESMApps:${distro_codename}-apps-security";
|
||
|
|
"${distro_id}ESM:${distro_codename}-infra-security";
|
||
|
|
};
|
||
|
|
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
||
|
|
Unattended-Upgrade::MinimalSteps "true";
|
||
|
|
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
||
|
|
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||
|
|
Unattended-Upgrade::Automatic-Reboot "false";
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Enable automatic updates
|
||
|
|
systemctl enable unattended-upgrades
|
||
|
|
systemctl start unattended-upgrades
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 8.4: Configure Log Rotation
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Configure logrotate for application logs
|
||
|
|
cat > /etc/logrotate.d/explorer << 'EOF'
|
||
|
|
/var/log/explorer/*.log {
|
||
|
|
daily
|
||
|
|
rotate 30
|
||
|
|
compress
|
||
|
|
delaycompress
|
||
|
|
notifempty
|
||
|
|
missingok
|
||
|
|
create 0640 explorer explorer
|
||
|
|
sharedscripts
|
||
|
|
postrotate
|
||
|
|
systemctl reload explorer-indexer explorer-api explorer-frontend > /dev/null 2>&1 || true
|
||
|
|
endscript
|
||
|
|
}
|
||
|
|
EOF
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 8.5: Set Up Backup Strategy
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Create backup script
|
||
|
|
cat > /usr/local/bin/explorer-backup.sh << 'EOF'
|
||
|
|
#!/bin/bash
|
||
|
|
BACKUP_DIR="/backups/explorer"
|
||
|
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||
|
|
mkdir -p $BACKUP_DIR
|
||
|
|
|
||
|
|
# Backup database
|
||
|
|
pg_dump -U explorer explorer | gzip > $BACKUP_DIR/db_$DATE.sql.gz
|
||
|
|
|
||
|
|
# Backup configuration
|
||
|
|
tar -czf $BACKUP_DIR/config_$DATE.tar.gz \
|
||
|
|
/home/explorer/explorer-monorepo/.env \
|
||
|
|
/etc/nginx/sites-available/explorer \
|
||
|
|
/etc/systemd/system/explorer-*.service
|
||
|
|
|
||
|
|
# Cleanup old backups (keep 30 days)
|
||
|
|
find $BACKUP_DIR -type f -mtime +30 -delete
|
||
|
|
EOF
|
||
|
|
|
||
|
|
chmod +x /usr/local/bin/explorer-backup.sh
|
||
|
|
|
||
|
|
# Add to crontab (daily at 2 AM)
|
||
|
|
(crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/explorer-backup.sh") | crontab -
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Phase 9: Monitoring & Maintenance
|
||
|
|
|
||
|
|
### Task 9.1: Set Up Health Checks
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Create health check script
|
||
|
|
cat > /usr/local/bin/explorer-health-check.sh << 'EOF'
|
||
|
|
#!/bin/bash
|
||
|
|
API_URL="http://localhost:8080/health"
|
||
|
|
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $API_URL)
|
||
|
|
|
||
|
|
if [ $STATUS -ne 200 ]; then
|
||
|
|
systemctl restart explorer-api
|
||
|
|
# Send alert (configure email/Slack/etc)
|
||
|
|
fi
|
||
|
|
EOF
|
||
|
|
|
||
|
|
chmod +x /usr/local/bin/explorer-health-check.sh
|
||
|
|
|
||
|
|
# Add to crontab (every 5 minutes)
|
||
|
|
(crontab -l 2>/dev/null; echo "*/5 * * * * /usr/local/bin/explorer-health-check.sh") | crontab -
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 9.2: Configure Log Monitoring
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Install log monitoring tools
|
||
|
|
apt install -y logwatch
|
||
|
|
|
||
|
|
# Configure logwatch
|
||
|
|
vim /etc/logwatch/conf/logwatch.conf
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task 9.3: Set Up Cloudflare Analytics
|
||
|
|
|
||
|
|
1. **Go to Analytics → Web Traffic**
|
||
|
|
- Monitor request rates
|
||
|
|
- Track error rates
|
||
|
|
- Monitor cache hit ratios
|
||
|
|
|
||
|
|
2. **Set Up Alerts**
|
||
|
|
- High error rate alerts
|
||
|
|
- DDoS detection alerts
|
||
|
|
- Certificate expiration alerts
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Post-Deployment Checklist
|
||
|
|
|
||
|
|
- [ ] All services running and healthy
|
||
|
|
- [ ] DNS resolving correctly
|
||
|
|
- [ ] SSL certificates active
|
||
|
|
- [ ] Cloudflare Tunnel connected (if using)
|
||
|
|
- [ ] Nginx proxying correctly
|
||
|
|
- [ ] API endpoints responding
|
||
|
|
- [ ] Frontend loading correctly
|
||
|
|
- [ ] Database migrations complete
|
||
|
|
- [ ] Indexer processing blocks
|
||
|
|
- [ ] Firewall rules configured
|
||
|
|
- [ ] Backups configured and tested
|
||
|
|
- [ ] Monitoring and alerts configured
|
||
|
|
- [ ] Documentation updated
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### Service Not Starting
|
||
|
|
```bash
|
||
|
|
# Check service status
|
||
|
|
systemctl status explorer-api
|
||
|
|
journalctl -u explorer-api -f
|
||
|
|
|
||
|
|
# Check logs
|
||
|
|
journalctl -u explorer-api --since "1 hour ago"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Database Connection Issues
|
||
|
|
```bash
|
||
|
|
# Test connection
|
||
|
|
psql -U explorer -d explorer -h localhost
|
||
|
|
|
||
|
|
# Check PostgreSQL logs
|
||
|
|
tail -f /var/log/postgresql/postgresql-16-main.log
|
||
|
|
```
|
||
|
|
|
||
|
|
### Nginx Issues
|
||
|
|
```bash
|
||
|
|
# Test configuration
|
||
|
|
nginx -t
|
||
|
|
|
||
|
|
# Check error logs
|
||
|
|
tail -f /var/log/nginx/explorer-error.log
|
||
|
|
```
|
||
|
|
|
||
|
|
### Cloudflare Tunnel Issues
|
||
|
|
```bash
|
||
|
|
# Check tunnel status
|
||
|
|
systemctl status cloudflared
|
||
|
|
cloudflared tunnel info explorer-tunnel
|
||
|
|
|
||
|
|
# View tunnel logs
|
||
|
|
journalctl -u cloudflared -f
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Maintenance Tasks
|
||
|
|
|
||
|
|
### Daily
|
||
|
|
- Monitor service status
|
||
|
|
- Check error logs
|
||
|
|
- Review Cloudflare analytics
|
||
|
|
|
||
|
|
### Weekly
|
||
|
|
- Review security logs
|
||
|
|
- Check disk space
|
||
|
|
- Verify backups
|
||
|
|
|
||
|
|
### Monthly
|
||
|
|
- Update system packages
|
||
|
|
- Review and optimize database
|
||
|
|
- Update application dependencies
|
||
|
|
- Review and adjust resource allocation
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Security Notes
|
||
|
|
|
||
|
|
1. **Never commit .env files** with real credentials
|
||
|
|
2. **Rotate passwords** regularly
|
||
|
|
3. **Keep system updated** with security patches
|
||
|
|
4. **Monitor logs** for suspicious activity
|
||
|
|
5. **Review Cloudflare WAF** logs regularly
|
||
|
|
6. **Backup database** daily
|
||
|
|
7. **Test disaster recovery** procedures quarterly
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Support & Resources
|
||
|
|
|
||
|
|
- **Cloudflare Docs**: https://developers.cloudflare.com/
|
||
|
|
- **Nginx Docs**: https://nginx.org/en/docs/
|
||
|
|
- **Proxmox Docs**: https://pve.proxmox.com/pve-docs/
|
||
|
|
- **Project Docs**: See `docs/` directory
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Last Updated**: 2024-12-23
|
||
|
|
**Version**: 1.0.0
|
||
|
|
|