General06 deployment
Production Server Setup
This guide covers the complete setup of production servers for the Kulcare API Backend application.
Server Requirements
Minimum Hardware Requirements
Application Server
- CPU: 4 cores (8 recommended)
- RAM: 8GB (16GB recommended)
- Storage: 100GB SSD
- Network: 1Gbps connection
Database Server
- CPU: 4 cores (8 recommended)
- RAM: 16GB (32GB recommended)
- Storage: 500GB SSD with backup
- Network: 1Gbps connection
Cache/Search Server
- CPU: 2 cores (4 recommended)
- RAM: 8GB (16GB recommended)
- Storage: 100GB SSD
- Network: 1Gbps connection
Operating System
- OS: Ubuntu 20.04 LTS or higher
- Kernel: Latest stable version
- Architecture: x86_64
Initial Server Setup
1. Update System Packages
# Update package index
sudo apt update && sudo apt upgrade -y
# Install essential packages
sudo apt install -y curl wget gnupg2 software-properties-common apt-transport-https ca-certificates lsb-release2. Create Application User
# Create kulcare user
sudo adduser kulcare --disabled-password --gecos ""
# Add to sudo group (if needed)
sudo usermod -aG sudo kulcare
# Switch to kulcare user
sudo su - kulcare3. Setup SSH Keys
# Generate SSH keys for deployment
ssh-keygen -t rsa -b 4096 -C "deploy@kulcare.com"
# Add to authorized_keys for GitHub access
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keysRuby Environment Setup
1. Install rbenv
# Install rbenv
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
source ~/.bashrc
# Install ruby-build
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build2. Install Ruby
# Install Ruby dependencies
sudo apt install -y build-essential libssl-dev libreadline-dev zlib1g-dev libffi-dev
# Install Ruby 3.2.0
rbenv install 3.2.0
rbenv global 3.2.0
# Verify installation
ruby -v
gem -v3. Install Bundler
gem install bundler
rbenv rehashDatabase Setup (PostgreSQL)
1. Install PostgreSQL
# Add PostgreSQL APT repository
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
# Install PostgreSQL
sudo apt update
sudo apt install -y postgresql-14 postgresql-client-14 postgresql-contrib-14
# Start and enable PostgreSQL
sudo systemctl start postgresql
sudo systemctl enable postgresql2. Configure PostgreSQL
# Switch to postgres user
sudo -u postgres psql
-- In PostgreSQL prompt:
-- Create kulcare database and user
CREATE USER kulcare WITH PASSWORD 'secure_password_here';
CREATE DATABASE kulcare_production OWNER kulcare;
GRANT ALL PRIVILEGES ON DATABASE kulcare_production TO kulcare;
-- Enable necessary extensions
\c kulcare_production;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
-- Exit PostgreSQL
\q3. Configure PostgreSQL Settings
# Edit postgresql.conf
sudo nano /etc/postgresql/14/main/postgresql.confAdd/modify these settings:
# Memory settings
shared_buffers = 256MB
effective_cache_size = 1GB
maintenance_work_mem = 64MB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
# Connection settings
max_connections = 200
listen_addresses = 'localhost'
# Logging
log_line_prefix = '%t [%p-%l] %q%u@%d '
log_checkpoints = on
log_connections = on
log_disconnections = on
log_lock_waits = on
log_temp_files = 04. Configure pg_hba.conf
# Edit pg_hba.conf
sudo nano /etc/postgresql/14/main/pg_hba.confAdd this line for local connections:
local kulcare_production kulcare md5
host kulcare_production kulcare 127.0.0.1/32 md5# Restart PostgreSQL
sudo systemctl restart postgresqlRedis Setup
1. Install Redis
# Install Redis
sudo apt install -y redis-server
# Start and enable Redis
sudo systemctl start redis
sudo systemctl enable redis2. Configure Redis
# Edit Redis configuration
sudo nano /etc/redis/redis.confKey settings:
# Memory management
maxmemory 2gb
maxmemory-policy allkeys-lru
# Persistence
save 900 1
save 300 10
save 60 10000
# Security
requirepass your_redis_password_here
bind 127.0.0.1
# Logging
loglevel notice
logfile /var/log/redis/redis-server.log# Restart Redis
sudo systemctl restart redisElasticsearch Setup
1. Install Elasticsearch 6.2.4
# Add Elasticsearch repository
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
echo "deb https://artifacts.elastic.co/packages/6.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-6.x.list
# Install Elasticsearch 6.2.4
sudo apt update
sudo apt install elasticsearch=6.2.4
# Prevent auto-updates
sudo apt-mark hold elasticsearch2. Configure Elasticsearch
# Edit Elasticsearch configuration
sudo nano /etc/elasticsearch/elasticsearch.ymlKey settings:
# Cluster settings
cluster.name: kulcare-production
node.name: kulcare-es-node-1
# Network settings
network.host: localhost
http.port: 9200
# Memory settings
bootstrap.memory_lock: true
# Data paths
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
# Discovery settings
discovery.type: single-node3. Configure Elasticsearch JVM
# Edit JVM options
sudo nano /etc/elasticsearch/jvm.optionsSet heap size (half of available RAM):
-Xms2g
-Xmx2g4. Start Elasticsearch
# Enable and start Elasticsearch
sudo systemctl daemon-reload
sudo systemctl enable elasticsearch
sudo systemctl start elasticsearch
# Verify installation
curl -X GET "localhost:9200/"Application Deployment
1. Create Application Directory
# Create application directory
sudo mkdir -p /var/www/kulcare-api-backend
sudo chown kulcare:kulcare /var/www/kulcare-api-backend
# Switch to application directory
cd /var/www/kulcare-api-backend2. Clone Application
# Clone repository
git clone https://github.com/your-org/kulcare-api-backend.git .
git checkout master
# Install dependencies
bundle install --deployment --without development test3. Setup Environment Configuration
# Create production environment file
cp .env.example .env.production
# Edit environment variables
nano .env.productionSee Environment Configuration for detailed settings.
4. Database Setup
# Run database migrations
RAILS_ENV=production bundle exec rake db:create
RAILS_ENV=production bundle exec rake db:migrate
# Setup Elasticsearch indices
RAILS_ENV=production bundle exec rake es:create_all_indices5. Precompile Assets (if needed)
# Precompile assets
RAILS_ENV=production bundle exec rake assets:precompileWeb Server Setup (Nginx)
1. Install Nginx
# Install Nginx
sudo apt install -y nginx
# Start and enable Nginx
sudo systemctl start nginx
sudo systemctl enable nginx2. Configure Nginx
# Create Nginx configuration
sudo nano /etc/nginx/sites-available/kulcare-api-backendupstream kulcare_backend {
server unix:///var/www/kulcare-api-backend/tmp/sockets/puma.sock;
}
server {
listen 80;
server_name api.kulcare.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name api.kulcare.com;
# SSL Configuration
ssl_certificate /etc/ssl/certs/kulcare.crt;
ssl_certificate_key /etc/ssl/private/kulcare.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384;
root /var/www/kulcare-api-backend/public;
index index.html;
# Request size limits
client_max_body_size 20M;
client_body_timeout 300s;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
# API endpoints
location / {
try_files $uri @kulcare_backend;
}
location @kulcare_backend {
proxy_pass http://kulcare_backend;
proxy_set_header Host $http_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;
}
# Static files
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# Error pages
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/kulcare-api-backend/public;
}
}3. Enable Nginx Site
# Enable site
sudo ln -s /etc/nginx/sites-available/kulcare-api-backend /etc/nginx/sites-enabled/
# Test configuration
sudo nginx -t
# Restart Nginx
sudo systemctl restart nginxProcess Management (Systemd)
1. Puma Service Configuration
# Create Puma systemd service
sudo nano /etc/systemd/system/puma-production.service[Unit]
Description=Puma HTTP Server (Production)
After=network.target postgresql.service redis.service
[Service]
Type=forking
User=kulcare
WorkingDirectory=/var/www/kulcare-api-backend
Environment=RAILS_ENV=production
Environment=RACK_ENV=production
# Puma configuration
ExecStart=/home/kulcare/.rbenv/shims/bundle exec puma -C config/puma.rb --daemon
ExecReload=/bin/kill -USR1 $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
PIDFile=/var/www/kulcare-api-backend/tmp/pids/puma.pid
# Restart policy
Restart=always
RestartSec=10
# Resource limits
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target2. Sidekiq Service Configuration
# Create Sidekiq systemd service
sudo nano /etc/systemd/system/sidekiq-production.service[Unit]
Description=Sidekiq Background Jobs (Production)
After=network.target postgresql.service redis.service
[Service]
Type=simple
User=kulcare
WorkingDirectory=/var/www/kulcare-api-backend
Environment=RAILS_ENV=production
Environment=RACK_ENV=production
# Sidekiq configuration
ExecStart=/home/kulcare/.rbenv/shims/bundle exec sidekiq -C config/sidekiq.yml
ExecReload=/bin/kill -USR1 $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
# Restart policy
Restart=always
RestartSec=5
# Resource limits
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target3. Enable and Start Services
# Reload systemd daemon
sudo systemctl daemon-reload
# Enable services
sudo systemctl enable puma-production
sudo systemctl enable sidekiq-production
# Start services
sudo systemctl start puma-production
sudo systemctl start sidekiq-production
# Check status
sudo systemctl status puma-production
sudo systemctl status sidekiq-productionSSL Certificate Setup
1. Install Certbot (Let's Encrypt)
# Install Certbot
sudo apt install -y certbot python3-certbot-nginx
# Obtain SSL certificate
sudo certbot --nginx -d api.kulcare.com
# Set up auto-renewal
sudo crontab -eAdd this line for auto-renewal:
0 12 * * * /usr/bin/certbot renew --quietMonitoring and Logging
1. Configure Log Rotation
# Create logrotate configuration
sudo nano /etc/logrotate.d/kulcare-api-backend/var/www/kulcare-api-backend/log/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 kulcare kulcare
postrotate
/bin/kill -USR1 $(cat /var/www/kulcare-api-backend/tmp/pids/puma.pid) > /dev/null 2>&1
endscript
}2. Setup Process Monitoring
# Install htop for process monitoring
sudo apt install -y htop
# Create monitoring script
nano /home/kulcare/monitor.sh#!/bin/bash
# Monitor critical processes
ps aux | grep -E "(puma|sidekiq|nginx|postgres|redis|elasticsearch)" | grep -v grepchmod +x /home/kulcare/monitor.shBackup Configuration
1. Database Backup Script
# Create backup directory
sudo mkdir -p /var/backups/kulcare
sudo chown kulcare:kulcare /var/backups/kulcare
# Create backup script
nano /home/kulcare/backup_database.sh#!/bin/bash
# Database backup script
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/var/backups/kulcare"
DB_NAME="kulcare_production"
# Create database dump
pg_dump -U kulcare -h localhost $DB_NAME | gzip > $BACKUP_DIR/db_backup_$DATE.sql.gz
# Keep only last 7 days of backups
find $BACKUP_DIR -name "db_backup_*.sql.gz" -mtime +7 -delete
echo "Database backup completed: db_backup_$DATE.sql.gz"chmod +x /home/kulcare/backup_database.sh
# Add to crontab for daily backups
crontab -eAdd this line:
0 2 * * * /home/kulcare/backup_database.sh >> /var/log/backup.log 2>&1Security Configuration
1. Firewall Setup
# Install and configure UFW
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable
# Check firewall status
sudo ufw status2. Fail2Ban Setup
# Install Fail2Ban
sudo apt install -y fail2ban
# Create custom configuration
sudo nano /etc/fail2ban/jail.local[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
[sshd]
enabled = true
[nginx-http-auth]
enabled = true
[nginx-req-limit]
enabled = true
filter = nginx-req-limit
action = iptables-multiport[name=ReqLimit, port="http,https", protocol=tcp]
logpath = /var/log/nginx/*.log
maxretry = 10
findtime = 600
bantime = 7200# Start and enable Fail2Ban
sudo systemctl start fail2ban
sudo systemctl enable fail2banPost-Deployment Verification
1. Service Health Check
# Check all services
sudo systemctl status puma-production
sudo systemctl status sidekiq-production
sudo systemctl status nginx
sudo systemctl status postgresql
sudo systemctl status redis
sudo systemctl status elasticsearch
# Check process list
ps aux | grep -E "(puma|sidekiq|nginx|postgres|redis|elasticsearch)" | grep -v grep2. Application Health Check
# Test API endpoint
curl -k https://api.kulcare.com/health
# Test database connection
RAILS_ENV=production bundle exec rails c
# In Rails console:
ActiveRecord::Base.connection.execute("SELECT 1")
# Test Redis connection
redis-cli ping
# Test Elasticsearch
curl -X GET "localhost:9200/_cluster/health"3. Performance Testing
# Install Apache Bench
sudo apt install -y apache2-utils
# Basic load test
ab -n 100 -c 10 https://api.kulcare.com/healthMaintenance Tasks
1. Regular Updates
# System updates (monthly)
sudo apt update && sudo apt upgrade -y
# Application updates (as needed)
cd /var/www/kulcare-api-backend
git pull origin master
bundle install --deployment
RAILS_ENV=production bundle exec rake db:migrate
sudo systemctl restart puma-production sidekiq-production2. Log Management
# Check log sizes
du -h /var/www/kulcare-api-backend/log/
du -h /var/log/nginx/
du -h /var/log/postgresql/
# Clear old logs if needed
find /var/www/kulcare-api-backend/log/ -name "*.log" -mtime +30 -deleteTroubleshooting
Common Issues
-
Puma not starting
# Check logs journalctl -u puma-production -f # Check socket permissions ls -la /var/www/kulcare-api-backend/tmp/sockets/ -
Database connection issues
# Test connection sudo -u kulcare psql kulcare_production # Check PostgreSQL logs sudo tail -f /var/log/postgresql/postgresql-14-main.log -
Elasticsearch issues
# Check Elasticsearch status curl localhost:9200/_cat/health # Check logs sudo tail -f /var/log/elasticsearch/kulcare-production.log
Next Steps
- Configure Environment Variables
- Setup Background Jobs
- Configure Monitoring
- Review Troubleshooting Guide