Bare Metal Deployment¶
This guide covers deploying Nexus on bare metal servers, providing complete control over the infrastructure and optimal performance for high-throughput applications.
Overview¶
Bare metal deployment offers the highest performance and control but requires more operational overhead. This approach is ideal for organizations with specific compliance requirements, latency-sensitive applications, or those wanting to maximize resource utilization.
Prerequisites¶
Hardware Requirements¶
Minimum Requirements¶
- CPU: 4 cores, 2.4 GHz
- Memory: 8 GB RAM
- Storage: 100 GB SSD
- Network: 1 Gbps Ethernet
Recommended Requirements¶
- CPU: 16 cores, 3.0 GHz
- Memory: 32 GB RAM
- Storage: 500 GB NVMe SSD
- Network: 10 Gbps Ethernet
High Availability Setup¶
- Load Balancer: 2 servers (active/passive)
- Application Servers: 3+ servers
- Database Servers: 3 servers (primary + 2 replicas)
- Storage: Shared storage or distributed filesystem
Software Requirements¶
- Operating System: Ubuntu 20.04 LTS / CentOS 8 / RHEL 8
- Container Runtime: Docker 20.10+ or Podman 3.0+
- Orchestration: Kubernetes 1.20+ or Docker Swarm
- Database: PostgreSQL 13+ or MongoDB 5.0+
- Cache: Redis 6.0+
- Load Balancer: HAProxy 2.4+ or NGINX 1.20+
Server Preparation¶
Operating System Setup¶
Ubuntu 20.04 LTS¶
# Update system
sudo apt update && sudo apt upgrade -y
# Install essential packages
sudo apt install -y curl wget git unzip htop iotop nethogs
# Configure firewall
sudo ufw enable
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 8080/tcp
# Disable swap for Kubernetes
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
CentOS 8 / RHEL 8¶
# Update system
sudo dnf update -y
# Install essential packages
sudo dnf install -y curl wget git unzip htop iotop
# Configure firewall
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
# Disable SELinux (for Kubernetes)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
Docker Installation¶
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Add user to docker group
sudo usermod -aG docker $USER
# Enable and start Docker
sudo systemctl enable docker
sudo systemctl start docker
# Configure Docker daemon
sudo mkdir -p /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
sudo systemctl restart docker
Single Server Deployment¶
Docker Compose Setup¶
Create a docker-compose.yml
file:
version: '3.8'
services:
nexus:
image: nexus/nexus:latest
container_name: nexus
restart: unless-stopped
ports:
- "8080:8080"
environment:
- NODE_ENV=production
- DB_HOST=postgres
- DB_PORT=5432
- DB_NAME=nexus
- DB_USERNAME=nexus
- DB_PASSWORD=${DB_PASSWORD}
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD}
volumes:
- nexus_data:/app/data
- nexus_logs:/app/logs
- ./config:/app/config:ro
depends_on:
- postgres
- redis
networks:
- nexus_network
postgres:
image: postgres:15
container_name: nexus_postgres
restart: unless-stopped
environment:
- POSTGRES_DB=nexus
- POSTGRES_USER=nexus
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./backups:/backups
ports:
- "5432:5432"
networks:
- nexus_network
redis:
image: redis:7-alpine
container_name: nexus_redis
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
ports:
- "6379:6379"
networks:
- nexus_network
nginx:
image: nginx:alpine
container_name: nexus_nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- nginx_logs:/var/log/nginx
depends_on:
- nexus
networks:
- nexus_network
volumes:
nexus_data:
nexus_logs:
postgres_data:
redis_data:
nginx_logs:
networks:
nexus_network:
driver: bridge
Environment Configuration¶
Create a .env
file:
# Database configuration
DB_PASSWORD=your_secure_database_password_here
# Redis configuration
REDIS_PASSWORD=your_secure_redis_password_here
# Application configuration
NEXUS_SECRET_KEY=your_application_secret_key_here
JWT_SECRET=your_jwt_secret_key_here
# External services
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=nexus@example.com
SMTP_PASSWORD=your_smtp_password_here
NGINX Configuration¶
Create nginx.conf
:
events {
worker_connections 1024;
}
http {
upstream nexus_backend {
server nexus:8080;
}
server {
listen 80;
server_name nexus.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name nexus.example.com;
ssl_certificate /etc/nginx/ssl/nexus.crt;
ssl_certificate_key /etc/nginx/ssl/nexus.key;
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;
ssl_prefer_server_ciphers off;
client_max_body_size 100M;
location / {
proxy_pass http://nexus_backend;
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;
}
location /health {
proxy_pass http://nexus_backend/health;
access_log off;
}
}
}
Start the Stack¶
# Create necessary directories
mkdir -p config ssl backups
# Generate SSL certificates (self-signed for testing)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout ssl/nexus.key \
-out ssl/nexus.crt \
-subj "/C=US/ST=CA/L=San Francisco/O=Nexus/CN=nexus.example.com"
# Start services
docker-compose up -d
# Check status
docker-compose ps
High Availability Deployment¶
Multi-Server Architecture¶
┌─────────────────┐ ┌─────────────────┐
│ Load Balancer │ │ Load Balancer │
│ (HAProxy) │ │ (HAProxy) │
│ Primary │ │ Backup │
└─────────┬───────┘ └─────────┬───────┘
│ │
└──────────┬───────────┘
│
┌───────────┴───────────┐
│ │
┌────────▼────────┐ ┌─────────▼────────┐ ┌─────────────────┐
│ Application │ │ Application │ │ Application │
│ Server 1 │ │ Server 2 │ │ Server 3 │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
└───────────┬───────────┴───────────┬───────────┘
│ │
┌───────────▼───────────┐ ┌──────▼──────────────┐
│ Database Cluster │ │ Redis Cluster │
│ (PostgreSQL) │ │ │
└───────────────────────┘ └─────────────────────┘
HAProxy Load Balancer Setup¶
Install HAProxy¶
Configure HAProxy¶
Edit /etc/haproxy/haproxy.cfg
:
global
log 127.0.0.1:514 local0
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
mode http
log global
option httplog
option dontlognull
option log-health-checks
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend nexus_frontend
bind *:80
bind *:443 ssl crt /etc/ssl/certs/nexus.pem
redirect scheme https if !{ ssl_fc }
default_backend nexus_servers
backend nexus_servers
balance roundrobin
option httpchk GET /health
http-check expect status 200
server app1 10.0.1.10:8080 check
server app2 10.0.1.11:8080 check
server app3 10.0.1.12:8080 check
listen stats
bind *:8404
stats enable
stats uri /stats
stats refresh 30s
stats admin if TRUE
Database Cluster Setup¶
PostgreSQL with Streaming Replication¶
Primary Server Configuration¶
# Install PostgreSQL
sudo apt install -y postgresql-15 postgresql-contrib-15
# Configure PostgreSQL
sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'secure_password';"
sudo -u postgres createuser -s nexus
sudo -u postgres createdb nexus -O nexus
# Edit postgresql.conf
sudo nano /etc/postgresql/15/main/postgresql.conf
Add to postgresql.conf
:
listen_addresses = '*'
wal_level = replica
max_wal_senders = 3
max_replication_slots = 3
synchronous_commit = on
synchronous_standby_names = 'standby1,standby2'
Edit pg_hba.conf
:
Replica Server Configuration¶
# Stop PostgreSQL
sudo systemctl stop postgresql
# Remove existing data
sudo rm -rf /var/lib/postgresql/15/main/*
# Create base backup
sudo -u postgres pg_basebackup -h 10.0.1.20 -D /var/lib/postgresql/15/main -U nexus -v -P -W
# Create standby.signal
sudo -u postgres touch /var/lib/postgresql/15/main/standby.signal
# Configure recovery
echo "primary_conninfo = 'host=10.0.1.20 port=5432 user=nexus password=secure_password'" | sudo -u postgres tee /var/lib/postgresql/15/main/postgresql.auto.conf
# Start PostgreSQL
sudo systemctl start postgresql
Redis Cluster Setup¶
Redis Cluster Configuration¶
Create redis.conf
for each node:
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
Start Redis Cluster¶
# Start Redis instances on each server
redis-server /etc/redis/redis.conf
# Create cluster
redis-cli --cluster create \
10.0.1.10:7000 10.0.1.11:7000 10.0.1.12:7000 \
10.0.1.13:7000 10.0.1.14:7000 10.0.1.15:7000 \
--cluster-replicas 1
Monitoring and Logging¶
System Monitoring with Prometheus¶
Install Prometheus¶
# Create prometheus user
sudo useradd --no-create-home --shell /bin/false prometheus
# Download and install
wget https://github.com/prometheus/prometheus/releases/download/v2.40.0/prometheus-2.40.0.linux-amd64.tar.gz
tar xzf prometheus-2.40.0.linux-amd64.tar.gz
sudo cp prometheus-2.40.0.linux-amd64/prometheus /usr/local/bin/
sudo cp prometheus-2.40.0.linux-amd64/promtool /usr/local/bin/
sudo chown prometheus:prometheus /usr/local/bin/prometheus
sudo chown prometheus:prometheus /usr/local/bin/promtool
# Create directories
sudo mkdir /etc/prometheus
sudo mkdir /var/lib/prometheus
sudo chown prometheus:prometheus /etc/prometheus
sudo chown prometheus:prometheus /var/lib/prometheus
Configure Prometheus¶
Create /etc/prometheus/prometheus.yml
:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'nexus'
static_configs:
- targets: ['10.0.1.10:8080', '10.0.1.11:8080', '10.0.1.12:8080']
- job_name: 'node'
static_configs:
- targets: ['10.0.1.10:9100', '10.0.1.11:9100', '10.0.1.12:9100']
- job_name: 'postgres'
static_configs:
- targets: ['10.0.1.20:9187']
- job_name: 'redis'
static_configs:
- targets: ['10.0.1.30:9121']
Log Management with ELK Stack¶
Elasticsearch Installation¶
# Install Java
sudo apt install -y openjdk-11-jdk
# Add Elasticsearch repository
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
echo "deb https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
# Install Elasticsearch
sudo apt update
sudo apt install -y elasticsearch
# Configure Elasticsearch
sudo nano /etc/elasticsearch/elasticsearch.yml
Add to elasticsearch.yml
:
cluster.name: nexus-logs
node.name: node-1
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 0.0.0.0
http.port: 9200
discovery.type: single-node
Backup and Disaster Recovery¶
Database Backup Strategy¶
Automated Backup Script¶
Create /opt/scripts/backup.sh
:
#!/bin/bash
BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d_%H%M%S)
DB_NAME="nexus"
DB_USER="nexus"
# Create backup directory
mkdir -p $BACKUP_DIR
# Database backup
pg_dump -h localhost -U $DB_USER $DB_NAME | gzip > $BACKUP_DIR/nexus_db_$DATE.sql.gz
# Redis backup
redis-cli --rdb $BACKUP_DIR/redis_$DATE.rdb
# Application data backup
tar -czf $BACKUP_DIR/nexus_data_$DATE.tar.gz /opt/nexus/data
# Clean old backups (keep 7 days)
find $BACKUP_DIR -name "*.gz" -mtime +7 -delete
find $BACKUP_DIR -name "*.rdb" -mtime +7 -delete
echo "Backup completed: $DATE"
Schedule Backups¶
# Add to crontab
crontab -e
# Add this line for daily backups at 2 AM
0 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
Disaster Recovery Procedures¶
Database Recovery¶
# Stop application
docker-compose stop nexus
# Restore database
gunzip -c /backups/nexus_db_20240101_020000.sql.gz | psql -h localhost -U nexus nexus
# Restore Redis
redis-cli --rdb /backups/redis_20240101_020000.rdb
# Restore application data
tar -xzf /backups/nexus_data_20240101_020000.tar.gz -C /
# Start application
docker-compose start nexus
Security Hardening¶
Firewall Configuration¶
# Install and configure UFW
sudo ufw --force reset
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH
sudo ufw allow ssh
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Allow application ports (from specific networks)
sudo ufw allow from 10.0.1.0/24 to any port 8080
sudo ufw allow from 10.0.1.0/24 to any port 5432
sudo ufw allow from 10.0.1.0/24 to any port 6379
# Enable firewall
sudo ufw enable
SSL/TLS Configuration¶
Generate Production Certificates¶
# Install Certbot
sudo apt install -y certbot
# Generate Let's Encrypt certificate
sudo certbot certonly --standalone -d nexus.example.com
# Configure automatic renewal
echo "0 12 * * * /usr/bin/certbot renew --quiet" | sudo crontab -
System Hardening¶
SSH configuration:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
Protocol 2
ClientAliveInterval 300
ClientAliveCountMax 2
Performance Optimization¶
System Tuning¶
Kernel Parameters¶
Add to /etc/sysctl.conf
:
# Network performance
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 12582912 16777216
net.ipv4.tcp_wmem = 4096 12582912 16777216
# File descriptor limits
fs.file-max = 2097152
# Virtual memory
vm.swappiness = 10
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
Application Limits¶
Add to /etc/security/limits.conf
:
Database Optimization¶
PostgreSQL Tuning¶
Add to postgresql.conf
:
# Memory settings
shared_buffers = 256MB
effective_cache_size = 1GB
work_mem = 4MB
maintenance_work_mem = 64MB
# Checkpoint settings
checkpoint_completion_target = 0.9
wal_buffers = 16MB
# Query planner
random_page_cost = 1.1
effective_io_concurrency = 200
Troubleshooting¶
Common Issues¶
High CPU Usage¶
# Check top processes
htop
# Check Docker container resources
docker stats
# Check database queries
sudo -u postgres psql nexus -c "SELECT query, state, query_start FROM pg_stat_activity WHERE state = 'active';"
Memory Issues¶
# Check memory usage
free -h
# Check swap usage
swapon -s
# Clear page cache if needed
sudo sysctl vm.drop_caches=3
Network Issues¶
# Check network connections
netstat -tulpn
# Check firewall status
sudo ufw status
# Test connectivity
telnet nexus.example.com 443