Kotchasan Framework Documentation

Kotchasan Framework Documentation

Deployment Guide

EN 06 Feb 2026 13:11

Deployment Guide

This comprehensive guide covers installation, configuration, and optimization of the Kotchasan Framework for production environments.

Table of Contents

  1. System Requirements
  2. Server Installation
  3. Database Configuration
  4. Web Server Configuration
  5. Security Configuration
  6. Performance Optimization
  7. Backup and Recovery
  8. Monitoring and Troubleshooting

System Requirements

Minimum Requirements

Server:
- CPU: 1 Core 2.0 GHz
- RAM: 512 MB
- Storage: 1 GB SSD
- Bandwidth: 10 GB/month

Software:
- PHP 7.4 or higher
- MySQL 5.7 or MariaDB 10.2
- Apache 2.4 or Nginx 1.16
- SSL Certificate (recommended)
Server:
- CPU: 2 Cores 2.4 GHz or higher
- RAM: 2 GB or more
- Storage: 20 GB SSD
- Bandwidth: 100 GB/month

Software:
- PHP 8.1 or higher
- MySQL 8.0 or MariaDB 10.6
- Apache 2.4 or Nginx 1.20
- SSL Certificate
- Redis (for caching)
- Elasticsearch (for search)

Required PHP Extensions

Essential:
- mbstring
- openssl
- PDO
- pdo_mysql
- curl
- gd
- zip
- xml
- json

Recommended:
- opcache
- redis
- memcached
- imagick
- intl

Server Installation

1. Ubuntu/Debian Installation

# Update packages
sudo apt update && sudo apt upgrade -y

# Install Apache, MySQL, PHP
sudo apt install apache2 mysql-server php8.1 php8.1-mysql php8.1-cli php8.1-common php8.1-mbstring php8.1-gd php8.1-curl php8.1-zip php8.1-xml -y

# Enable PHP modules
sudo a2enmod php8.1
sudo a2enmod rewrite
sudo a2enmod ssl
sudo a2enmod headers

# Restart Apache
sudo systemctl restart apache2

# Enable services
sudo systemctl enable apache2
sudo systemctl enable mysql

2. Composer Installation

# Download and install Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
sudo chmod +x /usr/local/bin/composer

# Verify installation
composer --version

3. Kotchasan Framework Installation

# Create project directory
sudo mkdir -p /var/www/html/myproject
cd /var/www/html/myproject

# Clone or download Framework (recommended)
git clone https://github.com/kotchasan/kotchasan.git .

# Or use Composer
composer create-project kotchasan/kotchasan .

# Set permissions
sudo chown -R www-data:www-data /var/www/html/myproject
sudo chmod -R 755 /var/www/html/myproject
sudo chmod -R 777 /var/www/html/myproject/datas
sudo chmod -R 777 /var/www/html/myproject/tmp

4. Virtual Host Configuration

# /etc/apache2/sites-available/myproject.conf
<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    DocumentRoot /var/www/html/myproject

    <Directory /var/www/html/myproject>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/myproject_error.log
    CustomLog ${APACHE_LOG_DIR}/myproject_access.log combined

    # Redirect to HTTPS
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

<VirtualHost *:443>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    DocumentRoot /var/www/html/myproject

    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/yourdomain.crt
    SSLCertificateKeyFile /etc/ssl/private/yourdomain.key
    SSLCertificateChainFile /etc/ssl/certs/intermediate.crt

    <Directory /var/www/html/myproject>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    # Security Headers
    Header always set X-Frame-Options DENY
    Header always set X-Content-Type-Options nosniff
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

    ErrorLog ${APACHE_LOG_DIR}/myproject_ssl_error.log
    CustomLog ${APACHE_LOG_DIR}/myproject_ssl_access.log combined
</VirtualHost>
# Enable site
sudo a2ensite myproject.conf
sudo systemctl reload apache2

Database Configuration

1. Database Creation

-- Connect to MySQL
mysql -u root -p

-- Create database
CREATE DATABASE kotchasan_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Create user
CREATE USER 'kotchasan_user'@'localhost' IDENTIFIED BY 'strong_password_here';

-- Grant privileges
GRANT ALL PRIVILEGES ON kotchasan_db.* TO 'kotchasan_user'@'localhost';
FLUSH PRIVILEGES;

-- Exit MySQL
EXIT;

2. Configuration File Setup

// settings/config.php

return [
    'version' => '1.0.0',
    'web_title' => 'My Website',
    'web_description' => 'Description of my website',
    'timezone' => 'Asia/Bangkok',

    // Kotchasan\Database Configuration
    'db' => [
        'hostname' => 'localhost',
        'username' => 'kotchasan_user',
        'password' => 'strong_password_here',
        'dbname' => 'kotchasan_db',
        'prefix' => 'app_'
    ],

    // Cache Configuration
    'cache' => [
        'driver' => 'file', // file, redis, memcached
        'path' => ROOT_PATH.'datas/cache/',
        'prefix' => 'kotchasan_',
        'default_ttl' => 3600
    ],

    // Session Configuration
    'session' => [
        'name' => 'KOTCHASAN_SESSION',
        'lifetime' => 3600,
        'path' => '/',
        'domain' => '',
        'secure' => true,
        'httponly' => true,
        'samesite' => 'Strict'
    ],

    // Security Configuration
    'security' => [
        'encryption_key' => 'your-32-character-secret-key-here',
        'password_min_length' => 8,
        'max_login_attempts' => 5,
        'lockout_duration' => 900, // 15 minutes
        'csrf_protection' => true
    ]
];

3. Database Performance Optimization

-- my.cnf or mysqld.cnf configuration
[mysqld]
# General Settings
default-storage-engine = InnoDB
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

# Performance Settings
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT

# Query Cache
query_cache_type = 1
query_cache_size = 128M
query_cache_limit = 32M

# Connection Settings
max_connections = 200
max_connect_errors = 10000
wait_timeout = 28800
interactive_timeout = 28800

# Slow Query Log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

Web Server Configuration

1. Apache Configuration

# .htaccess
RewriteEngine On

# Force HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Remove www (or add www as needed)
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

# Main Routing
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?_route=$1 [QSA,L]

# Security Rules
RewriteCond %{THE_REQUEST} [A-Z]{3,}\s/+([^\s]*)\s [NC]
RewriteRule ^(.*)$ - [F,L]

# Block sensitive files
<FilesMatch "\.(htaccess|htpasswd|ini|log|sh|sql|conf)$">
    Require all denied
</FilesMatch>

# Block access to includes directory
RedirectMatch 403 ^/includes/.*$
RedirectMatch 403 ^/settings/.*$
RedirectMatch 403 ^/Kotchasan/.*$

# Security Headers
<IfModule mod_headers.c>
    Header always set X-Frame-Options "DENY"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
</IfModule>

# Compression
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript
</IfModule>

# Caching
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpg "access plus 1 month"
    ExpiresByType image/jpeg "access plus 1 month"
    ExpiresByType image/gif "access plus 1 month"
    ExpiresByType image/png "access plus 1 month"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/pdf "access plus 1 month"
    ExpiresByType text/javascript "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType application/x-javascript "access plus 1 month"
    ExpiresByType application/x-shockwave-flash "access plus 1 month"
    ExpiresByType image/x-icon "access plus 1 year"
    ExpiresDefault "access plus 2 days"
</IfModule>

2. Nginx Configuration

# /etc/nginx/sites-available/myproject
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://yourdomain.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name www.yourdomain.com;
    return 301 https://yourdomain.com$request_uri;

    ssl_certificate /etc/ssl/certs/yourdomain.crt;
    ssl_certificate_key /etc/ssl/private/yourdomain.key;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com;
    root /var/www/html/myproject;
    index index.php index.html;

    # SSL Configuration
    ssl_certificate /etc/ssl/certs/yourdomain.crt;
    ssl_certificate_key /etc/ssl/private/yourdomain.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;

    # Security Headers
    add_header X-Frame-Options "DENY" 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 Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Gzip Compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;

    # Main location
    location / {
        try_files $uri $uri/ @rewrite;
    }

    location @rewrite {
        rewrite ^(.+)$ /index.php?_route=$1 last;
    }

    # PHP handler
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;

        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
        fastcgi_busy_buffers_size 256k;
    }

    # Static files caching
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|zip)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # Block sensitive files
    location ~* \.(htaccess|htpasswd|ini|log|sh|sql|conf)$ {
        deny all;
    }

    location /settings/ { deny all; }
    location /Kotchasan/ { deny all; }
    location /includes/ { deny all; }
}

Security Configuration

1. Brute Force Protection

// modules/security/models/bruteforce.php

class BruteForceProtection
{
    private $maxAttempts = 5;
$lockoutTime = 90; // 0; // 15 minutes

    public function checkAttempts($ip)
    {
        $attempts = $this->getAttempts($ip);

        if ($attempts >= $this->maxAttempts) {
            $lastAttempt = $this->getLastAttemptTime($ip);

            if (time() - $lastAttempt < $this->lockoutTime) {
                return false; // Still locked out
            } else {
                $this->clearAttempts($ip); // Reset attempts
            }
        }

        return true;
    }

    public function recordFailedAttempt($ip)
    {
        $this->db()->createQuery()
            ->insert('login_attempts', [
                'ip_address' => $ip,
                'attempted_at' => date('Y-m-d H:i:s'),
                'success' => 0
            ])
            ->execute();
    }

    public function recordSuccessfulLogin($ip)
    {
        $this->clearAttempts($ip);

        $this->db()->createQuery()
            ->insert('login_attempts', [
                'ip_address' => $ip,
                'attempted_at' => date('Y-m-d H:i:s'),
                'success' => 1
            ])
            ->execute();
    }

    private function getAttempts($ip)
    {
        return $this->db()->createQuery()
            ->from('login_attempts')
            ->where(['ip_address', $ip])
            ->andWhere(['success', 0])
            ->andWhere(['attempted_at', '>', date('Y-m-d H:i:s', time() - $this->lockoutTime)])
            ->count();
    }
}

2. CSRF Protection

// Kotchasan/Csrf.php

class Csrf
{
    public static function generateToken()
    {
        if (empty($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }

        return $_SESSION['csrf_token'];
    }

    public static function validateToken($token)
    {
        if (empty($_SESSION['csrf_token']) || empty($token)) {
            return false;
        }

        return hash_equals($_SESSION['csrf_token'], $token);
    }

    public static function getTokenField()
    {
        $token = self::generateToken();
        return '<input type="hidden" name="_token" value="'.$token.'">';
    }
}

3. Data Encryption

// Kotchasan/Encryption.php

class Encryption
{
    private $key;
    private $cipher = 'AES-256-CBC';

    public function __construct($key)
    {
        $this->key = hash('sha256', $key, true);
    }

    public function encrypt($data)
    {
        $iv = random_bytes(16);
        $encrypted = openssl_encrypt($data, $this->cipher, $this->key, 0, $iv);

        return base64_encode($iv . $encrypted);
    }

    public function decrypt($data)
    {
        $data = base64_decode($data);
        $iv = substr($data, 0, 16);
        $encrypted = substr($data, 16);

        return openssl_decrypt($encrypted, $this->cipher, $this->key, 0, $iv);
    }
}

Performance Optimization

1. Redis Cache Implementation

// Kotchasan/Cache/Redis.php

class RedisCache
{
    private $redis;
    private $prefix;

    public function __construct($config)
    {
        $this->redis = new Redis();
        $this->redis->connect($config['host'], $config['port']);

        if (!empty($config['password'])) {
            $this->redis->auth($config['password']);
        }

        $this->prefix = $config['prefix'] ?? 'kotchasan:';
    }

    public function get($key)
    {
        $data = $this->redis->get($this->prefix . $key);
        return $data ? unserialize($data) : null;
    }

$ttl = 360; // 0)
    {
        return $this->redis->setex($this->prefix . $key, $ttl, serialize($value));
    }

    public function delete($key)
    {
        return $this->redis->del($this->prefix . $key);
    }

    public function flush()
    {
        $keys = $this->redis->keys($this->prefix . '*');
        if (!empty($keys)) {
            return $this->redis->del($keys);
        }
        return true;
    }
}

2. OPcache Configuration

; php.ini configuration
[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.max_wasted_percentage=5
opcache.use_cwd=1
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.save_comments=1
opcache.fast_shutdown=1

3. Asset Compression and Caching

// modules/system/controllers/assets.php

class AssetsController
{
    public function css($files)
    {
        $cacheFile = 'datas/cache/css/' . md5(implode(',', $files)) . '.css';

        if (!file_exists($cacheFile) || $this->isModified($files, $cacheFile)) {
            $content = '';

            foreach ($files as $file) {
                if (file_exists($file)) {
                    $content .= file_get_contents($file) . "\n";
                }
            }

            // Minify CSS
            $content = $this->minifyCSS($content);

            // Save to cache
            file_put_contents($cacheFile, $content);
        }

        header('Content-Type: text/css');
        header('Cache-Control: public, max-age=31536000');
        readfile($cacheFile);
    }

    private function minifyCSS($css)
    {
        // Remove comments
        $css = preg_replace('!/\[^]\+([^/][^]\+)/!', '', $css);

        // Remove whitespace
        $css = str_replace(["\r\n", "\r", "\n", "\t", '  ', '    ', '    '], '', $css);

        return $css;
    }
}

Backup and Recovery

1. Automated Backup Script

#!/bin/bash
# backup.sh

# Configuration
DB_NAME="kotchasan_db"
DB_USER="kotchasan_user"
DB_PASS="strong_password_here"
BACKUP_DIR="/backup/kotchasan"
WEB_DIR="/var/www/html/myproject"
DATE=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Database backup
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_DIR/db_$DATE.sql.gz

# Files backup
tar -czf $BACKUP_DIR/files_$DATE.tar.gz -C $WEB_DIR datas/ uploads/ settings/

# Keep only last 7 days of backups
find $BACKUP_DIR -name "*.gz" -mtime +7 -delete

# Log backup
echo "$(date): Backup completed successfully" >> $BACKUP_DIR/backup.log

2. Cron Job Setup

# Edit crontab
crontab -e

# Add this line for daily backup at 2:00 AM
0 2 * * * /path/to/backup.sh

# Database backup every 6 hours
0 */6 * * * mysqldump -u kotchasan_user -p'password' kotchasan_db | gzip > /backup/db_$(date +\%Y\%m\%d_\%H\%M\%S).sql.gz

3. Recovery Script

#!/bin/bash
# restore.sh

# Configuration
DB_NAME="kotchasan_db"
DB_USER="kotchasan_user"
DB_PASS="strong_password_here"
WEB_DIR="/var/www/html/myproject"

# Restore database
echo "Restoring database..."
gunzip < $1 | mysql -u$DB_USER -p$DB_PASS $DB_NAME

# Restore files
echo "Restoring files..."
tar -xzf $2 -C $WEB_DIR

# Fix permissions
chown -R www-data:www-data $WEB_DIR
chmod -R 755 $WEB_DIR
chmod -R 777 $WEB_DIR/datas
chmod -R 777 $WEB_DIR/tmp

echo "Restore completed successfully"

Monitoring and Troubleshooting

1. Debug Mode Configuration

// settings/config.php

return [
    'debug' => true, // Enable only during development
    'log_level' => 'debug',
    'log_file' => ROOT_PATH.'datas/logs/app.log',

    // Error reporting
    'error_reporting' => E_ALL,
    'display_errors' => true, // Disable in production
];

2. Log Monitoring

# Monitor Apache error log
sudo tail -f /var/log/apache2/myproject_error.log

# Monitor MySQL slow query log
sudo tail -f /var/log/mysql/slow.log

# Monitor Application log
tail -f /var/www/html/myproject/datas/logs/app.log

# Monitor System log
sudo tail -f /var/log/syslog

3. Performance Monitoring

// modules/system/performance.php

class PerformanceMonitor
{
    private $startTime;
    private $startMemory;

    public function start()
    {
        $this->startTime = microtime(true);
        $this->startMemory = memory_get_usage();
    }

    public function end()
    {
        $endTime = microtime(true);
        $endMemory = memory_get_usage();

        $executionTime = $endTime - $this->startTime;
        $memoryUsage = $endMemory - $this->startMemory;

        error_log("Execution Time: " . number_format($executionTime, 4) . " seconds");
        error_log("Memory Usage: " . number_format($memoryUsage / 1024 / 1024, 2) . " MB");
        error_log("Peak Memory: " . number_format(memory_get_peak_usage() / 1024 / 1024, 2) . " MB");
    }
}

4. System Health Checks

# Test database connection
mysql -u kotchasan_user -p kotchasan_db -e "SELECT 1"

# Check PHP configuration
php -i | grep -E "(memory_limit|max_execution_time|upload_max_filesize)"

# Test file write permissions
touch /var/www/html/myproject/datas/test.txt && rm /var/www/html/myproject/datas/test.txt

# Test SSL certificate
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com

# Test page load speed
curl -w "@curl-format.txt" -o /dev/null -s "https://yourdomain.com"

5. Common Issue Troubleshooting

Issue: 500 Internal Server Error
Solution:
- Check error logs
- Verify file permissions
- Check .htaccess syntax

Issue: Database connection failed
Solution:
- Verify database credentials
- Check MySQL service status
- Check firewall settings

Issue: Slow page loading
Solution:
- Enable caching
- Optimize database queries
- Use CDN for static files

Issue: Session not working
Solution:
- Check session configuration
- Verify cookie settings
- Check session directory permissions

Summary

This guide provides comprehensive coverage of installing and configuring the Kotchasan Framework for production use, from server installation and security configuration to backup procedures and troubleshooting.

Key Points to Remember:

  1. Security: Use HTTPS, keep software updated, configure firewall
  2. Performance: Implement caching, optimize database, compress assets
  3. Backup: Regular backups, test recovery procedures
  4. Monitoring: Watch logs, monitor performance, fix issues quickly

Following this guide will help ensure your system is stable, secure, and performant in production environments.