v0.3.0 - Complete deployment documentation and examples - Added comprehensive deployment guide, automated deployment scripts, nginx SSL proxy setup, backup automation, and monitoring tools. Includes VPS deployment, cloud platform guides, and practical examples for production deployment of event-based configuration system.

This commit is contained in:
Your Name
2025-09-06 20:19:12 -04:00
parent a02c1204ce
commit c1de1bb480
39 changed files with 6109 additions and 2452 deletions

View File

@@ -0,0 +1,70 @@
# Deployment Examples
This directory contains practical deployment examples and scripts for the C Nostr Relay with event-based configuration.
## Directory Structure
```
examples/deployment/
├── README.md # This file
├── simple-vps/ # Basic VPS deployment
├── nginx-proxy/ # Nginx reverse proxy configurations
├── monitoring/ # Monitoring and alerting examples
└── backup/ # Backup and recovery scripts
```
## Quick Start Examples
### 1. Simple VPS Deployment
For a basic Ubuntu VPS deployment:
```bash
cd examples/deployment/simple-vps
chmod +x deploy.sh
sudo ./deploy.sh
```
### 2. SSL Proxy Setup
For nginx reverse proxy with SSL:
```bash
cd examples/deployment/nginx-proxy
chmod +x setup-ssl-proxy.sh
sudo ./setup-ssl-proxy.sh -d relay.example.com -e admin@example.com
```
### 3. Monitoring Setup
For continuous monitoring:
```bash
cd examples/deployment/monitoring
chmod +x monitor-relay.sh
sudo ./monitor-relay.sh -c -e admin@example.com
```
### 4. Backup Setup
For automated backups:
```bash
cd examples/deployment/backup
chmod +x backup-relay.sh
sudo ./backup-relay.sh -s my-backup-bucket -e admin@example.com
```
## Configuration Examples
All examples assume the event-based configuration system where:
- No config files are needed
- Configuration is stored as kind 33334 events in the database
- Admin keys are generated on first startup
- Database naming uses relay pubkey (`<relay_pubkey>.nrdb`)
## Security Notes
- **Save Admin Keys**: All deployment examples emphasize capturing the admin private key on first startup
- **Firewall Configuration**: Examples include proper firewall rules
- **SSL/TLS**: Production examples include HTTPS configuration
- **User Isolation**: Service runs as dedicated `c-relay` system user
## Support
For detailed documentation, see:
- [`docs/deployment_guide.md`](../../docs/deployment_guide.md) - Comprehensive deployment guide
- [`docs/user_guide.md`](../../docs/user_guide.md) - User guide
- [`docs/configuration_guide.md`](../../docs/configuration_guide.md) - Configuration reference

View File

@@ -0,0 +1,367 @@
#!/bin/bash
# C Nostr Relay - Backup Script
# Automated backup solution for event-based configuration relay
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Default configuration
RELAY_DIR="/opt/c-relay"
BACKUP_DIR="/backup/c-relay"
RETENTION_DAYS="30"
COMPRESS="true"
REMOTE_BACKUP=""
S3_BUCKET=""
NOTIFICATION_EMAIL=""
LOG_FILE="/var/log/relay-backup.log"
# Functions
print_step() {
echo -e "${BLUE}[STEP]${NC} $1"
echo "$(date '+%Y-%m-%d %H:%M:%S') [STEP] $1" >> "$LOG_FILE"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
echo "$(date '+%Y-%m-%d %H:%M:%S') [SUCCESS] $1" >> "$LOG_FILE"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
echo "$(date '+%Y-%m-%d %H:%M:%S') [WARNING] $1" >> "$LOG_FILE"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" >> "$LOG_FILE"
}
show_help() {
echo "Usage: $0 [OPTIONS]"
echo
echo "Options:"
echo " -d, --relay-dir DIR Relay directory (default: /opt/c-relay)"
echo " -b, --backup-dir DIR Backup directory (default: /backup/c-relay)"
echo " -r, --retention DAYS Retention period in days (default: 30)"
echo " -n, --no-compress Don't compress backups"
echo " -s, --s3-bucket BUCKET Upload to S3 bucket"
echo " -e, --email EMAIL Send notification email"
echo " -v, --verify Verify backup integrity"
echo " -h, --help Show this help message"
echo
echo "Examples:"
echo " $0 # Basic backup"
echo " $0 -s my-backup-bucket -e admin@example.com"
echo " $0 -r 7 -n # 7-day retention, no compression"
}
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-d|--relay-dir)
RELAY_DIR="$2"
shift 2
;;
-b|--backup-dir)
BACKUP_DIR="$2"
shift 2
;;
-r|--retention)
RETENTION_DAYS="$2"
shift 2
;;
-n|--no-compress)
COMPRESS="false"
shift
;;
-s|--s3-bucket)
S3_BUCKET="$2"
shift 2
;;
-e|--email)
NOTIFICATION_EMAIL="$2"
shift 2
;;
-v|--verify)
VERIFY="true"
shift
;;
-h|--help)
show_help
exit 0
;;
*)
print_error "Unknown option: $1"
show_help
exit 1
;;
esac
done
}
check_dependencies() {
print_step "Checking dependencies..."
# Check sqlite3
if ! command -v sqlite3 &> /dev/null; then
print_error "sqlite3 not found. Install with: apt install sqlite3"
exit 1
fi
# Check compression tools
if [[ "$COMPRESS" == "true" ]]; then
if ! command -v gzip &> /dev/null; then
print_error "gzip not found for compression"
exit 1
fi
fi
# Check S3 tools if needed
if [[ -n "$S3_BUCKET" ]]; then
if ! command -v aws &> /dev/null; then
print_error "AWS CLI not found. Install with: apt install awscli"
exit 1
fi
fi
print_success "Dependencies verified"
}
find_database() {
print_step "Finding relay database..."
# Look for .nrdb files in relay directory
DB_FILES=($(find "$RELAY_DIR" -name "*.nrdb" 2>/dev/null))
if [[ ${#DB_FILES[@]} -eq 0 ]]; then
print_error "No relay database files found in $RELAY_DIR"
exit 1
elif [[ ${#DB_FILES[@]} -gt 1 ]]; then
print_warning "Multiple database files found:"
printf '%s\n' "${DB_FILES[@]}"
print_warning "Using the first one: ${DB_FILES[0]}"
fi
DB_FILE="${DB_FILES[0]}"
DB_NAME=$(basename "$DB_FILE")
print_success "Found database: $DB_FILE"
}
create_backup_directory() {
print_step "Creating backup directory..."
if [[ ! -d "$BACKUP_DIR" ]]; then
mkdir -p "$BACKUP_DIR"
chmod 700 "$BACKUP_DIR"
print_success "Created backup directory: $BACKUP_DIR"
else
print_success "Using existing backup directory: $BACKUP_DIR"
fi
}
perform_backup() {
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_name="relay_backup_${timestamp}"
local backup_file="$BACKUP_DIR/${backup_name}.nrdb"
print_step "Creating database backup..."
# Check if database is accessible
if [[ ! -r "$DB_FILE" ]]; then
print_error "Cannot read database file: $DB_FILE"
exit 1
fi
# Get database size
local db_size=$(du -h "$DB_FILE" | cut -f1)
print_step "Database size: $db_size"
# Create SQLite backup using .backup command (hot backup)
if sqlite3 "$DB_FILE" ".backup $backup_file" 2>/dev/null; then
print_success "Database backup created: $backup_file"
else
# Fallback to file copy if .backup fails
print_warning "SQLite backup failed, using file copy method"
cp "$DB_FILE" "$backup_file"
print_success "File copy backup created: $backup_file"
fi
# Verify backup file
if [[ ! -f "$backup_file" ]]; then
print_error "Backup file was not created"
exit 1
fi
# Check backup integrity
if [[ "$VERIFY" == "true" ]]; then
print_step "Verifying backup integrity..."
if sqlite3 "$backup_file" "PRAGMA integrity_check;" | grep -q "ok"; then
print_success "Backup integrity verified"
else
print_error "Backup integrity check failed"
exit 1
fi
fi
# Compress backup
if [[ "$COMPRESS" == "true" ]]; then
print_step "Compressing backup..."
gzip "$backup_file"
backup_file="${backup_file}.gz"
print_success "Backup compressed: $backup_file"
fi
# Set backup file as global variable for other functions
BACKUP_FILE="$backup_file"
BACKUP_NAME="$backup_name"
}
upload_to_s3() {
if [[ -z "$S3_BUCKET" ]]; then
return 0
fi
print_step "Uploading backup to S3..."
local s3_path="s3://$S3_BUCKET/c-relay/$(date +%Y)/$(date +%m)/"
if aws s3 cp "$BACKUP_FILE" "$s3_path" --storage-class STANDARD_IA; then
print_success "Backup uploaded to S3: $s3_path"
else
print_error "Failed to upload backup to S3"
return 1
fi
}
cleanup_old_backups() {
print_step "Cleaning up old backups..."
local deleted_count=0
# Clean local backups
while IFS= read -r -d '' file; do
rm "$file"
((deleted_count++))
done < <(find "$BACKUP_DIR" -name "relay_backup_*.nrdb*" -mtime "+$RETENTION_DAYS" -print0 2>/dev/null)
if [[ $deleted_count -gt 0 ]]; then
print_success "Deleted $deleted_count old local backups"
else
print_success "No old local backups to delete"
fi
# Clean S3 backups if configured
if [[ -n "$S3_BUCKET" ]]; then
local cutoff_date=$(date -d "$RETENTION_DAYS days ago" +%Y-%m-%d)
print_step "Cleaning S3 backups older than $cutoff_date..."
# Note: This is a simplified approach. In production, use S3 lifecycle policies
aws s3 ls "s3://$S3_BUCKET/c-relay/" --recursive | \
awk '$1 < "'$cutoff_date'" {print $4}' | \
while read -r key; do
aws s3 rm "s3://$S3_BUCKET/$key"
print_step "Deleted S3 backup: $key"
done
fi
}
send_notification() {
if [[ -z "$NOTIFICATION_EMAIL" ]]; then
return 0
fi
print_step "Sending notification email..."
local subject="C Nostr Relay Backup - $(date +%Y-%m-%d)"
local backup_size=$(du -h "$BACKUP_FILE" | cut -f1)
local message="Backup completed successfully.
Details:
- Date: $(date)
- Database: $DB_FILE
- Backup File: $BACKUP_FILE
- Backup Size: $backup_size
- Retention: $RETENTION_DAYS days
"
if [[ -n "$S3_BUCKET" ]]; then
message+="\n- S3 Bucket: $S3_BUCKET"
fi
# Try to send email using mail command
if command -v mail &> /dev/null; then
echo -e "$message" | mail -s "$subject" "$NOTIFICATION_EMAIL"
print_success "Notification sent to $NOTIFICATION_EMAIL"
else
print_warning "Mail command not available, skipping notification"
fi
}
show_backup_summary() {
local backup_size=$(du -h "$BACKUP_FILE" | cut -f1)
local backup_count=$(find "$BACKUP_DIR" -name "relay_backup_*.nrdb*" | wc -l)
echo
echo "🎉 Backup Completed Successfully!"
echo
echo "Backup Details:"
echo " Source DB: $DB_FILE"
echo " Backup File: $BACKUP_FILE"
echo " Backup Size: $backup_size"
echo " Compressed: $COMPRESS"
echo " Verified: ${VERIFY:-false}"
echo
echo "Storage:"
echo " Local Backups: $backup_count files in $BACKUP_DIR"
echo " Retention: $RETENTION_DAYS days"
if [[ -n "$S3_BUCKET" ]]; then
echo " S3 Bucket: $S3_BUCKET"
fi
echo
echo "Management Commands:"
echo " List backups: find $BACKUP_DIR -name 'relay_backup_*'"
echo " Restore: See examples/deployment/backup/restore-relay.sh"
echo
}
# Main execution
main() {
echo
echo "==============================================="
echo "💾 C Nostr Relay - Database Backup"
echo "==============================================="
echo
# Initialize log file
mkdir -p "$(dirname "$LOG_FILE")"
touch "$LOG_FILE"
parse_args "$@"
check_dependencies
find_database
create_backup_directory
perform_backup
upload_to_s3
cleanup_old_backups
send_notification
show_backup_summary
print_success "Backup process completed successfully!"
}
# Handle errors
trap 'print_error "Backup failed at line $LINENO"' ERR
# Run main function
main "$@"

View File

@@ -0,0 +1,460 @@
#!/bin/bash
# C Nostr Relay - Monitoring Script
# Comprehensive monitoring for event-based configuration relay
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
RELAY_DIR="/opt/c-relay"
SERVICE_NAME="c-relay"
RELAY_PORT="8888"
LOG_FILE="/var/log/relay-monitor.log"
ALERT_EMAIL=""
WEBHOOK_URL=""
CHECK_INTERVAL="60"
MAX_MEMORY_MB="1024"
MAX_DB_SIZE_MB="10240"
MIN_DISK_SPACE_MB="1024"
# Counters for statistics
TOTAL_CHECKS=0
FAILED_CHECKS=0
ALERTS_SENT=0
# Functions
print_step() {
echo -e "${BLUE}[INFO]${NC} $1"
log_message "INFO" "$1"
}
print_success() {
echo -e "${GREEN}[OK]${NC} $1"
log_message "OK" "$1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
log_message "WARN" "$1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
log_message "ERROR" "$1"
}
log_message() {
local level="$1"
local message="$2"
echo "$(date '+%Y-%m-%d %H:%M:%S') [$level] $message" >> "$LOG_FILE"
}
show_help() {
echo "Usage: $0 [OPTIONS]"
echo
echo "Options:"
echo " -d, --relay-dir DIR Relay directory (default: /opt/c-relay)"
echo " -p, --port PORT Relay port (default: 8888)"
echo " -i, --interval SECONDS Check interval (default: 60)"
echo " -e, --email EMAIL Alert email address"
echo " -w, --webhook URL Webhook URL for alerts"
echo " -m, --max-memory MB Max memory usage alert (default: 1024MB)"
echo " -s, --max-db-size MB Max database size alert (default: 10240MB)"
echo " -f, --min-free-space MB Min disk space alert (default: 1024MB)"
echo " -c, --continuous Run continuously (daemon mode)"
echo " -h, --help Show this help message"
echo
echo "Examples:"
echo " $0 # Single check"
echo " $0 -c -i 30 -e admin@example.com # Continuous monitoring"
echo " $0 -w https://hooks.slack.com/... # Webhook notifications"
}
parse_args() {
CONTINUOUS="false"
while [[ $# -gt 0 ]]; do
case $1 in
-d|--relay-dir)
RELAY_DIR="$2"
shift 2
;;
-p|--port)
RELAY_PORT="$2"
shift 2
;;
-i|--interval)
CHECK_INTERVAL="$2"
shift 2
;;
-e|--email)
ALERT_EMAIL="$2"
shift 2
;;
-w|--webhook)
WEBHOOK_URL="$2"
shift 2
;;
-m|--max-memory)
MAX_MEMORY_MB="$2"
shift 2
;;
-s|--max-db-size)
MAX_DB_SIZE_MB="$2"
shift 2
;;
-f|--min-free-space)
MIN_DISK_SPACE_MB="$2"
shift 2
;;
-c|--continuous)
CONTINUOUS="true"
shift
;;
-h|--help)
show_help
exit 0
;;
*)
print_error "Unknown option: $1"
show_help
exit 1
;;
esac
done
}
check_process_running() {
print_step "Checking if relay process is running..."
if pgrep -f "c_relay_x86" > /dev/null; then
print_success "Relay process is running"
return 0
else
print_error "Relay process is not running"
return 1
fi
}
check_port_listening() {
print_step "Checking if port $RELAY_PORT is listening..."
if netstat -tln 2>/dev/null | grep -q ":$RELAY_PORT " || \
ss -tln 2>/dev/null | grep -q ":$RELAY_PORT "; then
print_success "Port $RELAY_PORT is listening"
return 0
else
print_error "Port $RELAY_PORT is not listening"
return 1
fi
}
check_service_status() {
print_step "Checking systemd service status..."
if systemctl is-active --quiet "$SERVICE_NAME"; then
print_success "Service $SERVICE_NAME is active"
return 0
else
local status=$(systemctl is-active "$SERVICE_NAME" 2>/dev/null || echo "unknown")
print_error "Service $SERVICE_NAME status: $status"
return 1
fi
}
check_memory_usage() {
print_step "Checking memory usage..."
local memory_kb=$(ps aux | grep "c_relay_x86" | grep -v grep | awk '{sum+=$6} END {print sum}')
if [[ -z "$memory_kb" ]]; then
print_warning "Could not determine memory usage"
return 1
fi
local memory_mb=$((memory_kb / 1024))
if [[ $memory_mb -gt $MAX_MEMORY_MB ]]; then
print_error "High memory usage: ${memory_mb}MB (limit: ${MAX_MEMORY_MB}MB)"
return 1
else
print_success "Memory usage: ${memory_mb}MB"
return 0
fi
}
check_database_size() {
print_step "Checking database size..."
local db_files=($(find "$RELAY_DIR" -name "*.nrdb" 2>/dev/null))
if [[ ${#db_files[@]} -eq 0 ]]; then
print_warning "No database files found"
return 1
fi
local total_size=0
for db_file in "${db_files[@]}"; do
if [[ -r "$db_file" ]]; then
local size_kb=$(du -k "$db_file" | cut -f1)
total_size=$((total_size + size_kb))
fi
done
local total_size_mb=$((total_size / 1024))
if [[ $total_size_mb -gt $MAX_DB_SIZE_MB ]]; then
print_error "Large database size: ${total_size_mb}MB (limit: ${MAX_DB_SIZE_MB}MB)"
return 1
else
print_success "Database size: ${total_size_mb}MB"
return 0
fi
}
check_disk_space() {
print_step "Checking disk space..."
local free_space_kb=$(df "$RELAY_DIR" | awk 'NR==2 {print $4}')
local free_space_mb=$((free_space_kb / 1024))
if [[ $free_space_mb -lt $MIN_DISK_SPACE_MB ]]; then
print_error "Low disk space: ${free_space_mb}MB (minimum: ${MIN_DISK_SPACE_MB}MB)"
return 1
else
print_success "Free disk space: ${free_space_mb}MB"
return 0
fi
}
check_database_integrity() {
print_step "Checking database integrity..."
local db_files=($(find "$RELAY_DIR" -name "*.nrdb" 2>/dev/null))
if [[ ${#db_files[@]} -eq 0 ]]; then
print_warning "No database files to check"
return 1
fi
local integrity_ok=true
for db_file in "${db_files[@]}"; do
if [[ -r "$db_file" ]]; then
if timeout 30 sqlite3 "$db_file" "PRAGMA integrity_check;" | grep -q "ok"; then
print_success "Database integrity OK: $(basename "$db_file")"
else
print_error "Database integrity failed: $(basename "$db_file")"
integrity_ok=false
fi
fi
done
if $integrity_ok; then
return 0
else
return 1
fi
}
check_websocket_connection() {
print_step "Checking WebSocket connection..."
# Simple connection test using curl
if timeout 10 curl -s -N -H "Connection: Upgrade" \
-H "Upgrade: websocket" -H "Sec-WebSocket-Key: test" \
-H "Sec-WebSocket-Version: 13" \
"http://localhost:$RELAY_PORT/" >/dev/null 2>&1; then
print_success "WebSocket connection test passed"
return 0
else
print_warning "WebSocket connection test failed (may be normal)"
return 1
fi
}
check_configuration_events() {
print_step "Checking configuration events..."
local db_files=($(find "$RELAY_DIR" -name "*.nrdb" 2>/dev/null))
if [[ ${#db_files[@]} -eq 0 ]]; then
print_warning "No database files found"
return 1
fi
local config_count=0
for db_file in "${db_files[@]}"; do
if [[ -r "$db_file" ]]; then
local count=$(sqlite3 "$db_file" "SELECT COUNT(*) FROM events WHERE kind = 33334;" 2>/dev/null || echo "0")
config_count=$((config_count + count))
fi
done
if [[ $config_count -gt 0 ]]; then
print_success "Configuration events found: $config_count"
return 0
else
print_warning "No configuration events found"
return 1
fi
}
send_alert() {
local subject="$1"
local message="$2"
local severity="$3"
ALERTS_SENT=$((ALERTS_SENT + 1))
# Email alert
if [[ -n "$ALERT_EMAIL" ]] && command -v mail >/dev/null 2>&1; then
echo -e "$message" | mail -s "$subject" "$ALERT_EMAIL"
print_step "Alert sent to $ALERT_EMAIL"
fi
# Webhook alert
if [[ -n "$WEBHOOK_URL" ]] && command -v curl >/dev/null 2>&1; then
local webhook_data="{\"text\":\"$subject\",\"attachments\":[{\"color\":\"$severity\",\"text\":\"$message\"}]}"
curl -X POST -H 'Content-type: application/json' \
--data "$webhook_data" "$WEBHOOK_URL" >/dev/null 2>&1
print_step "Alert sent to webhook"
fi
}
restart_service() {
print_step "Attempting to restart service..."
if systemctl restart "$SERVICE_NAME"; then
print_success "Service restarted successfully"
sleep 5 # Wait for service to stabilize
return 0
else
print_error "Failed to restart service"
return 1
fi
}
run_checks() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local failed_checks=0
local total_checks=8
echo
echo "🔍 Relay Health Check - $timestamp"
echo "=================================="
# Core functionality checks
check_process_running || ((failed_checks++))
check_service_status || ((failed_checks++))
check_port_listening || ((failed_checks++))
# Resource checks
check_memory_usage || ((failed_checks++))
check_disk_space || ((failed_checks++))
check_database_size || ((failed_checks++))
# Database checks
check_database_integrity || ((failed_checks++))
check_configuration_events || ((failed_checks++))
# Optional checks
check_websocket_connection # Don't count this as critical
TOTAL_CHECKS=$((TOTAL_CHECKS + total_checks))
FAILED_CHECKS=$((FAILED_CHECKS + failed_checks))
# Summary
echo
if [[ $failed_checks -eq 0 ]]; then
print_success "All checks passed ($total_checks/$total_checks)"
return 0
else
print_error "Failed checks: $failed_checks/$total_checks"
# Send alert if configured
if [[ -n "$ALERT_EMAIL" || -n "$WEBHOOK_URL" ]]; then
local alert_subject="C Nostr Relay Health Alert"
local alert_message="Relay health check failed.
Failed checks: $failed_checks/$total_checks
Time: $timestamp
Host: $(hostname)
Service: $SERVICE_NAME
Port: $RELAY_PORT
Please check the relay logs:
sudo journalctl -u $SERVICE_NAME --since '10 minutes ago'
"
send_alert "$alert_subject" "$alert_message" "danger"
fi
# Auto-restart if service is down
if ! check_process_running >/dev/null 2>&1; then
print_step "Process is down, attempting restart..."
restart_service
fi
return 1
fi
}
show_statistics() {
if [[ $TOTAL_CHECKS -gt 0 ]]; then
local success_rate=$(( (TOTAL_CHECKS - FAILED_CHECKS) * 100 / TOTAL_CHECKS ))
echo
echo "📊 Monitoring Statistics"
echo "======================="
echo "Total Checks: $TOTAL_CHECKS"
echo "Failed Checks: $FAILED_CHECKS"
echo "Success Rate: ${success_rate}%"
echo "Alerts Sent: $ALERTS_SENT"
fi
}
cleanup() {
echo
print_step "Monitoring stopped"
show_statistics
exit 0
}
# Main execution
main() {
echo
echo "📡 C Nostr Relay - Health Monitor"
echo "================================="
echo
# Initialize log file
mkdir -p "$(dirname "$LOG_FILE")"
touch "$LOG_FILE"
parse_args "$@"
# Trap signals for cleanup
trap cleanup SIGINT SIGTERM
if [[ "$CONTINUOUS" == "true" ]]; then
print_step "Starting continuous monitoring (interval: ${CHECK_INTERVAL}s)"
print_step "Press Ctrl+C to stop"
while true; do
run_checks
sleep "$CHECK_INTERVAL"
done
else
run_checks
fi
show_statistics
}
# Run main function
main "$@"

View File

@@ -0,0 +1,168 @@
# Nginx Configuration for C Nostr Relay
# Complete nginx.conf for reverse proxy setup with SSL
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging format
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# Basic settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml;
# Rate limiting
limit_req_zone $remote_addr zone=relay:10m rate=10r/s;
# Map WebSocket upgrade
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Upstream for the relay
upstream c_relay_backend {
server 127.0.0.1:8888;
keepalive 32;
}
# HTTP Server (redirect to HTTPS)
server {
listen 80;
server_name relay.yourdomain.com;
# Redirect all HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
# HTTPS Server
server {
listen 443 ssl http2;
server_name relay.yourdomain.com;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/relay.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/relay.yourdomain.com/privkey.pem;
# SSL Security Settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/relay.yourdomain.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Security Headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self'; connect-src 'self' wss://relay.yourdomain.com; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
# Rate limiting
limit_req zone=relay burst=20 nodelay;
# Main proxy location for WebSocket and HTTP
location / {
# Proxy settings
proxy_pass http://c_relay_backend;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
# Headers
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_set_header X-Forwarded-Host $server_name;
# WebSocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Timeouts for WebSocket connections
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 60s;
# Buffer settings
proxy_buffering off;
proxy_request_buffering off;
# Error handling
proxy_intercept_errors on;
error_page 502 503 504 /50x.html;
}
# Error pages
location = /50x.html {
root /usr/share/nginx/html;
}
# Health check endpoint (if implemented)
location /health {
proxy_pass http://c_relay_backend/health;
access_log off;
}
# Deny access to hidden files
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# Optional: Metrics endpoint (if implemented)
location /metrics {
proxy_pass http://c_relay_backend/metrics;
# Restrict access to monitoring systems
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;
}
}
}

View File

@@ -0,0 +1,346 @@
#!/bin/bash
# C Nostr Relay - Nginx SSL Proxy Setup Script
# Sets up nginx as a reverse proxy with Let's Encrypt SSL
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
DOMAIN=""
EMAIL=""
RELAY_PORT="8888"
NGINX_CONF_DIR="/etc/nginx"
SITES_AVAILABLE="/etc/nginx/sites-available"
SITES_ENABLED="/etc/nginx/sites-enabled"
# Functions
print_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
show_help() {
echo "Usage: $0 -d DOMAIN -e EMAIL [OPTIONS]"
echo
echo "Required options:"
echo " -d, --domain DOMAIN Domain name for the relay (e.g., relay.example.com)"
echo " -e, --email EMAIL Email address for Let's Encrypt"
echo
echo "Optional options:"
echo " -p, --port PORT Relay port (default: 8888)"
echo " -h, --help Show this help message"
echo
echo "Example:"
echo " $0 -d relay.example.com -e admin@example.com"
}
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-d|--domain)
DOMAIN="$2"
shift 2
;;
-e|--email)
EMAIL="$2"
shift 2
;;
-p|--port)
RELAY_PORT="$2"
shift 2
;;
-h|--help)
show_help
exit 0
;;
*)
print_error "Unknown option: $1"
show_help
exit 1
;;
esac
done
if [[ -z "$DOMAIN" || -z "$EMAIL" ]]; then
print_error "Domain and email are required"
show_help
exit 1
fi
}
check_root() {
if [[ $EUID -ne 0 ]]; then
print_error "This script must be run as root (use sudo)"
exit 1
fi
}
check_relay_running() {
print_step "Checking if C Nostr Relay is running..."
if ! pgrep -f "c_relay_x86" > /dev/null; then
print_error "C Nostr Relay is not running"
print_error "Please start the relay first with: sudo systemctl start c-relay"
exit 1
fi
if ! netstat -tln | grep -q ":$RELAY_PORT"; then
print_error "Relay is not listening on port $RELAY_PORT"
exit 1
fi
print_success "Relay is running on port $RELAY_PORT"
}
install_nginx() {
print_step "Installing nginx..."
if command -v nginx &> /dev/null; then
print_warning "Nginx is already installed"
else
apt update
apt install -y nginx
systemctl enable nginx
print_success "Nginx installed"
fi
}
install_certbot() {
print_step "Installing certbot for Let's Encrypt..."
if command -v certbot &> /dev/null; then
print_warning "Certbot is already installed"
else
apt install -y certbot python3-certbot-nginx
print_success "Certbot installed"
fi
}
create_nginx_config() {
print_step "Creating nginx configuration..."
# Backup existing default config
if [[ -f "$SITES_ENABLED/default" ]]; then
mv "$SITES_ENABLED/default" "$SITES_ENABLED/default.backup"
print_warning "Backed up default nginx config"
fi
# Create site configuration
cat > "$SITES_AVAILABLE/$DOMAIN" << EOF
# HTTP Server (will be modified by certbot for HTTPS)
server {
listen 80;
server_name $DOMAIN;
# Rate limiting
limit_req_zone \$remote_addr zone=relay:10m rate=10r/s;
limit_req zone=relay burst=20 nodelay;
# Map WebSocket upgrade
map \$http_upgrade \$connection_upgrade {
default upgrade;
'' close;
}
location / {
# Proxy settings
proxy_pass http://127.0.0.1:$RELAY_PORT;
proxy_http_version 1.1;
proxy_cache_bypass \$http_upgrade;
# Headers
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 \$connection_upgrade;
# Timeouts for WebSocket connections
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
# Buffer settings
proxy_buffering off;
}
# Health check
location /health {
proxy_pass http://127.0.0.1:$RELAY_PORT/health;
access_log off;
}
}
EOF
# Enable the site
ln -sf "$SITES_AVAILABLE/$DOMAIN" "$SITES_ENABLED/"
print_success "Nginx configuration created for $DOMAIN"
}
test_nginx_config() {
print_step "Testing nginx configuration..."
if nginx -t; then
print_success "Nginx configuration is valid"
else
print_error "Nginx configuration is invalid"
exit 1
fi
}
restart_nginx() {
print_step "Restarting nginx..."
systemctl restart nginx
systemctl enable nginx
if systemctl is-active --quiet nginx; then
print_success "Nginx restarted successfully"
else
print_error "Failed to restart nginx"
exit 1
fi
}
setup_ssl() {
print_step "Setting up SSL certificate with Let's Encrypt..."
# Obtain certificate
if certbot --nginx -d "$DOMAIN" --email "$EMAIL" --agree-tos --non-interactive; then
print_success "SSL certificate obtained and configured"
else
print_error "Failed to obtain SSL certificate"
exit 1
fi
}
setup_auto_renewal() {
print_step "Setting up SSL certificate auto-renewal..."
# Create renewal cron job
cat > /etc/cron.d/certbot-renew << EOF
# Renew Let's Encrypt certificates
0 12 * * * root /usr/bin/certbot renew --quiet && /usr/bin/systemctl reload nginx
EOF
print_success "Auto-renewal configured"
}
configure_firewall() {
print_step "Configuring firewall..."
if command -v ufw &> /dev/null; then
ufw allow 'Nginx Full'
ufw delete allow 'Nginx HTTP' 2>/dev/null || true
print_success "UFW configured for nginx"
elif command -v firewall-cmd &> /dev/null; then
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
print_success "Firewalld configured"
else
print_warning "No recognized firewall found"
print_warning "Please ensure ports 80 and 443 are open"
fi
}
test_setup() {
print_step "Testing the setup..."
sleep 5
# Test HTTP redirect
if curl -s -o /dev/null -w "%{http_code}" "http://$DOMAIN" | grep -q "301\|302"; then
print_success "HTTP to HTTPS redirect working"
else
print_warning "HTTP redirect test failed"
fi
# Test HTTPS
if curl -s -o /dev/null -w "%{http_code}" "https://$DOMAIN" | grep -q "200"; then
print_success "HTTPS connection working"
else
print_warning "HTTPS test failed"
fi
# Test WebSocket (if relay supports it)
if command -v wscat &> /dev/null; then
print_step "Testing WebSocket connection..."
timeout 5 wscat -c "wss://$DOMAIN" --execute "exit" &>/dev/null && \
print_success "WebSocket connection working" || \
print_warning "WebSocket test inconclusive (install wscat for better testing)"
fi
}
show_final_status() {
echo
echo "🎉 SSL Proxy Setup Complete!"
echo
echo "Configuration Summary:"
echo " Domain: $DOMAIN"
echo " SSL: Let's Encrypt"
echo " Backend: 127.0.0.1:$RELAY_PORT"
echo " Config: $SITES_AVAILABLE/$DOMAIN"
echo
echo "Your Nostr relay is now accessible at:"
echo " HTTPS URL: https://$DOMAIN"
echo " WebSocket: wss://$DOMAIN"
echo
echo "Management Commands:"
echo " Test config: sudo nginx -t"
echo " Reload nginx: sudo systemctl reload nginx"
echo " Check SSL: sudo certbot certificates"
echo " Renew SSL: sudo certbot renew"
echo
echo "SSL certificate will auto-renew via cron."
echo
}
# Main execution
main() {
echo
echo "============================================"
echo "🔒 C Nostr Relay - SSL Proxy Setup"
echo "============================================"
echo
parse_args "$@"
check_root
check_relay_running
install_nginx
install_certbot
create_nginx_config
test_nginx_config
restart_nginx
setup_ssl
setup_auto_renewal
configure_firewall
test_setup
show_final_status
print_success "SSL proxy setup completed successfully!"
}
# Run main function
main "$@"

View File

@@ -0,0 +1,282 @@
#!/bin/bash
# C Nostr Relay - Simple VPS Deployment Script
# Deploys the relay with event-based configuration on Ubuntu/Debian VPS
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
RELAY_USER="c-relay"
INSTALL_DIR="/opt/c-relay"
SERVICE_NAME="c-relay"
RELAY_PORT="8888"
# Functions
print_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
check_root() {
if [[ $EUID -ne 0 ]]; then
print_error "This script must be run as root (use sudo)"
exit 1
fi
}
detect_os() {
if [[ -f /etc/debian_version ]]; then
OS="debian"
print_success "Detected Debian/Ubuntu system"
elif [[ -f /etc/redhat-release ]]; then
OS="redhat"
print_success "Detected RedHat/CentOS system"
else
print_error "Unsupported operating system"
exit 1
fi
}
install_dependencies() {
print_step "Installing system dependencies..."
if [[ $OS == "debian" ]]; then
apt update
apt install -y build-essential git sqlite3 libsqlite3-dev \
libwebsockets-dev libssl-dev libsecp256k1-dev \
libcurl4-openssl-dev zlib1g-dev systemd curl wget
elif [[ $OS == "redhat" ]]; then
yum groupinstall -y "Development Tools"
yum install -y git sqlite-devel libwebsockets-devel \
openssl-devel libsecp256k1-devel libcurl-devel \
zlib-devel systemd curl wget
fi
print_success "Dependencies installed"
}
create_user() {
print_step "Creating system user for relay..."
if id "$RELAY_USER" &>/dev/null; then
print_warning "User $RELAY_USER already exists"
else
useradd --system --home-dir "$INSTALL_DIR" --shell /bin/false "$RELAY_USER"
print_success "Created user: $RELAY_USER"
fi
}
setup_directories() {
print_step "Setting up directories..."
mkdir -p "$INSTALL_DIR"
chown "$RELAY_USER:$RELAY_USER" "$INSTALL_DIR"
chmod 755 "$INSTALL_DIR"
print_success "Directories configured"
}
build_relay() {
print_step "Building C Nostr Relay..."
# Check if we're in the source directory
if [[ ! -f "Makefile" ]]; then
print_error "Makefile not found. Please run this script from the c-relay source directory."
exit 1
fi
# Clean and build
make clean
make
if [[ ! -f "build/c_relay_x86" ]]; then
print_error "Build failed - binary not found"
exit 1
fi
print_success "Relay built successfully"
}
install_binary() {
print_step "Installing relay binary..."
cp build/c_relay_x86 "$INSTALL_DIR/"
chown "$RELAY_USER:$RELAY_USER" "$INSTALL_DIR/c_relay_x86"
chmod +x "$INSTALL_DIR/c_relay_x86"
print_success "Binary installed to $INSTALL_DIR"
}
install_service() {
print_step "Installing systemd service..."
# Use the existing systemd service file
if [[ -f "systemd/c-relay.service" ]]; then
cp systemd/c-relay.service /etc/systemd/system/
systemctl daemon-reload
print_success "Systemd service installed"
else
print_warning "Systemd service file not found, creating basic one..."
cat > /etc/systemd/system/c-relay.service << EOF
[Unit]
Description=C Nostr Relay
After=network.target
[Service]
Type=simple
User=$RELAY_USER
Group=$RELAY_USER
WorkingDirectory=$INSTALL_DIR
ExecStart=$INSTALL_DIR/c_relay_x86
Restart=always
RestartSec=5
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=$INSTALL_DIR
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
print_success "Basic systemd service created"
fi
}
configure_firewall() {
print_step "Configuring firewall..."
if command -v ufw &> /dev/null; then
# UFW (Ubuntu)
ufw allow "$RELAY_PORT/tcp" comment "Nostr Relay"
print_success "UFW rule added for port $RELAY_PORT"
elif command -v firewall-cmd &> /dev/null; then
# Firewalld (CentOS/RHEL)
firewall-cmd --permanent --add-port="$RELAY_PORT/tcp"
firewall-cmd --reload
print_success "Firewalld rule added for port $RELAY_PORT"
else
print_warning "No recognized firewall found. Please manually open port $RELAY_PORT"
fi
}
start_service() {
print_step "Starting relay service..."
systemctl enable "$SERVICE_NAME"
systemctl start "$SERVICE_NAME"
sleep 3
if systemctl is-active --quiet "$SERVICE_NAME"; then
print_success "Relay service started and enabled"
else
print_error "Failed to start relay service"
print_error "Check logs with: journalctl -u $SERVICE_NAME --no-pager"
exit 1
fi
}
capture_admin_keys() {
print_step "Capturing admin keys..."
echo
echo "=================================="
echo "🔑 CRITICAL: ADMIN PRIVATE KEY 🔑"
echo "=================================="
echo
print_warning "The admin private key will be shown in the service logs."
print_warning "This key is generated ONCE and is needed for all configuration updates!"
echo
echo "To view the admin key, run:"
echo " sudo journalctl -u $SERVICE_NAME --no-pager | grep -A 5 'Admin Private Key'"
echo
echo "Or check recent logs:"
echo " sudo journalctl -u $SERVICE_NAME --since '5 minutes ago'"
echo
print_error "IMPORTANT: Save this key in a secure location immediately!"
echo
}
show_status() {
print_step "Deployment Status"
echo
echo "🎉 Deployment Complete!"
echo
echo "Service Status:"
systemctl status "$SERVICE_NAME" --no-pager -l
echo
echo "Quick Commands:"
echo " Check status: sudo systemctl status $SERVICE_NAME"
echo " View logs: sudo journalctl -u $SERVICE_NAME -f"
echo " Restart: sudo systemctl restart $SERVICE_NAME"
echo " Stop: sudo systemctl stop $SERVICE_NAME"
echo
echo "Relay Information:"
echo " Port: $RELAY_PORT"
echo " Directory: $INSTALL_DIR"
echo " User: $RELAY_USER"
echo " Database: Auto-generated in $INSTALL_DIR"
echo
echo "Next Steps:"
echo "1. Get your admin private key from the logs (see above)"
echo "2. Configure your relay using the event-based system"
echo "3. Set up SSL/TLS with a reverse proxy (nginx/apache)"
echo "4. Configure monitoring and backups"
echo
echo "Documentation:"
echo " User Guide: docs/user_guide.md"
echo " Config Guide: docs/configuration_guide.md"
echo " Deployment: docs/deployment_guide.md"
echo
}
# Main deployment flow
main() {
echo
echo "=========================================="
echo "🚀 C Nostr Relay - Simple VPS Deployment"
echo "=========================================="
echo
check_root
detect_os
install_dependencies
create_user
setup_directories
build_relay
install_binary
install_service
configure_firewall
start_service
capture_admin_keys
show_status
print_success "Deployment completed successfully!"
}
# Run main function
main "$@"