Kulcare Docs
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-release

2. 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 - kulcare

3. 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_keys

Ruby 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-build

2. 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 -v

3. Install Bundler

gem install bundler
rbenv rehash

Database 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 postgresql

2. 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
\q

3. Configure PostgreSQL Settings

# Edit postgresql.conf
sudo nano /etc/postgresql/14/main/postgresql.conf

Add/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 = 0

4. Configure pg_hba.conf

# Edit pg_hba.conf
sudo nano /etc/postgresql/14/main/pg_hba.conf

Add 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 postgresql

Redis Setup

1. Install Redis

# Install Redis
sudo apt install -y redis-server

# Start and enable Redis
sudo systemctl start redis
sudo systemctl enable redis

2. Configure Redis

# Edit Redis configuration
sudo nano /etc/redis/redis.conf

Key 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 redis

Elasticsearch 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 elasticsearch

2. Configure Elasticsearch

# Edit Elasticsearch configuration
sudo nano /etc/elasticsearch/elasticsearch.yml

Key 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-node

3. Configure Elasticsearch JVM

# Edit JVM options
sudo nano /etc/elasticsearch/jvm.options

Set heap size (half of available RAM):

-Xms2g
-Xmx2g

4. 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-backend

2. 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 test

3. Setup Environment Configuration

# Create production environment file
cp .env.example .env.production

# Edit environment variables
nano .env.production

See 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_indices

5. Precompile Assets (if needed)

# Precompile assets
RAILS_ENV=production bundle exec rake assets:precompile

Web Server Setup (Nginx)

1. Install Nginx

# Install Nginx
sudo apt install -y nginx

# Start and enable Nginx
sudo systemctl start nginx
sudo systemctl enable nginx

2. Configure Nginx

# Create Nginx configuration
sudo nano /etc/nginx/sites-available/kulcare-api-backend
upstream 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 nginx

Process 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.target

2. 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.target

3. 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-production

SSL 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 -e

Add this line for auto-renewal:

0 12 * * * /usr/bin/certbot renew --quiet

Monitoring 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 grep
chmod +x /home/kulcare/monitor.sh

Backup 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 -e

Add this line:

0 2 * * * /home/kulcare/backup_database.sh >> /var/log/backup.log 2>&1

Security 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 status

2. 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 fail2ban

Post-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 grep

2. 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/health

Maintenance 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-production

2. 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 -delete

Troubleshooting

Common Issues

  1. Puma not starting

    # Check logs
    journalctl -u puma-production -f
    
    # Check socket permissions
    ls -la /var/www/kulcare-api-backend/tmp/sockets/
  2. Database connection issues

    # Test connection
    sudo -u kulcare psql kulcare_production
    
    # Check PostgreSQL logs
    sudo tail -f /var/log/postgresql/postgresql-14-main.log
  3. Elasticsearch issues

    # Check Elasticsearch status
    curl localhost:9200/_cat/health
    
    # Check logs
    sudo tail -f /var/log/elasticsearch/kulcare-production.log

Next Steps

On this page