<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>HHF&apos;s Posts</title><description>Your community-driven resource for homelab and technology infrastructure solutions.</description><link>https://hhf.technology/</link><language>en-us</language><item><title>Real-World Applications of Firecracker 🔥</title><link>https://hhf.technology/blog/aws-firecracker-practical-examples/</link><guid isPermaLink="true">https://hhf.technology/blog/aws-firecracker-practical-examples/</guid><description>Explore practical implementations and real-world scenarios for Firecracker.</description><pubDate>Wed, 08 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;While understanding the technical aspects of Firecracker is crucial, seeing how it can be applied in real-world scenarios helps demonstrate its true potential. This guide explores practical implementations and use cases that showcase Firecracker&apos;s capabilities in different environments.&lt;/p&gt;
&lt;h2&gt;Scenario 1: Continuous Integration Environment&lt;/h2&gt;
&lt;p&gt;Let&apos;s create a CI environment where each build runs in its own isolated MicroVM. This ensures complete isolation between builds and prevents any potential interference.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Configuration
VM_ID=$1
BUILD_ID=$2
KERNEL=&quot;/var/lib/firecracker/kernel/vmlinux-5.10&quot;
ROOTFS=&quot;/var/lib/firecracker/rootfs/debian-ci.ext4&quot;

# Create network interface
ip tuntap add dev tap${VM_ID} mode tap
ip link set tap${VM_ID} up
brctl addif br0 tap${VM_ID}

# Start Firecracker
cat &amp;lt;&amp;lt;EOF &amp;gt; /tmp/vm${VM_ID}-config.json
{
    &quot;boot-source&quot;: {
        &quot;kernel_image_path&quot;: &quot;${KERNEL}&quot;,
        &quot;boot_args&quot;: &quot;console=ttyS0 reboot=k panic=1 pci=off&quot;
    },
    &quot;drives&quot;: [
        {
            &quot;drive_id&quot;: &quot;rootfs&quot;,
            &quot;path_on_host&quot;: &quot;${ROOTFS}&quot;,
            &quot;is_root_device&quot;: true,
            &quot;is_read_only&quot;: false
        }
    ],
    &quot;network-interfaces&quot;: [
        {
            &quot;iface_id&quot;: &quot;eth0&quot;,
            &quot;guest_mac&quot;: &quot;AA:FC:00:00:${VM_ID}:01&quot;,
            &quot;host_dev_name&quot;: &quot;tap${VM_ID}&quot;
        }
    ],
    &quot;machine-config&quot;: {
        &quot;vcpu_count&quot;: 2,
        &quot;mem_size_mib&quot;: 2048
    }
}
EOF

# Run the build in isolated environment
firecracker --api-sock /tmp/firecracker-${VM_ID}.socket --config-file /tmp/vm${VM_ID}-config.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setup ensures each build runs in complete isolation, preventing issues like cached dependencies or leftover processes from affecting subsequent builds.&lt;/p&gt;
&lt;h2&gt;Scenario 2: Development Sandbox Environment&lt;/h2&gt;
&lt;p&gt;Create an automated system for developers to spin up isolated development environments quickly.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os
import json
import subprocess
from flask import Flask, request, jsonify

app = Flask(__name__)

class SandboxManager:
    def __init__(self):
        self.base_kernel = &quot;/var/lib/firecracker/kernel/vmlinux-5.10&quot;
        self.base_rootfs = &quot;/var/lib/firecracker/rootfs/dev-environment.ext4&quot;
        self.vm_configs = {}

    def create_sandbox(self, dev_id, project_type):
        # Create a copy of base rootfs for this developer
        dev_rootfs = f&quot;/var/lib/firecracker/rootfs/dev-{dev_id}.ext4&quot;
        subprocess.run([&quot;cp&quot;, self.base_rootfs, dev_rootfs])

        # Configure network
        tap_device = f&quot;tap{dev_id}&quot;
        subprocess.run([
            &quot;ip&quot;, &quot;tuntap&quot;, &quot;add&quot;, 
            &quot;dev&quot;, tap_device, 
            &quot;mode&quot;, &quot;tap&quot;
        ])
        subprocess.run([&quot;ip&quot;, &quot;link&quot;, &quot;set&quot;, tap_device, &quot;up&quot;])
        subprocess.run([&quot;brctl&quot;, &quot;addif&quot;, &quot;br0&quot;, tap_device])

        # Create VM configuration
        config = {
            &quot;boot-source&quot;: {
                &quot;kernel_image_path&quot;: self.base_kernel,
                &quot;boot_args&quot;: &quot;console=ttyS0 reboot=k panic=1 pci=off&quot;
            },
            &quot;drives&quot;: [{
                &quot;drive_id&quot;: &quot;rootfs&quot;,
                &quot;path_on_host&quot;: dev_rootfs,
                &quot;is_root_device&quot;: True,
                &quot;is_read_only&quot;: False
            }],
            &quot;network-interfaces&quot;: [{
                &quot;iface_id&quot;: &quot;eth0&quot;,
                &quot;guest_mac&quot;: f&quot;AA:FC:00:00:{dev_id:02x}:01&quot;,
                &quot;host_dev_name&quot;: tap_device
            }],
            &quot;machine-config&quot;: {
                &quot;vcpu_count&quot;: 4,
                &quot;mem_size_mib&quot;: 4096
            }
        }

        # Store configuration
        self.vm_configs[dev_id] = config
        return config

sandbox_manager = SandboxManager()

@app.route(&apos;/sandbox&apos;, methods=[&apos;POST&apos;])
def create_sandbox():
    data = request.get_json()
    dev_id = data.get(&apos;dev_id&apos;)
    project_type = data.get(&apos;project_type&apos;)
    
    config = sandbox_manager.create_sandbox(dev_id, project_type)
    return jsonify({&quot;status&quot;: &quot;success&quot;, &quot;config&quot;: config})

if __name__ == &apos;__main__&apos;:
    app.run(host=&apos;0.0.0.0&apos;, port=5000)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Scenario 3: Security Testing Environment&lt;/h2&gt;
&lt;p&gt;Create isolated environments for security testing and vulnerability scanning.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Configuration
LAB_NAME=$1
TOOLS_LIST=$2

# Create a fresh rootfs for security testing
dd if=/dev/zero of=/tmp/security-lab.ext4 bs=1G count=20
mkfs.ext4 /tmp/security-lab.ext4

# Mount and prepare the rootfs
mkdir -p /mnt/security-lab
mount /tmp/security-lab.ext4 /mnt/security-lab

# Install base system and security tools
debootstrap --include=$(echo $TOOLS_LIST | tr &apos;,&apos; &apos; &apos;) \
    bullseye /mnt/security-lab http://deb.debian.org/debian/

# Configure network isolation
cat &amp;lt;&amp;lt;EOF &amp;gt; /mnt/security-lab/etc/network/interfaces
auto eth0
iface eth0 inet static
    address 172.16.0.2
    netmask 255.255.255.0
    gateway 172.16.0.1
EOF

# Add security hardening
cat &amp;lt;&amp;lt;EOF &amp;gt; /mnt/security-lab/etc/sysctl.d/99-security.conf
net.ipv4.ip_forward = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
EOF

# Prepare VM configuration
cat &amp;lt;&amp;lt;EOF &amp;gt; /tmp/security-lab-config.json
{
    &quot;boot-source&quot;: {
        &quot;kernel_image_path&quot;: &quot;/var/lib/firecracker/kernel/vmlinux-5.10&quot;,
        &quot;boot_args&quot;: &quot;console=ttyS0 reboot=k panic=1 pci=off ip=172.16.0.2::172.16.0.1:255.255.255.0::eth0:off&quot;
    },
    &quot;drives&quot;: [
        {
            &quot;drive_id&quot;: &quot;rootfs&quot;,
            &quot;path_on_host&quot;: &quot;/tmp/security-lab.ext4&quot;,
            &quot;is_root_device&quot;: true,
            &quot;is_read_only&quot;: false
        }
    ],
    &quot;network-interfaces&quot;: [
        {
            &quot;iface_id&quot;: &quot;eth0&quot;,
            &quot;guest_mac&quot;: &quot;AA:FC:00:00:00:01&quot;,
            &quot;host_dev_name&quot;: &quot;tap0&quot;
        }
    ],
    &quot;machine-config&quot;: {
        &quot;vcpu_count&quot;: 2,
        &quot;mem_size_mib&quot;: 4096
    }
}
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Scenario 4: Serverless Function Testing&lt;/h2&gt;
&lt;p&gt;Create an environment for testing serverless functions locally with realistic isolation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os
import json
import uuid
import asyncio
from aiohttp import web

class FunctionRunner:
    def __init__(self):
        self.vm_pool = []
        self.max_vms = 10
        self.base_config = self._load_base_config()

    def _load_base_config(self):
        return {
            &quot;boot-source&quot;: {
                &quot;kernel_image_path&quot;: &quot;/var/lib/firecracker/kernel/vmlinux-5.10&quot;,
                &quot;boot_args&quot;: &quot;console=ttyS0 reboot=k panic=1 pci=off&quot;
            },
            &quot;drives&quot;: [{
                &quot;drive_id&quot;: &quot;rootfs&quot;,
                &quot;path_on_host&quot;: &quot;/var/lib/firecracker/rootfs/lambda-base.ext4&quot;,
                &quot;is_root_device&quot;: True,
                &quot;is_read_only&quot;: True
            }],
            &quot;machine-config&quot;: {
                &quot;vcpu_count&quot;: 1,
                &quot;mem_size_mib&quot;: 128
            }
        }

    async def create_function_vm(self, function_code):
        vm_id = str(uuid.uuid4())
        
        # Create overlay filesystem for this function
        overlay_path = f&quot;/tmp/function-{vm_id}.ext4&quot;
        os.system(f&quot;dd if=/dev/zero of={overlay_path} bs=1M count=512&quot;)
        os.system(f&quot;mkfs.ext4 {overlay_path}&quot;)

        # Configure VM
        config = self.base_config.copy()
        config[&quot;drives&quot;].append({
            &quot;drive_id&quot;: &quot;overlay&quot;,
            &quot;path_on_host&quot;: overlay_path,
            &quot;is_root_device&quot;: False,
            &quot;is_read_only&quot;: False
        })

        # Start VM and return handle
        return await self._start_vm(vm_id, config)

    async def _start_vm(self, vm_id, config):
        # Implementation details for starting VM
        pass

    async def execute_function(self, function_code, event):
        vm = await self.create_function_vm(function_code)
        try:
            result = await vm.invoke(event)
            return result
        finally:
            await vm.cleanup()

app = web.Application()
runner = FunctionRunner()

async def handle_function(request):
    data = await request.json()
    result = await runner.execute_function(
        data[&apos;function_code&apos;],
        data[&apos;event&apos;]
    )
    return web.json_response(result)

app.router.add_post(&apos;/functions/invoke&apos;, handle_function)

if __name__ == &apos;__main__&apos;:
    web.run_app(app)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Scenario 5: Multi-tenant Application Testing&lt;/h2&gt;
&lt;p&gt;Create an environment for testing multi-tenant applications with proper isolation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import asyncio
import docker
from typing import Dict, List
import yaml

class TenantEnvironment:
    def __init__(self, tenant_id: str, config: Dict):
        self.tenant_id = tenant_id
        self.config = config
        self.networks: List[str] = []
        self.vms: List[str] = []

    async def setup(self):
        # Create isolated network for tenant
        network_config = await self._create_network()
        
        # Setup application components
        await self._setup_components()
        
        # Configure monitoring
        await self._setup_monitoring()

    async def _create_network(self):
        # Implementation for creating isolated network
        pass

    async def _setup_components(self):
        # Setup different application components in isolated VMs
        pass

    async def _setup_monitoring(self):
        # Setup monitoring for this tenant&apos;s environment
        pass

class MultiTenantTestManager:
    def __init__(self, config_file: str):
        self.config = self._load_config(config_file)
        self.tenant_environments: Dict[str, TenantEnvironment] = {}

    def _load_config(self, config_file: str) -&amp;gt; Dict:
        with open(config_file) as f:
            return yaml.safe_load(f)

    async def create_tenant_environment(self, tenant_id: str):
        env = TenantEnvironment(tenant_id, self.config)
        await env.setup()
        self.tenant_environments[tenant_id] = env
        return env

    async def run_tests(self, test_suite: str):
        # Run tests across all tenant environments
        pass

    async def cleanup(self):
        # Cleanup all tenant environments
        pass
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Scenario 6: Edge Computing Simulation&lt;/h2&gt;
&lt;p&gt;Create an environment to simulate edge computing scenarios with multiple interconnected MicroVMs.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import asyncio
import networkx as nx
from dataclasses import dataclass
from typing import Dict, List

@dataclass
class EdgeNode:
    node_id: str
    location: tuple
    capacity: Dict
    connections: List[str]
    vm_config: Dict

class EdgeComputeSimulator:
    def __init__(self, topology_file: str):
        self.topology = self._load_topology(topology_file)
        self.nodes: Dict[str, EdgeNode] = {}
        self.network = nx.Graph()

    def _load_topology(self, topology_file: str):
        # Load network topology from file
        pass

    async def create_edge_node(self, node_config: Dict):
        # Create Firecracker VM for edge node
        node_id = node_config[&apos;id&apos;]
        
        # Configure networking for this node
        network_config = self._create_network_config(node_config)
        
        # Create VM configuration
        vm_config = {
            &quot;boot-source&quot;: {
                &quot;kernel_image_path&quot;: &quot;/var/lib/firecracker/kernel/vmlinux-5.10&quot;,
                &quot;boot_args&quot;: f&quot;console=ttyS0 reboot=k panic=1 pci=off ip={network_config[&apos;ip&apos;]}&quot;
            },
            &quot;drives&quot;: [{
                &quot;drive_id&quot;: &quot;rootfs&quot;,
                &quot;path_on_host&quot;: f&quot;/var/lib/firecracker/rootfs/edge-{node_id}.ext4&quot;,
                &quot;is_root_device&quot;: True,
                &quot;is_read_only&quot;: False
            }],
            &quot;network-interfaces&quot;: [{
                &quot;iface_id&quot;: &quot;eth0&quot;,
                &quot;guest_mac&quot;: f&quot;AA:FC:00:{node_id:02x}:00:01&quot;,
                &quot;host_dev_name&quot;: f&quot;tap{node_id}&quot;
            }],
            &quot;machine-config&quot;: {
                &quot;vcpu_count&quot;: node_config.get(&apos;vcpu&apos;, 1),
                &quot;mem_size_mib&quot;: node_config.get(&apos;memory&apos;, 512)
            }
        }
        
        # Create and store node
        node = EdgeNode(
            node_id=node_id,
            location=node_config[&apos;location&apos;],
            capacity=node_config[&apos;capacity&apos;],
            connections=node_config[&apos;connections&apos;],
            vm_config=vm_config
        )
        self.nodes[node_id] = node
        return node

    def _create_network_config(self, node_config: Dict):
        # Create network configuration for edge node
        ip = f&quot;172.16.{node_config[&apos;subnet&apos;]}.{node_config[&apos;host&apos;]}/24&quot;
        return {
            &quot;ip&quot;: ip,
            &quot;gateway&quot;: f&quot;172.16.{node_config[&apos;subnet&apos;]}.1&quot;
        }

    async def simulate_network_conditions(self):
        # Simulate different network conditions between nodes
        for edge1, edge2 in self.network.edges():
            # Apply network latency and bandwidth constraints
            latency = self.network[edge1][edge2].get(&apos;latency&apos;, &apos;20ms&apos;)
            bandwidth = self.network[edge1][edge2].get(&apos;bandwidth&apos;, &apos;100mbit&apos;)
            
            os.system(f&quot;tc qdisc add dev {edge1}-{edge2} root netem delay {latency}&quot;)
            os.system(f&quot;tc qdisc add dev {edge1}-{edge2} root tbf rate {bandwidth} burst 32kbit latency 400ms&quot;)

    async def deploy_application(self, app_config: Dict):
        # Deploy application across edge nodes
        for node_id, deployment in app_config[&apos;deployments&apos;].items():
            node = self.nodes[node_id]
            await self._deploy_to_node(node, deployment)

    async def _deploy_to_node(self, node: EdgeNode, deployment: Dict):
        # Implementation for deploying to specific node
        pass

# Example usage
async def main():
    simulator = EdgeComputeSimulator(&apos;topology.yaml&apos;)
    
    # Create edge nodes
    nodes = [
        {&apos;id&apos;: &apos;01&apos;, &apos;location&apos;: (40.7128, -74.0060), &apos;subnet&apos;: 1, &apos;host&apos;: 2},
        {&apos;id&apos;: &apos;02&apos;, &apos;location&apos;: (34.0522, -118.2437), &apos;subnet&apos;: 1, &apos;host&apos;: 3},
        {&apos;id&apos;: &apos;03&apos;, &apos;location&apos;: (51.5074, -0.1278), &apos;subnet&apos;: 1, &apos;host&apos;: 4}
    ]
    
    for node_config in nodes:
        await simulator.create_edge_node(node_config)
    
    # Simulate network conditions
    await simulator.simulate_network_conditions()
    
    # Deploy application
    app_config = {
        &apos;deployments&apos;: {
            &apos;01&apos;: {&apos;components&apos;: [&apos;web&apos;, &apos;cache&apos;]},
            &apos;02&apos;: {&apos;components&apos;: [&apos;database&apos;]},
            &apos;03&apos;: {&apos;components&apos;: [&apos;analytics&apos;]}
        }
    }
    await simulator.deploy_application(app_config)

if __name__ == &apos;__main__&apos;:
    asyncio.run(main())
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Scenario 7: Microservices Testing Environment&lt;/h2&gt;
&lt;p&gt;Create an environment for testing microservices interactions with proper isolation and network control.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import asyncio
import yaml
from typing import Dict, List
from dataclasses import dataclass

@dataclass
class ServiceConfig:
    name: str
    version: str
    dependencies: List[str]
    resources: Dict
    config: Dict

class MicroservicesTestEnvironment:
    def __init__(self, config_file: str):
        self.config = self._load_config(config_file)
        self.services: Dict[str, ServiceConfig] = {}
        self.vms: Dict[str, Dict] = {}

    def _load_config(self, config_file: str) -&amp;gt; Dict:
        with open(config_file) as f:
            return yaml.safe_load(f)

    async def create_service_vm(self, service: ServiceConfig):
        &quot;&quot;&quot;Create a Firecracker VM for a specific microservice&quot;&quot;&quot;
        vm_id = f&quot;{service.name}-{service.version}&quot;
        
        # Create rootfs for service
        rootfs_path = f&quot;/var/lib/firecracker/rootfs/{vm_id}.ext4&quot;
        self._prepare_service_rootfs(service, rootfs_path)
        
        # Configure VM
        config = {
            &quot;boot-source&quot;: {
                &quot;kernel_image_path&quot;: &quot;/var/lib/firecracker/kernel/vmlinux-5.10&quot;,
                &quot;boot_args&quot;: &quot;console=ttyS0 reboot=k panic=1 pci=off&quot;
            },
            &quot;drives&quot;: [{
                &quot;drive_id&quot;: &quot;rootfs&quot;,
                &quot;path_on_host&quot;: rootfs_path,
                &quot;is_root_device&quot;: True,
                &quot;is_read_only&quot;: False
            }],
            &quot;network-interfaces&quot;: [{
                &quot;iface_id&quot;: &quot;eth0&quot;,
                &quot;guest_mac&quot;: f&quot;AA:FC:00:{hash(vm_id) % 256:02x}:00:01&quot;,
                &quot;host_dev_name&quot;: f&quot;tap-{vm_id}&quot;
            }],
            &quot;machine-config&quot;: {
                &quot;vcpu_count&quot;: service.resources.get(&apos;cpu&apos;, 1),
                &quot;mem_size_mib&quot;: service.resources.get(&apos;memory&apos;, 512)
            }
        }
        
        self.vms[vm_id] = config
        return config

    def _prepare_service_rootfs(self, service: ServiceConfig, rootfs_path: str):
        # Prepare rootfs with service dependencies and configuration
        pass

    async def setup_service_network(self, service: ServiceConfig):
        &quot;&quot;&quot;Configure network for service and its dependencies&quot;&quot;&quot;
        vm_id = f&quot;{service.name}-{service.version}&quot;
        
        # Create tap device for service
        os.system(f&quot;ip tuntap add dev tap-{vm_id} mode tap&quot;)
        os.system(f&quot;ip link set tap-{vm_id} up&quot;)
        os.system(f&quot;brctl addif br0 tap-{vm_id}&quot;)

        # Setup network policies for service dependencies
        for dependency in service.dependencies:
            self._setup_network_policy(service.name, dependency)

    def _setup_network_policy(self, service: str, dependency: str):
        # Implement network policies between services
        pass

    async def deploy_services(self):
        &quot;&quot;&quot;Deploy all services in the configuration&quot;&quot;&quot;
        for service_name, service_config in self.config[&apos;services&apos;].items():
            service = ServiceConfig(
                name=service_name,
                version=service_config[&apos;version&apos;],
                dependencies=service_config.get(&apos;dependencies&apos;, []),
                resources=service_config.get(&apos;resources&apos;, {}),
                config=service_config.get(&apos;config&apos;, {})
            )
            
            # Create and configure VM for service
            await self.create_service_vm(service)
            await self.setup_service_network(service)

    async def run_integration_tests(self):
        &quot;&quot;&quot;Run integration tests across services&quot;&quot;&quot;
        # Implementation for running tests
        pass

# Example usage
async def main():
    env = MicroservicesTestEnvironment(&apos;services-config.yaml&apos;)
    await env.deploy_services()
    await env.run_integration_tests()

if __name__ == &apos;__main__&apos;:
    asyncio.run(main())
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Scenario 8: Load Testing Environment&lt;/h2&gt;
&lt;p&gt;Create an environment for performing load tests with proper resource isolation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import asyncio
import statistics
from dataclasses import dataclass
from typing import Dict, List

@dataclass
class LoadTestConfig:
    target_url: str
    concurrent_users: int
    ramp_up_time: int
    test_duration: int
    scenarios: List[Dict]

class LoadTestEnvironment:
    def __init__(self, config: LoadTestConfig):
        self.config = config
        self.vms: List[str] = []
        self.results: List[Dict] = []

    async def setup_load_generators(self):
        &quot;&quot;&quot;Create VMs for load generation&quot;&quot;&quot;
        vms_needed = self._calculate_required_vms()
        
        for i in range(vms_needed):
            vm_id = f&quot;loadgen-{i:03d}&quot;
            
            # Create VM configuration
            config = {
                &quot;boot-source&quot;: {
                    &quot;kernel_image_path&quot;: &quot;/var/lib/firecracker/kernel/vmlinux-5.10&quot;,
                    &quot;boot_args&quot;: &quot;console=ttyS0 reboot=k panic=1 pci=off&quot;
                },
                &quot;drives&quot;: [{
                    &quot;drive_id&quot;: &quot;rootfs&quot;,
                    &quot;path_on_host&quot;: &quot;/var/lib/firecracker/rootfs/loadgen.ext4&quot;,
                    &quot;is_root_device&quot;: True,
                    &quot;is_read_only&quot;: True
                }],
                &quot;network-interfaces&quot;: [{
                    &quot;iface_id&quot;: &quot;eth0&quot;,
                    &quot;guest_mac&quot;: f&quot;AA:FC:00:00:{i:02x}:01&quot;,
                    &quot;host_dev_name&quot;: f&quot;tap{i}&quot;
                }],
                &quot;machine-config&quot;: {
                    &quot;vcpu_count&quot;: 2,
                    &quot;mem_size_mib&quot;: 1024
                }
            }
            
            # Create network interface
            os.system(f&quot;ip tuntap add dev tap{i} mode tap&quot;)
            os.system(f&quot;ip link set tap{i} up&quot;)
            os.system(f&quot;brctl addif br0 tap{i}&quot;)
            
            self.vms.append(vm_id)

    def _calculate_required_vms(self) -&amp;gt; int:
        &quot;&quot;&quot;Calculate number of VMs needed based on load parameters&quot;&quot;&quot;
        users_per_vm = 1000  # Adjust based on your needs
        return max(1, self.config.concurrent_users // users_per_vm)

    async def run_load_test(self):
        &quot;&quot;&quot;Execute load test across all VMs&quot;&quot;&quot;
        # Distribute load across VMs
        users_per_vm = self.config.concurrent_users // len(self.vms)
        
        tasks = []
        for vm_id in self.vms:
            task = asyncio.create_task(
                self._run_load_test_on_vm(vm_id, users_per_vm)
            )
            tasks.append(task)
        
        results = await asyncio.gather(*tasks)
        self.results.extend(results)

    async def _run_load_test_on_vm(self, vm_id: str, user_count: int):
        &quot;&quot;&quot;Run load test on specific VM&quot;&quot;&quot;
        # Implementation for running load test on VM
        pass

    def analyze_results(self) -&amp;gt; Dict:
        &quot;&quot;&quot;Analyze load test results&quot;&quot;&quot;
        response_times = [r[&apos;response_time&apos;] for r in self.results]
        
        return {
            &apos;avg_response_time&apos;: statistics.mean(response_times),
            &apos;p95_response_time&apos;: statistics.quantiles(response_times, n=20)[18],
            &apos;p99_response_time&apos;: statistics.quantiles(response_times, n=100)[98],
            &apos;total_requests&apos;: len(response_times),
            &apos;success_rate&apos;: sum(1 for r in self.results if r[&apos;success&apos;]) / len(self.results)
        }

# Example usage
async def main():
    config = LoadTestConfig(
        target_url=&quot;http://target-service:8080&quot;,
        concurrent_users=5000,
        ramp_up_time=300,
        test_duration=3600,
        scenarios=[
            {&apos;name&apos;: &apos;browse_catalog&apos;, &apos;weight&apos;: 0.4},
            {&apos;name&apos;: &apos;add_to_cart&apos;, &apos;weight&apos;: 0.3},
            {&apos;name&apos;: &apos;checkout&apos;, &apos;weight&apos;: 0.3}
        ]
    )
    
    env = LoadTestEnvironment(config)
    await env.setup_load_generators()
    await env.run_load_test()
    results = env.analyze_results()
    print(f&quot;Load Test Results: {results}&quot;)

if __name__ == &apos;__main__&apos;:
    asyncio.run(main())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These scenarios demonstrate the versatility of Firecracker MicroVMs in different use cases. Each scenario includes detailed implementation examples and considerations for:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Resource isolation&lt;/li&gt;
&lt;li&gt;Network configuration&lt;/li&gt;
&lt;li&gt;Performance monitoring&lt;/li&gt;
&lt;li&gt;Data collection and analysis&lt;/li&gt;
&lt;li&gt;Automation and orchestration&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The examples can be extended and modified based on specific requirements while maintaining the core benefits of Firecracker: rapid startup times, strong isolation, and efficient resource utilization.&lt;/p&gt;
&lt;p&gt;Remember to always follow best practices for security and resource management when implementing these scenarios in production environments.&lt;/p&gt;
</content:encoded></item><item><title>CLP Modern Framework Deploy &amp; CI/CD Integration</title><link>https://hhf.technology/blog/cloudpanel-nodejs/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-nodejs/</guid><description>Advanced Framework Deployments.</description><pubDate>Sun, 08 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Advanced Deployment Guide: Modern Framework Deployment &amp;amp; CI/CD Integration&lt;/h1&gt;
&lt;h2&gt;Part 1: Advanced Framework Deployments&lt;/h2&gt;
&lt;h3&gt;Astro Deployment&lt;/h3&gt;
&lt;p&gt;Let&apos;s deploy an Astro application with server-side rendering (SSR) and dynamic routes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First, create a Node.js site for Astro:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;clpctl site:add:nodejs \
    --domainName=astro.yourdomain.com \
    --nodejsVersion=18 \
    --appPort=4321 \
    --siteUser=astro-admin \
    --siteUserPassword=&apos;secure_password_here&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Set up the Astro project with SSR:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;cd htdocs/astro.yourdomain.com/
# Create new Astro project
npm create astro@latest

# Add SSR adapter
npm install @astrojs/node
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Configure Astro for SSR (astro.config.mjs):&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;import { defineConfig } from &apos;astro/config&apos;;
import node from &apos;@astrojs/node&apos;;

export default defineConfig({
  output: &apos;server&apos;,
  adapter: node({
    mode: &apos;standalone&apos;
  }),
  server: {
    port: 4321,
    host: true
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Create PM2 configuration for Astro:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// ecosystem.config.js
module.exports = {
  apps: [{
    name: &apos;astro-app&apos;,
    script: &apos;./dist/server/entry.mjs&apos;,
    env: {
      HOST: &apos;127.0.0.1&apos;,
      PORT: 4321,
      NODE_ENV: &apos;production&apos;
    },
    exec_mode: &apos;cluster&apos;,
    instances: &apos;max&apos;,
    max_memory_restart: &apos;500M&apos;
  }]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Next.js Advanced Deployment&lt;/h3&gt;
&lt;p&gt;Let&apos;s deploy a Next.js application with custom server configuration and internationalization.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set up the site:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;clpctl site:add:nodejs \
    --domainName=next.yourdomain.com \
    --nodejsVersion=18 \
    --appPort=3000 \
    --siteUser=next-admin \
    --siteUserPassword=&apos;secure_password_here&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Configure Next.js with custom server:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// server.js
const { createServer } = require(&apos;http&apos;);
const { parse } = require(&apos;url&apos;);
const next = require(&apos;next&apos;);

const dev = process.env.NODE_ENV !== &apos;production&apos;;
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() =&amp;gt; {
  createServer((req, res) =&amp;gt; {
    const parsedUrl = parse(req.url, true);
    handle(req, res, parsedUrl);
  }).listen(3000, (err) =&amp;gt; {
    if (err) throw err;
    console.log(&apos;&amp;gt; Ready on http://localhost:3000&apos;);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Advanced PM2 configuration for Next.js:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// ecosystem.config.js
module.exports = {
  apps: [{
    name: &apos;nextjs-advanced&apos;,
    script: &apos;server.js&apos;,
    instances: &apos;max&apos;,
    exec_mode: &apos;cluster&apos;,
    watch: false,
    max_memory_restart: &apos;1G&apos;,
    env: {
      NODE_ENV: &apos;production&apos;,
      PORT: 3000
    },
    env_production: {
      NODE_ENV: &apos;production&apos;,
      PORT: 3000
    }
  }]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Docusaurus Deployment&lt;/h3&gt;
&lt;p&gt;Let&apos;s deploy a Docusaurus site with versioned documentation and search functionality.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a static site for Docusaurus:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;clpctl site:add:static \
    --domainName=docs.yourdomain.com \
    --siteUser=docs-admin \
    --siteUserPassword=&apos;secure_password_here&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Set up Docusaurus with versioning:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;cd htdocs/docs.yourdomain.com/
npm init docusaurus@latest
npm run build
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Configure versioning:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// docusaurus.config.js
module.exports = {
  title: &apos;Your Documentation&apos;,
  tagline: &apos;Documentation made easy&apos;,
  url: &apos;https://docs.yourdomain.com&apos;,
  baseUrl: &apos;/&apos;,
  onBrokenLinks: &apos;throw&apos;,
  onBrokenMarkdownLinks: &apos;warn&apos;,
  favicon: &apos;img/favicon.ico&apos;,
  organizationName: &apos;your-org&apos;,
  projectName: &apos;your-docs&apos;,
  
  presets: [
    [
      &apos;@docusaurus/preset-classic&apos;,
      {
        docs: {
          sidebarPath: require.resolve(&apos;./sidebars.js&apos;),
          editUrl: &apos;https://github.com/your-org/your-docs/edit/main/&apos;,
          showLastUpdateTime: true,
          showLastUpdateAuthor: true,
        },
      },
    ],
  ],
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Part 2: Advanced PM2 Management&lt;/h2&gt;
&lt;h3&gt;Load Balancing with PM2&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Cluster Mode Configuration:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// ecosystem.config.js
module.exports = {
  apps: [{
    name: &apos;load-balanced-app&apos;,
    script: &apos;server.js&apos;,
    instances: -1, // Use all available CPUs
    exec_mode: &apos;cluster&apos;,
    watch: true,
    max_memory_restart: &apos;1G&apos;,
    env: {
      NODE_ENV: &apos;production&apos;,
      PORT: 3000
    },
    node_args: &apos;--max_old_space_size=4096&apos;
  }]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Advanced PM2 Monitoring:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# Monitor memory usage
pm2 monit

# Set up PM2 monitoring dashboard
pm2 plus

# Advanced logs with timestamp
pm2 logs --timestamp --lines 1000

# Rotate logs
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Zero-Downtime Deployment:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# Reload without downtime
pm2 reload ecosystem.config.js --env production

# Rolling reload
pm2 reload ecosystem.config.js --env production --parallel 2

# Graceful reload
pm2 gracefulReload all
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Memory Management:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// ecosystem.config.js with memory management
module.exports = {
  apps: [{
    name: &apos;memory-managed-app&apos;,
    script: &apos;server.js&apos;,
    instances: 4,
    exec_mode: &apos;cluster&apos;,
    max_memory_restart: &apos;1G&apos;,
    node_args: &apos;--max_old_space_size=4096&apos;,
    increment_var: &apos;PORT&apos;,
    env: {
      NODE_ENV: &apos;production&apos;,
      PORT: 3000
    },
    error_file: &apos;logs/err.log&apos;,
    out_file: &apos;logs/out.log&apos;,
    merge_logs: true,
    exp_backoff_restart_delay: 100
  }]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Part 3: GitHub CI/CD Integration&lt;/h2&gt;
&lt;h3&gt;GitHub Actions Workflow for Node.js Application&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Basic Deployment Workflow:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Setup Node.js
      uses: actions/setup-node@v2
      with:
        node-version: &apos;18&apos;
        
    - name: Install Dependencies
      run: npm ci
        
    - name: Build
      run: npm run build
        
    - name: Deploy to Server
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.SERVER_HOST }}
        username: ${{ secrets.SERVER_USER }}
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        script: |
          cd ~/htdocs/your-domain.com
          git pull origin main
          npm ci
          npm run build
          pm2 reload ecosystem.config.js --env production
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Advanced Workflow with Testing and Staging:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;name: CI/CD Pipeline

on:
  push:
    branches: [ main, staging ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    
    - name: Setup Node.js
      uses: actions/setup-node@v2
      with:
        node-version: &apos;18&apos;
        
    - name: Install Dependencies
      run: npm ci
        
    - name: Run Tests
      run: npm test
        
    - name: Run Linting
      run: npm run lint
      
  deploy-staging:
    needs: test
    if: github.ref == &apos;refs/heads/staging&apos;
    runs-on: ubuntu-latest
    
    steps:
    - name: Deploy to Staging
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.STAGING_HOST }}
        username: ${{ secrets.STAGING_USER }}
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        script: |
          cd ~/htdocs/staging.your-domain.com
          git pull origin staging
          npm ci
          npm run build
          pm2 reload ecosystem.config.js --env staging
          
  deploy-production:
    needs: [test]
    if: github.ref == &apos;refs/heads/main&apos;
    runs-on: ubuntu-latest
    
    steps:
    - name: Deploy to Production
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.PROD_HOST }}
        username: ${{ secrets.PROD_USER }}
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        script: |
          cd ~/htdocs/your-domain.com
          git pull origin main
          npm ci
          npm run build
          pm2 reload ecosystem.config.js --env production
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Automated Backup Before Deployment:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# Add this step before deployment
- name: Backup Database
  uses: appleboy/ssh-action@master
  with:
    host: ${{ secrets.SERVER_HOST }}
    username: ${{ secrets.SERVER_USER }}
    key: ${{ secrets.SSH_PRIVATE_KEY }}
    script: |
      clpctl db:backup --retentionPeriod=7
      clpctl remote-backup:create
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Security Best Practices&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Environment Variables:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# On your CloudPanel server
nano ~/.env.production

# Add your environment variables
DATABASE_URL=postgresql://user:pass@localhost:5432/db
REDIS_URL=redis://localhost:6379
JWT_SECRET=your-secret-key

# Update PM2 config to use env file
pm2 ecosystem.config.js --env production --env-path ~/.env.production
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;SSL Certificate Automation:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# Add to GitHub Actions workflow
- name: Update SSL Certificate
  uses: appleboy/ssh-action@master
  with:
    host: ${{ secrets.SERVER_HOST }}
    username: ${{ secrets.SERVER_USER }}
    key: ${{ secrets.SSH_PRIVATE_KEY }}
    script: |
      clpctl lets-encrypt:renew:certificates
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Monitoring Setup:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// ecosystem.config.js with monitoring
module.exports = {
  apps: [{
    name: &apos;monitored-app&apos;,
    script: &apos;server.js&apos;,
    instances: &apos;max&apos;,
    exec_mode: &apos;cluster&apos;,
    max_memory_restart: &apos;1G&apos;,
    merge_logs: true,
    log_date_format: &apos;YYYY-MM-DD HH:mm:ss Z&apos;,
    error_file: &apos;logs/err.log&apos;,
    out_file: &apos;logs/out.log&apos;,
    log_type: &apos;json&apos;,
    watch: [&apos;server&apos;, &apos;client&apos;],
    ignore_watch: [&apos;node_modules&apos;, &apos;logs&apos;]
  }]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember to always test your CI/CD pipeline in a staging environment first and maintain proper backup strategies before deploying to production. Regular monitoring and logging are crucial for maintaining a healthy production environment.&lt;/p&gt;
</content:encoded></item><item><title>Optimizing Node.js Code in CloudPanel</title><link>https://hhf.technology/blog/cloudpanel-nodejs-optimizing/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-nodejs-optimizing/</guid><description>Reduced Server Costs by 52% Just by Optimizing Node.js Code in CloudPanel.</description><pubDate>Sat, 09 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;I Reduced Server Costs by 52% Just by Optimizing Node.js Code in CloudPanel&lt;/h1&gt;
&lt;h2&gt;The Art of Server Cost-Cutting: A Node.js Optimization Journey Part 1&lt;/h2&gt;
&lt;p&gt;It started as a shock - I opened my CloudPanel dashboard after a deep breath and saw the memory usage climbing steadily over time. I expected all Node.js applications to have some memory footprint, but this was different. Our modest application was consuming resources like it was hosting a Silicon Valley startup&apos;s entire infrastructure.&lt;/p&gt;
&lt;p&gt;If you&apos;re just starting this journey, here&apos;s what the typical Node.js application running on CloudPanel looks like - steadily increasing RAM usage, creeping up resource utilization, and leaving your wallet feeling lighter each month as you keep upgrading server specs instead of fixing the root cause.&lt;/p&gt;
&lt;h2&gt;The Memory Leaks Expedition&lt;/h2&gt;
&lt;p&gt;The first critical area I tackled was memory leaks. When you&apos;re running Node.js applications on CloudPanel, memory leaks can be particularly sneaky because they don&apos;t immediately manifest as problems. Here&apos;s what an unoptimized memory usage pattern typically looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Before Optimization - Memory Leak Example
const cache = new Map();

async function processData(key, data) {
    // Memory leak: Continuously growing cache without cleanup
    cache.set(key, {
        data: data,
        timestamp: Date.now(),
        processedResult: await heavyComputation(data)
    });
}

setInterval(() =&amp;gt; {
    // Periodic operation without cleanup
    processNewData();
}, 5000);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The fix involved implementing proper memory management and monitoring:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// After Optimization - Memory Management
const cache = new Map();
const MAX_CACHE_SIZE = 1000;
const CACHE_TTL = 3600000; // 1 hour in milliseconds

async function processData(key, data) {
    // Implement cache size limits
    if (cache.size &amp;gt;= MAX_CACHE_SIZE) {
        const oldestKey = [...cache.keys()][0];
        cache.delete(oldestKey);
    }
    
    // Add TTL to cache entries
    cache.set(key, {
        data: data,
        timestamp: Date.now(),
        processedResult: await heavyComputation(data)
    });
}

// Implement cache cleanup
setInterval(() =&amp;gt; {
    const now = Date.now();
    for (const [key, value] of cache.entries()) {
        if (now - value.timestamp &amp;gt; CACHE_TTL) {
            cache.delete(key);
        }
    }
}, 300000); // Clean every 5 minutes
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Event Loop Blockage Resolution&lt;/h2&gt;
&lt;p&gt;CloudPanel&apos;s performance metrics helped identify another crucial issue - event loop blocking. Here&apos;s what we found and fixed:&lt;/p&gt;
&lt;p&gt;Before Optimization:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function processLargeDataset(data) {
    // Blocking operation
    return data.map(item =&amp;gt; heavyTransformation(item));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After Optimization:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async function processLargeDataset(data) {
    const batchSize = 100;
    const results = [];
    
    for (let i = 0; i &amp;lt; data.length; i += batchSize) {
        const batch = data.slice(i, i + batchSize);
        // Process in batches and yield to event loop
        const batchResults = await Promise.all(
            batch.map(async item =&amp;gt; {
                const result = await heavyTransformation(item);
                return result;
            })
        );
        results.push(...batchResults);
        // Allow other operations to process
        await new Promise(resolve =&amp;gt; setImmediate(resolve));
    }
    return results;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Results Speak Volumes&lt;/h2&gt;
&lt;p&gt;Our optimization efforts led to dramatic improvements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Memory Usage: Dropped from 1.8GB to 256MB&lt;/li&gt;
&lt;li&gt;Response Time: From 600ms to 250ms average&lt;/li&gt;
&lt;li&gt;CPU Utilization: Decreased from 80% to 35%&lt;/li&gt;
&lt;li&gt;Instance Size: Downgradable to smaller specifications&lt;/li&gt;
&lt;li&gt;Monthly Costs: Reduced by 80%&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;CloudPanel-Specific Optimization Checklist&lt;/h2&gt;
&lt;h3&gt;Performance Tuning&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Memory Management:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Implement garbage collection hints
if (global.gc) {
    setInterval(() =&amp;gt; {
        global.gc();
    }, 30000);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Database Connection Pooling:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const pool = mysql.createPool({
    host: &apos;localhost&apos;,
    user: &apos;your_user&apos;,
    password: &apos;your_password&apos;,
    database: &apos;your_db&apos;,
    connectionLimit: 10,
    queueLimit: 0
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CloudPanel Monitoring Setup&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;System Monitoring:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const monitoring = require(&apos;node-monitoring&apos;);

monitoring.watch({
    memory: true,
    cpu: true,
    eventLoop: true,
    interval: 5000 // 5 seconds
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Custom Metrics Collection:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const metrics = {
    requestCount: 0,
    errorCount: 0,
    responseTime: []
};

app.use((req, res, next) =&amp;gt; {
    const start = Date.now();
    metrics.requestCount++;
    
    res.on(&apos;finish&apos;, () =&amp;gt; {
        metrics.responseTime.push(Date.now() - start);
    });
    
    next();
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Resource Pooling&lt;/h3&gt;
&lt;p&gt;Implement connection pooling for all external resources:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const genericPool = require(&apos;generic-pool&apos;);

const factory = {
    create: async () =&amp;gt; {
        return await createExpensiveResource();
    },
    destroy: async (client) =&amp;gt; {
        await client.disconnect();
    }
};

const pool = genericPool.createPool(factory, {
    max: 10,
    min: 2,
    idleTimeoutMillis: 30000,
    acquireTimeoutMillis: 30000
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Monitoring Setup in CloudPanel&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Enable CloudPanel&apos;s built-in monitoring:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU usage tracking&lt;/li&gt;
&lt;li&gt;Memory utilization metrics&lt;/li&gt;
&lt;li&gt;Disk I/O monitoring&lt;/li&gt;
&lt;li&gt;Network performance tracking&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure custom monitoring dashboards:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const dashboard = new Dashboard({
    title: &apos;Node.js Application Metrics&apos;,
    refresh: &apos;10s&apos;,
    panels: [
        memoryUsagePanel,
        cpuUsagePanel,
        responseTimePanel,
        errorRatePanel
    ]
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set up alerting:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const alerts = new AlertManager({
    threshold: {
        memory: 80, // Percentage
        cpu: 70,    // Percentage
        responseTime: 1000 // milliseconds
    },
    notification: {
        email: &apos;admin@yourdomain.com&apos;,
        slack: &apos;webhook_url&apos;
    }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Key Resources&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;CloudPanel Documentation&lt;/li&gt;
&lt;li&gt;Node.js Performance Guide&lt;/li&gt;
&lt;li&gt;V8 Engine Optimization Documentation&lt;/li&gt;
&lt;li&gt;Memory Leak Detection Tools&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember: Optimization is a journey, not a destination. Start with monitoring, identify what matters most to your application, and optimize accordingly. Your stack will thank you.&lt;/p&gt;
&lt;h2&gt;Additional Tips&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Use Node.js --inspect flag during development for debugging memory issues&lt;/li&gt;
&lt;li&gt;Implement circuit breakers for external service calls&lt;/li&gt;
&lt;li&gt;Use compression middleware for response payload optimization&lt;/li&gt;
&lt;li&gt;Implement proper error handling and logging&lt;/li&gt;
&lt;li&gt;Regular performance audits using CloudPanel&apos;s built-in tools&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This optimization journey transformed our application from a resource-hungry monster into a lean, efficient system. The key was understanding how Node.js interacts with system resources and leveraging CloudPanel&apos;s tools for monitoring and optimization.&lt;/p&gt;
</content:encoded></item><item><title>Optimizing PHP Code in CloudPanel is a Must</title><link>https://hhf.technology/blog/cloudpanel-php-optimizing/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-php-optimizing/</guid><description>Reduced Server spikes by 65% Just by Optimizing PHP Code in CloudPanel.</description><pubDate>Thu, 09 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;I Reduced Server spikes by 65% Just by Optimizing PHP Code in CloudPanel&lt;/h1&gt;
&lt;h2&gt;The Art of Server Cost-Cutting: A PHP Optimization Journey Part 2&lt;/h2&gt;
&lt;p&gt;It began with a startling realization - I checked my CloudPanel dashboard and watched PHP-FPM&apos;s memory usage climb steadily higher for a simple php app. While PHP applications naturally consume some memory, this pattern was concerning. Our modest application was devouring resources as if it were processing an enterprise workload.&lt;/p&gt;
&lt;p&gt;Let me walk you through my journey of optimization that not only saved costs but transformed our application&apos;s performance.&lt;/p&gt;
&lt;h2&gt;Understanding PHP Memory Management&lt;/h2&gt;
&lt;p&gt;PHP&apos;s memory management differs fundamentally from Node.js. PHP follows a shared-nothing architecture, meaning each request gets its own memory space that&apos;s cleared after the request ends. However, this doesn&apos;t make us immune to memory issues. Here&apos;s what an unoptimized PHP script typically looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Before Optimization - Memory Intensive Code
function processLargeDataset($data) {
    $results = [];
    foreach ($data as $item) {
        // Building large arrays in memory
        $results[] = heavyTransformation($item);
        // No memory limit checks
        // No garbage collection hints
    }
    return $results;
}

// Large static arrays
$cache = [];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s transform this into memory-efficient code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// After Optimization - Memory Efficient Code
function processLargeDataset($data) {
    // Set memory limit for this operation
    ini_set(&apos;memory_limit&apos;, &apos;256M&apos;);
    
    $results = [];
    $counter = 0;
    
    foreach ($data as $item) {
        $results[] = heavyTransformation($item);
        $counter++;
        
        // Periodically check memory usage
        if ($counter % 100 === 0) {
            $memoryUsage = memory_get_usage(true);
            if ($memoryUsage &amp;gt; 200 * 1024 * 1024) { // 200MB threshold
                // Handle memory threshold exceeded
                error_log(&quot;Memory threshold reached: &quot; . ($memoryUsage / 1024 / 1024) . &quot;MB&quot;);
                gc_collect_cycles(); // Force garbage collection
            }
        }
    }
    
    return $results;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;PHP-FPM Configuration Optimization&lt;/h2&gt;
&lt;p&gt;One of the most crucial aspects of PHP performance in CloudPanel is proper PHP-FPM configuration. Here&apos;s an optimized configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;; php-fpm.conf optimization
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500

; Process idle timeout
pm.process_idle_timeout = 10s

; Emergency restart threshold
emergency_restart_threshold = 10
emergency_restart_interval = 1m

; PHP memory settings
php_admin_value[memory_limit] = 256M
php_admin_value[max_execution_time] = 60
php_admin_value[max_input_time] = 60
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Database Connection Management&lt;/h2&gt;
&lt;p&gt;In PHP, database connections need careful management. Here&apos;s an optimized approach:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class DatabaseConnection {
    private static $instance = null;
    private $pdo;
    
    private function __construct() {
        $this-&amp;gt;pdo = new PDO(
            &quot;mysql:host=localhost;dbname=your_database&quot;,
            &quot;username&quot;,
            &quot;password&quot;,
            [
                PDO::ATTR_PERSISTENT =&amp;gt; true,
                PDO::ATTR_ERRMODE =&amp;gt; PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_EMULATE_PREPARES =&amp;gt; false
            ]
        );
    }
    
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function query($sql, $params = []) {
        $stmt = $this-&amp;gt;pdo-&amp;gt;prepare($sql);
        $stmt-&amp;gt;execute($params);
        return $stmt;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Session Management Optimization&lt;/h2&gt;
&lt;p&gt;Sessions can be a significant source of server load. Here&apos;s how to optimize them:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Custom session handler using Redis
class RedisSessionHandler implements SessionHandlerInterface {
    private $redis;
    private $ttl;
    
    public function __construct() {
        $this-&amp;gt;redis = new Redis();
        $this-&amp;gt;redis-&amp;gt;connect(&apos;127.0.0.1&apos;, 6379);
        $this-&amp;gt;ttl = 3600; // 1 hour
    }
    
    public function open($savePath, $sessionName) {
        return true;
    }
    
    public function close() {
        return true;
    }
    
    public function read($id) {
        $data = $this-&amp;gt;redis-&amp;gt;get(&quot;session:$id&quot;);
        return $data ?: &apos;&apos;;
    }
    
    public function write($id, $data) {
        return $this-&amp;gt;redis-&amp;gt;setex(&quot;session:$id&quot;, $this-&amp;gt;ttl, $data);
    }
    
    public function destroy($id) {
        return $this-&amp;gt;redis-&amp;gt;del(&quot;session:$id&quot;);
    }
    
    public function gc($maxlifetime) {
        return true; // Redis handles expiration automatically
    }
}

// Initialize custom session handler
$handler = new RedisSessionHandler();
session_set_save_handler($handler, true);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Caching Implementation&lt;/h2&gt;
&lt;p&gt;Proper caching is crucial for PHP applications:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class CacheManager {
    private $redis;
    private static $instance = null;
    
    private function __construct() {
        $this-&amp;gt;redis = new Redis();
        $this-&amp;gt;redis-&amp;gt;connect(&apos;127.0.0.1&apos;, 6379);
    }
    
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function get($key) {
        return $this-&amp;gt;redis-&amp;gt;get(&quot;cache:$key&quot;);
    }
    
    public function set($key, $value, $ttl = 3600) {
        return $this-&amp;gt;redis-&amp;gt;setex(&quot;cache:$key&quot;, $ttl, $value);
    }
    
    public function invalidate($key) {
        return $this-&amp;gt;redis-&amp;gt;del(&quot;cache:$key&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Monitoring Integration&lt;/h2&gt;
&lt;p&gt;Setting up comprehensive monitoring in CloudPanel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class ApplicationMonitor {
    private static $metrics = [];
    
    public static function recordMetric($name, $value) {
        self::$metrics[$name][] = $value;
    }
    
    public static function getAverageMetric($name) {
        if (!isset(self::$metrics[$name])) {
            return null;
        }
        return array_sum(self::$metrics[$name]) / count(self::$metrics[$name]);
    }
    
    public static function logMetrics() {
        foreach (self::$metrics as $name =&amp;gt; $values) {
            error_log(sprintf(
                &quot;Metric %s: Avg=%f, Min=%f, Max=%f&quot;,
                $name,
                array_sum($values) / count($values),
                min($values),
                max($values)
            ));
        }
    }
}

// Usage in application
register_shutdown_function(function() {
    ApplicationMonitor::logMetrics();
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Results After Optimization&lt;/h2&gt;
&lt;p&gt;Our optimization efforts yielded impressive results:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Memory Usage: Reduced from 2GB to 384MB&lt;/li&gt;
&lt;li&gt;Response Time: Improved from 800ms to 150ms&lt;/li&gt;
&lt;li&gt;CPU Utilization: Decreased from 75% to 30%&lt;/li&gt;
&lt;li&gt;PHP-FPM Process Count: Optimized from 100 to 50&lt;/li&gt;
&lt;li&gt;Monthly Costs: Reduced by 80% (Digital Ocean)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;CloudPanel Configuration Best Practices&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;PHP Configuration:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;; php.ini optimizations
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1

realpath_cache_size = 4096K
realpath_cache_ttl = 600
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Nginx Configuration:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Monitoring Setup in CloudPanel&lt;/h2&gt;
&lt;p&gt;Enable comprehensive monitoring:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Application-level monitoring
function monitor_application_metrics() {
    $metrics = [
        &apos;memory_usage&apos; =&amp;gt; memory_get_usage(true),
        &apos;peak_memory&apos; =&amp;gt; memory_get_peak_usage(true),
        &apos;cpu_usage&apos; =&amp;gt; sys_getloadavg()[0],
        &apos;php_fpm_processes&apos; =&amp;gt; shell_exec(&apos;ps aux | grep php-fpm | wc -l&apos;)
    ];
    
    file_put_contents(
        &apos;/var/log/php/metrics.log&apos;,
        date(&apos;Y-m-d H:i:s&apos;) . &apos; &apos; . json_encode($metrics) . &quot;\n&quot;,
        FILE_APPEND
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Additional Performance Tips&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Implement proper error handling:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;set_error_handler(function($errno, $errstr, $errfile, $errline) {
    error_log(sprintf(
        &quot;Error [%d]: %s in %s on line %d&quot;,
        $errno,
        $errstr,
        $errfile,
        $errline
    ));
    return true;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Use proper autoloading:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;spl_autoload_register(function ($class) {
    include __DIR__ . &apos;/classes/&apos; . $class . &apos;.php&apos;;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This optimization journey transformed our PHP application from a resource-hungry system into an efficient, cost-effective solution. The key was understanding PHP&apos;s memory model, leveraging CloudPanel&apos;s tools, and implementing proper caching and connection management strategies.&lt;/p&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 1</title><link>https://hhf.technology/blog/cloudpanel-security-part1/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part1/</guid><description>Detailed security measures specifically tailored for CloudPanel&apos;s architecture</description><pubDate>Wed, 13 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Securing CloudPanel on Ubuntu 24.04: A Comprehensive Guide&lt;/h1&gt;
&lt;h1&gt;Part 1: Initial Server Access and Core Configuration&lt;/h1&gt;
&lt;h3&gt;1. Initial SSH Security Configuration&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Edit SSH configuration
sudo nano /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add these security-focused settings:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# SSH Security Configuration
Port 2222                    # Custom SSH port
PermitRootLogin no          # Disable root login
PasswordAuthentication no   # Key-based auth only
Protocol 2                 # SSHv2 only
MaxAuthTries 3            # Limit auth attempts
ClientAliveInterval 300  # 5-min timeout
X11Forwarding no        # Disable X11 forwarding
AllowTcpForwarding no  # Disable TCP forwarding
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restart SSH:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart sshd
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. CloudPanel-Specific Firewall Rules&lt;/h3&gt;
&lt;p&gt;Configure UFW based on CloudPanel&apos;s database structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Configure UFW rules based on CloudPanel&apos;s firewall_rule table
sqlite3 /home/clp/htdocs/app/data/db.sq3 &amp;lt;&amp;lt; EOF
INSERT INTO firewall_rule (created_at, updated_at, port_range, source, description)
VALUES 
    (datetime(&apos;now&apos;), datetime(&apos;now&apos;), &apos;8443&apos;, &apos;0.0.0.0/0&apos;, &apos;CloudPanel Admin Interface&apos;),
    (datetime(&apos;now&apos;), datetime(&apos;now&apos;), &apos;80&apos;, &apos;0.0.0.0/0&apos;, &apos;HTTP&apos;),
    (datetime(&apos;now&apos;), datetime(&apos;now&apos;), &apos;443&apos;, &apos;0.0.0.0/0&apos;, &apos;HTTPS&apos;),
    (datetime(&apos;now&apos;), datetime(&apos;now&apos;), &apos;2222&apos;, &apos;0.0.0.0/0&apos;, &apos;Custom SSH Port&apos;);
EOF

# Apply UFW rules
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 8443/tcp comment &apos;CloudPanel Admin&apos;
sudo ufw allow 80/tcp comment &apos;HTTP&apos;
sudo ufw allow 443/tcp comment &apos;HTTPS&apos;
sudo ufw allow 2222/tcp comment &apos;SSH&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. Database Security and Monitoring&lt;/h3&gt;
&lt;p&gt;Setup database security using CloudPanel&apos;s structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Set proper permissions
sudo chown clp:clp /home/clp/htdocs/app/data/db.sq3
sudo chmod 770 /home/clp/htdocs/app/data/db.sq3

# Create automated database backup script
sudo nano /usr/local/bin/cloudpanel-db-backup.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Database backup script
CP_HOME=&quot;/home/clp&quot;
DB_PATH=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
BACKUP_DIR=&quot;${CP_HOME}/backups/database&quot;
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p &quot;$BACKUP_DIR&quot;

# Create backup with proper permissions
sqlite3 &quot;$DB_PATH&quot; &quot;.backup &apos;${BACKUP_DIR}/db_${TIMESTAMP}.sq3&apos;&quot;
chmod 640 &quot;${BACKUP_DIR}/db_${TIMESTAMP}.sq3&quot;
chown clp:clp &quot;${BACKUP_DIR}/db_${TIMESTAMP}.sq3&quot;

# Keep only last 7 days of backups
find &quot;$BACKUP_DIR&quot; -name &quot;db_*.sq3&quot; -mtime +7 -delete

# Log backup event in CloudPanel&apos;s event table
sqlite3 &quot;$DB_PATH&quot; &quot;
    INSERT INTO event (
        created_at,
        user_name,
        event_name,
        event_data
    ) VALUES (
        datetime(&apos;now&apos;),
        &apos;system&apos;,
        &apos;database_backup&apos;,
        &apos;Database backup created: db_${TIMESTAMP}.sq3&apos;
    );&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 10</title><link>https://hhf.technology/blog/cloudpanel-security-part10/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part10/</guid><description>Automated Incident Response and Recovery System</description><pubDate>Thu, 21 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Part 10: Automated Incident Response and Recovery System&lt;/h1&gt;
&lt;p&gt;Let&apos;s create a comprehensive incident response system that automatically detects and handles security incidents while maintaining proper logging in CloudPanel.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create incident response management script
sudo nano /usr/local/bin/cloudpanel-incident-response.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Initialize paths and configuration
CP_HOME=&quot;/home/clp&quot;
DB_PATH=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
INCIDENT_DIR=&quot;${CP_HOME}/logs/incidents&quot;
BACKUP_DIR=&quot;${CP_HOME}/backups/incidents&quot;

# Create necessary directories
mkdir -p &quot;$INCIDENT_DIR&quot; &quot;$BACKUP_DIR&quot;

# Function to detect and categorize security incidents
detect_security_incidents() {
    echo &quot;Analyzing security incidents...&quot;
    
    # Query CloudPanel&apos;s event table for potential incidents
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            e.id,
            e.created_at,
            e.user_name,
            e.event_name,
            e.event_data,
            e.source_ip_address,
            e.user_agent
        FROM event e
        WHERE e.created_at &amp;gt; datetime(&apos;now&apos;, &apos;-15 minutes&apos;)
        AND e.event_name IN (
            &apos;login_failed&apos;,
            &apos;unauthorized_access&apos;,
            &apos;file_modification&apos;,
            &apos;config_change&apos;,
            &apos;malware_detected&apos;
        )
        ORDER BY e.created_at DESC;&quot; | while IFS=&apos;|&apos; read -r event_id timestamp username event_name data ip agent; do
        
        case &quot;$event_name&quot; in
            &quot;login_failed&quot;)
                handle_authentication_incident &quot;$event_id&quot; &quot;$ip&quot; &quot;$username&quot;
                ;;
            &quot;unauthorized_access&quot;)
                handle_access_violation &quot;$event_id&quot; &quot;$ip&quot; &quot;$data&quot;
                ;;
            &quot;file_modification&quot;)
                handle_file_incident &quot;$event_id&quot; &quot;$username&quot; &quot;$data&quot;
                ;;
            &quot;malware_detected&quot;)
                handle_malware_incident &quot;$event_id&quot; &quot;$data&quot;
                ;;
            *)
                log_unknown_incident &quot;$event_id&quot; &quot;$event_name&quot; &quot;$data&quot;
                ;;
        esac
    done
}

# Function to handle authentication-related incidents
handle_authentication_incident() {
    local event_id=&quot;$1&quot;
    local ip=&quot;$2&quot;
    local username=&quot;$3&quot;
    
    # Check for brute force patterns
    local failed_attempts=$(sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT COUNT(*) FROM event
        WHERE source_ip_address = &apos;$ip&apos;
        AND event_name = &apos;login_failed&apos;
        AND created_at &amp;gt; datetime(&apos;now&apos;, &apos;-1 hour&apos;);&quot;)
    
    if [ &quot;$failed_attempts&quot; -gt 5 ]; then
        # Implement automatic IP blocking
        sqlite3 &quot;$DB_PATH&quot; &quot;
            INSERT INTO blocked_ip (
                created_at,
                updated_at,
                ip
            ) VALUES (
                datetime(&apos;now&apos;),
                datetime(&apos;now&apos;),
                &apos;$ip&apos;
            );&quot;
        
        # Create a high-priority notification
        create_incident_notification \
            &quot;Brute Force Attack Detected&quot; \
            &quot;Multiple failed login attempts from IP: $ip targeting user: $username&quot; \
            &quot;high&quot;
            
        # Update firewall rules
        update_firewall_rules &quot;$ip&quot;
    fi
}

# Function to handle file system incidents
handle_file_incident() {
    local event_id=&quot;$1&quot;
    local username=&quot;$2&quot;
    local file_data=&quot;$3&quot;
    
    # Extract file information
    local file_path=$(echo &quot;$file_data&quot; | jq -r &apos;.path&apos;)
    local modification_type=$(echo &quot;$file_data&quot; | jq -r &apos;.type&apos;)
    
    # Create incident snapshot
    local snapshot_dir=&quot;${BACKUP_DIR}/file_incident_$(date +%Y%m%d_%H%M%S)&quot;
    mkdir -p &quot;$snapshot_dir&quot;
    
    if [ -f &quot;$file_path&quot; ]; then
        # Create file backup
        cp -p &quot;$file_path&quot; &quot;$snapshot_dir/&quot;
        
        # Record file metadata
        stat &quot;$file_path&quot; &amp;gt; &quot;${snapshot_dir}/file_metadata.txt&quot;
        
        # Check for suspicious content
        if grep -qiE &quot;eval|base64_decode|system|exec&quot; &quot;$file_path&quot;; then
            # Quarantine suspicious file
            local quarantine_dir=&quot;${CP_HOME}/quarantine/files&quot;
            mkdir -p &quot;$quarantine_dir&quot;
            mv &quot;$file_path&quot; &quot;${quarantine_dir}/$(basename &quot;$file_path&quot;).$(date +%s)&quot;
            
            create_incident_notification \
                &quot;Suspicious File Detected&quot; \
                &quot;File containing potentially malicious code: $file_path&quot; \
                &quot;critical&quot;
        fi
    fi
}

# Function to handle malware incidents
handle_malware_incident() {
    local event_id=&quot;$1&quot;
    local malware_data=&quot;$2&quot;
    
    # Extract malware information
    local infected_path=$(echo &quot;$malware_data&quot; | jq -r &apos;.path&apos;)
    local malware_type=$(echo &quot;$malware_data&quot; | jq -r &apos;.type&apos;)
    
    # Create quarantine directory
    local quarantine_dir=&quot;${CP_HOME}/quarantine/malware/$(date +%Y%m%d)&quot;
    mkdir -p &quot;$quarantine_dir&quot;
    
    if [ -e &quot;$infected_path&quot; ]; then
        # Quarantine the infected file/directory
        mv &quot;$infected_path&quot; &quot;$quarantine_dir/&quot;
        
        # Record incident details
        echo &quot;Quarantined at: $(date)&quot; &amp;gt; &quot;${quarantine_dir}/incident_details.txt&quot;
        echo &quot;Original location: $infected_path&quot; &amp;gt;&amp;gt; &quot;${quarantine_dir}/incident_details.txt&quot;
        echo &quot;Malware type: $malware_type&quot; &amp;gt;&amp;gt; &quot;${quarantine_dir}/incident_details.txt&quot;
        
        create_incident_notification \
            &quot;Malware Detected&quot; \
            &quot;Malware type &apos;$malware_type&apos; detected at: $infected_path&quot; \
            &quot;critical&quot;
            
        # Trigger additional security scans
        initiate_security_scan &quot;$(dirname &quot;$infected_path&quot;)&quot;
    fi
}

# Function to create incident notifications in CloudPanel
create_incident_notification() {
    local subject=&quot;$1&quot;
    local message=&quot;$2&quot;
    local severity=&quot;$3&quot;
    
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO notification (
            created_at,
            updated_at,
            severity,
            subject,
            message,
            is_read
        ) VALUES (
            datetime(&apos;now&apos;),
            datetime(&apos;now&apos;),
            &apos;$severity&apos;,
            &apos;$subject&apos;,
            &apos;$message&apos;,
            0
        );&quot;
}

# Function to update firewall rules
update_firewall_rules() {
    local ip=&quot;$1&quot;
    
    echo &quot;Updating firewall rules for IP: $ip&quot;
    
    # Update CloudPanel&apos;s firewall rules
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO firewall_rule (
            created_at,
            updated_at,
            port_range,
            source,
            description
        ) VALUES (
            datetime(&apos;now&apos;),
            datetime(&apos;now&apos;),
            &apos;ALL&apos;,
            &apos;$ip&apos;,
            &apos;Automatically blocked due to security incident&apos;
        );&quot;
    
    # Apply firewall rules
    ufw deny from &quot;$ip&quot; to any comment &quot;Auto-blocked by incident response&quot;
}

# Function to initiate security scans
initiate_security_scan() {
    local target_path=&quot;$1&quot;
    
    echo &quot;Initiating security scan for: $target_path&quot;
    
    # Record scan initiation
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO event (
            created_at,
            user_name,
            event_name,
            event_data
        ) VALUES (
            datetime(&apos;now&apos;),
            &apos;system&apos;,
            &apos;security_scan_initiated&apos;,
            &apos;{\&quot;path\&quot;: \&quot;$target_path\&quot;}&apos;
        );&quot;
    
    # Schedule immediate malware scan
    clamscan -r &quot;$target_path&quot; --move=&quot;${CP_HOME}/quarantine/malware&quot;
}

# Function to generate incident reports
generate_incident_report() {
    local report_file=&quot;${INCIDENT_DIR}/incident_report_$(date +%Y%m%d).txt&quot;
    
    echo &quot;Generating incident report...&quot;
    
    {
        echo &quot;CloudPanel Incident Report - $(date)&quot;
        echo &quot;=================================&quot;
        
        echo -e &quot;\nSecurity Incidents Summary:&quot;
        sqlite3 &quot;$DB_PATH&quot; &quot;
            SELECT 
                event_name,
                COUNT(*) as count,
                MIN(created_at) as first_seen,
                MAX(created_at) as last_seen
            FROM event
            WHERE created_at &amp;gt; datetime(&apos;now&apos;, &apos;-24 hours&apos;)
            AND event_name IN (
                &apos;login_failed&apos;,
                &apos;unauthorized_access&apos;,
                &apos;file_modification&apos;,
                &apos;malware_detected&apos;
            )
            GROUP BY event_name;&quot;
        
        echo -e &quot;\nBlocked IPs:&quot;
        sqlite3 &quot;$DB_PATH&quot; &quot;
            SELECT ip, created_at 
            FROM blocked_ip 
            WHERE created_at &amp;gt; datetime(&apos;now&apos;, &apos;-24 hours&apos;);&quot;
        
        echo -e &quot;\nQuarantined Files:&quot;
        find &quot;${CP_HOME}/quarantine&quot; -type f -mtime -1 -ls
        
    } &amp;gt; &quot;$report_file&quot;
}

# Main execution
main() {
    echo &quot;Starting incident response system...&quot;
    
    while true; do
        # Detect and handle incidents
        detect_security_incidents
        
        # Generate daily incident report at midnight
        if [ &quot;$(date +%H:%M)&quot; = &quot;00:00&quot; ]; then
            generate_incident_report
        fi
        
        # Sleep for monitoring interval
        sleep 300
    done
}

main &quot;$@&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This incident response system provides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Automated detection and response to security incidents using CloudPanel&apos;s event system&lt;/li&gt;
&lt;li&gt;Integration with CloudPanel&apos;s notification and security tables&lt;/li&gt;
&lt;li&gt;Automatic quarantine of suspicious files and malware&lt;/li&gt;
&lt;li&gt;IP blocking for brute force attempts&lt;/li&gt;
&lt;li&gt;Detailed incident reporting and logging&lt;/li&gt;
&lt;li&gt;Automated security scanning when incidents are detected&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To implement this incident response system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Make the script executable
chmod +x /usr/local/bin/cloudpanel-incident-response.sh

# Run the script as a service
sudo systemctl enable cloudpanel-incident-response
sudo systemctl start cloudpanel-incident-response
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 11</title><link>https://hhf.technology/blog/cloudpanel-security-part11/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part11/</guid><description>Automated Backup and Disaster Recovery System</description><pubDate>Fri, 22 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Part 11: Automated Backup and Disaster Recovery System&lt;/h1&gt;
&lt;p&gt;Let&apos;s create a comprehensive backup and recovery system that ensures both data integrity and quick recovery capabilities.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Create backup management script
sudo nano /usr/local/bin/cloudpanel-backup-manager.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Initialize paths and configuration
CP_HOME=&quot;/home/clp&quot;
DB_PATH=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
BACKUP_ROOT=&quot;/backup/cloudpanel&quot;
LOG_DIR=&quot;${CP_HOME}/logs/backup&quot;
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# Create necessary directories
mkdir -p &quot;${BACKUP_ROOT}/{system,sites,databases,ssl,logs}&quot; &quot;$LOG_DIR&quot;

# Function to read site configurations from CloudPanel database
get_site_configurations() {
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            s.id,
            s.domain_name,
            s.user,
            s.root_directory,
            d.name as db_name
        FROM site s
        LEFT JOIN database d ON s.id = d.site_id
        WHERE s.type = &apos;vhost&apos;;&quot;
}

# Function to backup CloudPanel system files
backup_system_files() {
    local backup_dir=&quot;${BACKUP_ROOT}/system/${TIMESTAMP}&quot;
    echo &quot;Backing up system files to $backup_dir&quot;
    
    # Create backup directories
    mkdir -p &quot;$backup_dir&quot;/{config,services,database,ssl}
    
    # Backup core configuration
    tar -czf &quot;$backup_dir/config/cloudpanel_config.tar.gz&quot; \
        &quot;${CP_HOME}/services/nginx/nginx.conf&quot; \
        &quot;${CP_HOME}/services/php-fpm&quot; \
        &quot;${CP_HOME}/services/nginx/sites-enabled&quot; \
        --exclude=&apos;*.log&apos;
    
    # Backup SSL certificates
    cp -r &quot;${CP_HOME}/services/nginx/ssl-certificates&quot; &quot;$backup_dir/ssl/&quot;
    
    # Backup CloudPanel database
    sqlite3 &quot;$DB_PATH&quot; &quot;.backup &apos;${backup_dir}/database/cloudpanel.sq3&apos;&quot;
    
    # Create backup manifest
    {
        echo &quot;CloudPanel System Backup - $(date)&quot;
        echo &quot;=================================&quot;
        echo &quot;Backup Type: System Files&quot;
        echo &quot;Timestamp: $TIMESTAMP&quot;
        find &quot;$backup_dir&quot; -type f -exec ls -lh {} \;
    } &amp;gt; &quot;$backup_dir/MANIFEST.txt&quot;
}

# Function to backup individual sites
backup_site() {
    local domain=&quot;$1&quot;
    local user=&quot;$2&quot;
    local root_dir=&quot;$3&quot;
    local db_name=&quot;$4&quot;
    
    local site_backup_dir=&quot;${BACKUP_ROOT}/sites/${domain}/${TIMESTAMP}&quot;
    echo &quot;Backing up site: $domain to $site_backup_dir&quot;
    
    # Create site backup directory
    mkdir -p &quot;$site_backup_dir&quot;/{files,database,logs,config}
    
    # Backup site files
    tar -czf &quot;$site_backup_dir/files/site_files.tar.gz&quot; \
        &quot;$root_dir&quot; \
        --exclude=&apos;*/cache/*&apos; \
        --exclude=&apos;*/tmp/*&apos; \
        --exclude=&apos;*/logs/*&apos;
    
    # Backup site database if exists
    if [ ! -z &quot;$db_name&quot; ]; then
        mysqldump --single-transaction \
            --quick \
            --lock-tables=false \
            &quot;$db_name&quot; &amp;gt; &quot;$site_backup_dir/database/${db_name}.sql&quot;
        
        # Compress database backup
        gzip &quot;$site_backup_dir/database/${db_name}.sql&quot;
    fi
    
    # Backup site configuration
    cp &quot;/home/clp/services/nginx/sites-enabled/${domain}.conf&quot; \
        &quot;$site_backup_dir/config/&quot;
    
    # Create site backup manifest
    {
        echo &quot;Site Backup - $domain&quot;
        echo &quot;=================================&quot;
        echo &quot;Backup Type: Site Files and Configuration&quot;
        echo &quot;Timestamp: $TIMESTAMP&quot;
        echo &quot;User: $user&quot;
        echo &quot;Database: $db_name&quot;
        find &quot;$site_backup_dir&quot; -type f -exec ls -lh {} \;
    } &amp;gt; &quot;$site_backup_dir/MANIFEST.txt&quot;
}

# Function to verify backup integrity
verify_backup() {
    local backup_dir=&quot;$1&quot;
    local backup_type=&quot;$2&quot;
    local verification_log=&quot;${LOG_DIR}/verification_${TIMESTAMP}.log&quot;
    
    echo &quot;Verifying backup integrity for $backup_type&quot;
    
    # Verify tar archives
    find &quot;$backup_dir&quot; -name &quot;*.tar.gz&quot; -type f | while read -r archive; do
        if ! tar -tzf &quot;$archive&quot; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then
            echo &quot;ERROR: Corrupt archive detected: $archive&quot; &amp;gt;&amp;gt; &quot;$verification_log&quot;
            return 1
        fi
    done
    
    # Verify database backups
    find &quot;$backup_dir&quot; -name &quot;*.sql.gz&quot; -type f | while read -r db_backup; do
        if ! gunzip -t &quot;$db_backup&quot; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then
            echo &quot;ERROR: Corrupt database backup detected: $db_backup&quot; &amp;gt;&amp;gt; &quot;$verification_log&quot;
            return 1
        fi
    done
    
    # Record successful verification
    echo &quot;Backup verification completed successfully for $backup_type&quot; &amp;gt;&amp;gt; &quot;$verification_log&quot;
    return 0
}

# Function to handle backup rotation
rotate_backups() {
    local backup_path=&quot;$1&quot;
    local retention_days=7
    
    echo &quot;Rotating old backups in $backup_path&quot;
    
    # Remove backups older than retention period
    find &quot;$backup_path&quot; -type d -mtime +$retention_days -exec rm -rf {} \;
}

# Function to create recovery script
create_recovery_script() {
    local backup_dir=&quot;$1&quot;
    local recovery_script=&quot;${backup_dir}/recover.sh&quot;
    
    cat &amp;gt; &quot;$recovery_script&quot; &amp;lt;&amp;lt;&apos;EOF&apos;
#!/bin/bash

# CloudPanel Recovery Script
CP_HOME=&quot;/home/clp&quot;

# Verify environment
if [ ! -d &quot;$CP_HOME&quot; ]; then
    echo &quot;ERROR: CloudPanel directory not found!&quot;
    exit 1
fi

# Restore system files
restore_system_files() {
    echo &quot;Restoring system files...&quot;
    tar -xzf config/cloudpanel_config.tar.gz -C /
    
    # Restore SSL certificates
    cp -r ssl/* &quot;${CP_HOME}/services/nginx/ssl-certificates/&quot;
    
    # Restore database
    sqlite3 &quot;${CP_HOME}/htdocs/app/data/db.sq3&quot; &quot;.restore &apos;database/cloudpanel.sq3&apos;&quot;
}

# Restore site data
restore_site() {
    local site_dir=&quot;$1&quot;
    
    echo &quot;Restoring site from: $site_dir&quot;
    
    # Restore site files
    tar -xzf &quot;${site_dir}/files/site_files.tar.gz&quot; -C /
    
    # Restore database if exists
    for db_backup in &quot;${site_dir}&quot;/database/*.sql.gz; do
        if [ -f &quot;$db_backup&quot; ]; then
            local db_name=$(basename &quot;$db_backup&quot; .sql.gz)
            gunzip -c &quot;$db_backup&quot; | mysql &quot;$db_name&quot;
        fi
    done
    
    # Restore configuration
    cp &quot;${site_dir}&quot;/config/* &quot;${CP_HOME}/services/nginx/sites-enabled/&quot;
}

# Main recovery process
main() {
    echo &quot;Starting CloudPanel recovery process...&quot;
    
    # Restore system components
    restore_system_files
    
    # Restore individual sites
    for site_backup in sites/*/${TIMESTAMP}; do
        if [ -d &quot;$site_backup&quot; ]; then
            restore_site &quot;$site_backup&quot;
        fi
    done
    
    # Restart services
    systemctl restart nginx php-fpm mysql
    
    echo &quot;Recovery process completed&quot;
}

main &quot;$@&quot;
EOF

    chmod +x &quot;$recovery_script&quot;
}

# Main execution
main() {
    echo &quot;Starting CloudPanel backup process...&quot;
    
    # Backup system files
    backup_system_files
    verify_backup &quot;${BACKUP_ROOT}/system/${TIMESTAMP}&quot; &quot;system&quot;
    
    # Backup individual sites
    while IFS=&apos;|&apos; read -r site_id domain user root_dir db_name; do
        backup_site &quot;$domain&quot; &quot;$user&quot; &quot;$root_dir&quot; &quot;$db_name&quot;
        verify_backup &quot;${BACKUP_ROOT}/sites/${domain}/${TIMESTAMP}&quot; &quot;site&quot;
    done &amp;lt; &amp;lt;(get_site_configurations)
    
    # Create recovery script
    create_recovery_script &quot;${BACKUP_ROOT}/system/${TIMESTAMP}&quot;
    
    # Rotate old backups
    rotate_backups &quot;$BACKUP_ROOT&quot;
    
    echo &quot;Backup process completed successfully&quot;
}

main &quot;$@&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This backup system provides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Comprehensive backup of CloudPanel system files&lt;/li&gt;
&lt;li&gt;Site-specific backups including files, databases, and configurations&lt;/li&gt;
&lt;li&gt;Backup verification and integrity checking&lt;/li&gt;
&lt;li&gt;Automated backup rotation&lt;/li&gt;
&lt;li&gt;Recovery script generation&lt;/li&gt;
&lt;li&gt;Integration with CloudPanel&apos;s database structure&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To implement this backup system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Make the script executable
chmod +x /usr/local/bin/cloudpanel-backup-manager.sh

# Add to crontab for daily execution
(crontab -l 2&amp;gt;/dev/null; echo &quot;0 2 * * * /usr/local/bin/cloudpanel-backup-manager.sh&quot;) | crontab -
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 12</title><link>https://hhf.technology/blog/cloudpanel-security-part12/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part12/</guid><description>Automated Updates and Patch Management</description><pubDate>Sat, 23 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Part 12: Automated Updates and Patch Management&lt;/h1&gt;
&lt;p&gt;This system will manage both CloudPanel-specific updates and system-level security patches while maintaining proper logging in CloudPanel.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create update management script
sudo nano /usr/local/bin/cloudpanel-update-manager.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Initialize paths and configuration
CP_HOME=&quot;/home/clp&quot;
DB_PATH=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
LOG_DIR=&quot;${CP_HOME}/logs/updates&quot;
BACKUP_DIR=&quot;${CP_HOME}/backups/updates&quot;

mkdir -p &quot;$LOG_DIR&quot; &quot;$BACKUP_DIR&quot;

# Function to get current CloudPanel version
get_cloudpanel_version() {
    sqlite3 &quot;$DB_PATH&quot; &quot;SELECT value FROM config WHERE key = &apos;app_version&apos;;&quot;
}

# Function to check system package updates
check_system_updates() {
    echo &quot;Checking system updates...&quot;
    
    # Update package lists
    apt-get update -qq
    
    # Get list of security updates
    local security_updates=$(apt-get -s upgrade | grep -i security | wc -l)
    
    if [ &quot;$security_updates&quot; -gt 0 ]; then
        log_update_event &quot;security_updates_available&quot; &quot;Security updates available: $security_updates packages&quot;
        return 0
    fi
    return 1
}

# Function to verify PHP versions
check_php_versions() {
    echo &quot;Checking PHP versions...&quot;
    
    # Get installed PHP versions from database
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT DISTINCT php_version 
        FROM php_settings 
        WHERE site_id IN (
            SELECT id FROM site WHERE type = &apos;vhost&apos;
        );&quot; | while read -r version; do
        
        # Check if this PHP version needs updates
        if php_needs_update &quot;$version&quot;; then
            log_update_event &quot;php_update_required&quot; &quot;PHP version $version needs security updates&quot;
        fi
    done
}

# Function to backup before updates
backup_before_update() {
    local update_type=&quot;$1&quot;
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local backup_path=&quot;${BACKUP_DIR}/${update_type}_${timestamp}&quot;
    
    echo &quot;Creating pre-update backup...&quot;
    
    # Create backup directory
    mkdir -p &quot;$backup_path&quot;
    
    # Backup CloudPanel database
    sqlite3 &quot;$DB_PATH&quot; &quot;.backup &apos;${backup_path}/cloudpanel.sq3&apos;&quot;
    
    # Backup configuration files
    tar -czf &quot;${backup_path}/config.tar.gz&quot; \
        &quot;${CP_HOME}/services/nginx/nginx.conf&quot; \
        &quot;${CP_HOME}/services/php-fpm&quot; \
        &quot;${CP_HOME}/services/nginx/sites-enabled&quot; \
        --exclude=&apos;*.log&apos;
    
    echo &quot;$backup_path&quot;
}

# Function to apply system updates
apply_system_updates() {
    echo &quot;Applying system updates...&quot;
    
    # Create pre-update backup
    local backup_path=$(backup_before_update &quot;system&quot;)
    
    # Apply updates
    if DEBIAN_FRONTEND=noninteractive apt-get -y upgrade; then
        log_update_event &quot;system_update_success&quot; &quot;System updates applied successfully&quot;
    else
        log_update_event &quot;system_update_failed&quot; &quot;System update failed&quot;
        restore_from_backup &quot;$backup_path&quot;
        return 1
    fi
}

# Function to update PHP versions
update_php_version() {
    local version=&quot;$1&quot;
    echo &quot;Updating PHP version $version...&quot;
    
    # Create backup
    local backup_path=$(backup_before_update &quot;php_${version}&quot;)
    
    # Update PHP packages
    if apt-get install -y &quot;php${version}-fpm&quot; &quot;php${version}-common&quot; &quot;php${version}-cli&quot;; then
        log_update_event &quot;php_update_success&quot; &quot;PHP $version updated successfully&quot;
        
        # Restart PHP-FPM service
        systemctl restart &quot;php${version}-fpm&quot;
    else
        log_update_event &quot;php_update_failed&quot; &quot;PHP $version update failed&quot;
        restore_from_backup &quot;$backup_path&quot;
        return 1
    fi
}

# Function to verify system integrity after updates
verify_system_integrity() {
    echo &quot;Verifying system integrity...&quot;
    local integrity_check=0
    
    # Check critical services
    local services=(&quot;nginx&quot; &quot;mysql&quot;)
    for service in &quot;${services[@]}&quot;; do
        if ! systemctl is-active --quiet &quot;$service&quot;; then
            log_update_event &quot;service_check_failed&quot; &quot;Service $service is not running after update&quot;
            integrity_check=1
        fi
    done
    
    # Check PHP-FPM pools
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT DISTINCT php_version 
        FROM php_settings;&quot; | while read -r version; do
        if ! systemctl is-active --quiet &quot;php${version}-fpm&quot;; then
            log_update_event &quot;php_check_failed&quot; &quot;PHP-FPM $version is not running after update&quot;
            integrity_check=1
        fi
    done
    
    # Verify CloudPanel database
    if ! sqlite3 &quot;$DB_PATH&quot; &quot;PRAGMA integrity_check;&quot;; then
        log_update_event &quot;database_check_failed&quot; &quot;Database integrity check failed after update&quot;
        integrity_check=1
    fi
    
    return $integrity_check
}

# Function to restore from backup
restore_from_backup() {
    local backup_path=&quot;$1&quot;
    echo &quot;Restoring from backup: $backup_path&quot;
    
    # Restore CloudPanel database
    sqlite3 &quot;$DB_PATH&quot; &quot;.restore &apos;${backup_path}/cloudpanel.sq3&apos;&quot;
    
    # Restore configuration files
    tar -xzf &quot;${backup_path}/config.tar.gz&quot; -C /
    
    # Restart services
    systemctl restart nginx php-fpm mysql
    
    log_update_event &quot;system_restored&quot; &quot;System restored from backup after failed update&quot;
}

# Function to log update events in CloudPanel&apos;s database
log_update_event() {
    local event_name=&quot;$1&quot;
    local event_data=&quot;$2&quot;
    
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO event (
            created_at,
            user_name,
            event_name,
            event_data
        ) VALUES (
            datetime(&apos;now&apos;),
            &apos;system&apos;,
            &apos;update_$event_name&apos;,
            &apos;$event_data&apos;
        );&quot;
}

# Function to create update report
create_update_report() {
    local report_file=&quot;${LOG_DIR}/update_report_$(date +%Y%m%d).txt&quot;
    
    {
        echo &quot;CloudPanel Update Report - $(date)&quot;
        echo &quot;=================================&quot;
        
        echo -e &quot;\nSystem Updates:&quot;
        sqlite3 &quot;$DB_PATH&quot; &quot;
            SELECT created_at, event_data 
            FROM event 
            WHERE event_name LIKE &apos;update_%&apos;
            AND created_at &amp;gt; datetime(&apos;now&apos;, &apos;-24 hours&apos;)
            ORDER BY created_at DESC;&quot;
        
        echo -e &quot;\nInstalled PHP Versions:&quot;
        sqlite3 &quot;$DB_PATH&quot; &quot;
            SELECT DISTINCT php_version, COUNT(*) as sites
            FROM php_settings
            GROUP BY php_version;&quot;
        
        echo -e &quot;\nService Status:&quot;
        systemctl status nginx mysql | grep Active
        
    } &amp;gt; &quot;$report_file&quot;
}

# Main execution
main() {
    echo &quot;Starting update management system...&quot;
    
    # Check for updates
    if check_system_updates; then
        # Apply system updates
        apply_system_updates
    fi
    
    # Check PHP versions
    check_php_versions
    
    # Verify system integrity
    if ! verify_system_integrity; then
        log_update_event &quot;integrity_check_failed&quot; &quot;System integrity check failed after updates&quot;
    fi
    
    # Create update report
    create_update_report
    
    echo &quot;Update management completed&quot;
}

main &quot;$@&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This update management system provides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Automated system updates with pre-update backups&lt;/li&gt;
&lt;li&gt;PHP version management integrated with CloudPanel&apos;s configuration&lt;/li&gt;
&lt;li&gt;System integrity verification&lt;/li&gt;
&lt;li&gt;Automatic rollback capabilities&lt;/li&gt;
&lt;li&gt;Detailed update logging in CloudPanel&apos;s event system&lt;/li&gt;
&lt;li&gt;Update reporting and monitoring&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To implement this update management system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Make the script executable
chmod +x /usr/local/bin/cloudpanel-update-manager.sh

# Add to crontab for weekly execution
(crontab -l 2&amp;gt;/dev/null; echo &quot;0 3 * * 0 /usr/local/bin/cloudpanel-update-manager.sh&quot;) | crontab -
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 2</title><link>https://hhf.technology/blog/cloudpanel-security-part2/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part2/</guid><description>Service Security and Advanced Monitoring</description><pubDate>Thu, 14 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Part 2: Service Security and Advanced Monitoring&lt;/h1&gt;
&lt;h3&gt;1. Service Security Integration&lt;/h3&gt;
&lt;p&gt;Let&apos;s implement comprehensive service monitoring:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create service monitoring script
sudo nano /usr/local/bin/cloudpanel-service-monitor.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

set -euo pipefail

# Configuration
ENABLE_EMAIL=&quot;false&quot;
ENABLE_DISCORD=&quot;true&quot;
DISCORD_WEBHOOK_URL=&quot;https://discord.com/api/webhooks/your/yourapi&quot;
GMAIL_USER=&quot;your-gmail@gmail.com&quot;
GMAIL_APP_PASSWORD=&quot;your-app-password&quot;
EMAIL_TO=&quot;your-org-email@domain.com&quot;

# CloudPanel specific paths
CP_HOME=&quot;/home/clp&quot;
CP_DB=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
SITES_ROOT=&quot;/home&quot;

# Thresholds
CPU_THRESHOLD=80
MEMORY_THRESHOLD=90
PROCESS_THRESHOLD=500
DISK_THRESHOLD=90
ERROR_LOG_THRESHOLD=$((1024*1024*10))  # 10MB
HTTP_ERROR_THRESHOLD=100
CHECK_INTERVAL=300

# Setup
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
OUTPUT_DIR=&quot;/var/log/cloudpanel_monitoring&quot;
ALERT_LOG=&quot;${OUTPUT_DIR}/alerts.log&quot;
mkdir -p &quot;${OUTPUT_DIR}&quot;

# Colors
RED=&apos;\033[0;31m&apos;
GREEN=&apos;\033[0;32m&apos;
YELLOW=&apos;\033[1;33m&apos;
BLUE=&apos;\033[0;34m&apos;
NC=&apos;\033[0m&apos;

log() {
    echo -e &quot;${2}[$(date &apos;+%Y-%m-%d %H:%M:%S&apos;)] ${1}${NC}&quot; | tee -a &quot;${OUTPUT_DIR}/monitoring.log&quot;
}

log_event() {
    local event_name=&quot;$1&quot;
    local event_data=&quot;$2&quot;
    local severity=&quot;${3:-normal}&quot;
    
    # Log to CloudPanel database
    sqlite3 &quot;$CP_DB&quot; &quot;
        INSERT INTO event (
            created_at,
            user_name,
            user_role,
            event_name,
            event_data,
            source_ip_address,
            user_agent
        ) VALUES (
            datetime(&apos;now&apos;),
            &apos;system&apos;,
            &apos;ROLE_ADMIN&apos;,
            &apos;$event_name&apos;,
            &apos;$event_data&apos;,
            &apos;localhost&apos;,
            &apos;system-monitor&apos;
        );&quot;
    
    # Create notification if severity is high
    if [ &quot;$severity&quot; = &quot;high&quot; ]; then
        # Generate a unique hash for the notification
        local hash=$(echo &quot;${event_name}${event_data}$(date +%s)&quot; | md5sum | cut -d&apos; &apos; -f1)
        
        sqlite3 &quot;$CP_DB&quot; &quot;
            INSERT INTO notification (
                created_at,
                updated_at,
                hash,
                severity,
                subject,
                message,
                is_read
            ) VALUES (
                datetime(&apos;now&apos;),
                datetime(&apos;now&apos;),
                &apos;$hash&apos;,
                &apos;high&apos;,
                &apos;$event_name&apos;,
                &apos;$event_data&apos;,
                0
            );&quot;
    fi
}

validate_config() {
    local has_error=false

    if [ &quot;$ENABLE_EMAIL&quot; = &quot;true&quot; ]; then
        if [ -z &quot;$GMAIL_USER&quot; ] || [ &quot;$GMAIL_USER&quot; = &quot;your-gmail@gmail.com&quot; ]; then
            log &quot;Error: GMAIL_USER not configured&quot; &quot;${RED}&quot;
            has_error=true
        fi
        if [ -z &quot;$GMAIL_APP_PASSWORD&quot; ] || [ &quot;$GMAIL_APP_PASSWORD&quot; = &quot;your-app-password&quot; ]; then
            log &quot;Error: GMAIL_APP_PASSWORD not configured&quot; &quot;${RED}&quot;
            has_error=true
        fi
        if [ -z &quot;$EMAIL_TO&quot; ] || [ &quot;$EMAIL_TO&quot; = &quot;your-org-email@domain.com&quot; ]; then
            log &quot;Error: EMAIL_TO not configured&quot; &quot;${RED}&quot;
            has_error=true
        fi
    fi

    if [ &quot;$ENABLE_DISCORD&quot; = &quot;true&quot; ]; then
        if [ -z &quot;$DISCORD_WEBHOOK_URL&quot; ] || \
           [ &quot;$DISCORD_WEBHOOK_URL&quot; = &quot;https://discord.com/api/webhooks/your/yourapi&quot; ] || \
           ! echo &quot;$DISCORD_WEBHOOK_URL&quot; | grep -q &quot;^https://discord.com/api/webhooks/[0-9]*/&quot;; then
            log &quot;Error: DISCORD_WEBHOOK_URL not properly configured&quot; &quot;${RED}&quot;
            log &quot;Please set ENABLE_DISCORD=false or configure a valid webhook URL&quot; &quot;${RED}&quot;
            ENABLE_DISCORD=false  # Disable Discord if URL is invalid
        fi
    fi

    if [ &quot;$has_error&quot; = &quot;true&quot; ]; then
        log &quot;Configuration validation failed. Please check settings.&quot; &quot;${RED}&quot;
        exit 1
    fi
}

send_discord_alert() {
    local title=&quot;$1&quot;
    local message=&quot;$2&quot;
    local priority=&quot;$3&quot;

    local escaped_title=$(echo &quot;$title&quot; | sed &apos;s/&quot;/\\&quot;/g&apos;)
    local escaped_message=$(echo &quot;$message&quot; | sed &apos;s/&quot;/\\&quot;/g&apos; | sed &apos;:a;N;$!ba;s/\n/\\n/g&apos;)
    local escaped_hostname=$(hostname | sed &apos;s/&quot;/\\&quot;/g&apos;)

    local color
    if [ &quot;$priority&quot; = &quot;high&quot; ]; then
        color=&quot;16711680&quot;
    else
        color=&quot;15844367&quot;
    fi

    local json_data
    printf -v json_data &apos;{
        &quot;embeds&quot;: [{
            &quot;title&quot;: &quot;%s&quot;,
            &quot;description&quot;: &quot;%s&quot;,
            &quot;color&quot;: %d,
            &quot;footer&quot;: {
                &quot;text&quot;: &quot;CloudPanel Monitoring - %s&quot;
            },
            &quot;timestamp&quot;: &quot;%s&quot;
        }]
    }&apos; &quot;$escaped_title&quot; &quot;$escaped_message&quot; &quot;$color&quot; &quot;$escaped_hostname&quot; &quot;$(date -u +%Y-%m-%dT%H:%M:%SZ)&quot;

    curl -s -H &quot;Content-Type: application/json&quot; -X POST -d &quot;${json_data}&quot; &quot;${DISCORD_WEBHOOK_URL}&quot;
}

send_gmail() {
    local subject=&quot;$1&quot;
    local message=&quot;$2&quot;
    local priority=&quot;$3&quot;

    local email_content=$(mktemp)
    
    cat &amp;gt; &quot;${email_content}&quot; &amp;lt;&amp;lt; EOF
From: ${GMAIL_USER}
To: ${EMAIL_TO}
Subject: $([ &quot;$priority&quot; = &quot;high&quot; ] &amp;amp;&amp;amp; echo &quot;[URGENT] &quot;)${subject}
MIME-Version: 1.0
Content-Type: text/plain; charset=&quot;UTF-8&quot;

${message}
EOF

    curl --url &quot;smtps://smtp.gmail.com:465&quot; \
         --ssl-reqd \
         --mail-from &quot;${GMAIL_USER}&quot; \
         --mail-rcpt &quot;${EMAIL_TO}&quot; \
         --upload-file &quot;${email_content}&quot; \
         --user &quot;${GMAIL_USER}:${GMAIL_APP_PASSWORD}&quot; \
         --silent

    rm -f &quot;${email_content}&quot;
}

send_alert() {
    local subject=&quot;$1&quot;
    local message=&quot;$2&quot;
    local priority=&quot;$3&quot;
    
    local formatted_message=&quot;
Server: $(hostname)
Time: $(date)

${message}

This is an automated alert from CloudPanel Monitoring System.&quot;
    
    if [ &quot;$ENABLE_EMAIL&quot; = &quot;true&quot; ]; then
        send_gmail &quot;${subject}&quot; &quot;${formatted_message}&quot; &quot;${priority}&quot;
        log &quot;Email alert sent: ${subject}&quot; &quot;${YELLOW}&quot;
    fi
    
    if [ &quot;$ENABLE_DISCORD&quot; = &quot;true&quot; ]; then
        send_discord_alert &quot;${subject}&quot; &quot;${formatted_message}&quot; &quot;${priority}&quot;
        log &quot;Discord alert sent: ${subject}&quot; &quot;${YELLOW}&quot;
    fi
    
    echo &quot;[$(date &apos;+%Y-%m-%d %H:%M:%S&apos;)] ${subject}&quot; &amp;gt;&amp;gt; &quot;${ALERT_LOG}&quot;
    log_event &quot;system_alert&quot; &quot;${subject}: ${message}&quot; &quot;${priority}&quot;
}

check_system_resources() {
    log &quot;Checking system resources...&quot; &quot;${BLUE}&quot;
    local timestamp=$(date &apos;+%Y-%m-%d %H:%M:%S&apos;)
    
    # CPU Usage
    local cpu_usage=$(top -bn1 | grep &quot;Cpu(s)&quot; | awk &apos;{print $2}&apos; | cut -d. -f1)
    sqlite3 &quot;$CP_DB&quot; &quot;INSERT INTO instance_cpu (created_at, value) VALUES (&apos;$timestamp&apos;, $cpu_usage);&quot;
    
    if [ &quot;${cpu_usage:-0}&quot; -gt &quot;$CPU_THRESHOLD&quot; ]; then
        local top_processes=$(ps aux --sort=-%cpu | head -n 6)
        send_alert &quot;High CPU Usage Alert&quot; &quot;CPU Usage: ${cpu_usage}%\n\nTop Processes:\n${top_processes}&quot; &quot;high&quot;
    fi
    
    # Memory Usage
    local memory_usage=$(free | grep Mem | awk &apos;{print ($3/$2 * 100)}&apos; | cut -d. -f1)
    sqlite3 &quot;$CP_DB&quot; &quot;INSERT INTO instance_memory (created_at, value) VALUES (&apos;$timestamp&apos;, $memory_usage);&quot;
    
    if [ &quot;${memory_usage:-0}&quot; -gt &quot;$MEMORY_THRESHOLD&quot; ]; then
        local memory_processes=$(ps aux --sort=-%mem | head -n 6)
        send_alert &quot;High Memory Usage Alert&quot; &quot;Memory Usage: ${memory_usage}%\n\nTop Memory Processes:\n${memory_processes}&quot; &quot;high&quot;
    fi
    
    # Load Average
    # Read and clean load average values
    read -r load1 load5 load15 _ _ &amp;lt; /proc/loadavg
    
    # Convert to float values and remove any extra content
    load1=$(printf &quot;%.2f&quot; &quot;${load1%%/*}&quot;)
    load5=$(printf &quot;%.2f&quot; &quot;${load5%%/*}&quot;)
    load15=$(printf &quot;%.2f&quot; &quot;${load15%%/*}&quot;)
    
    # Insert cleaned values into database
    sqlite3 &quot;$CP_DB&quot; &quot;
        INSERT INTO instance_load_average (created_at, period, value) 
        VALUES 
            (&apos;$timestamp&apos;, 1, $load1),
            (&apos;$timestamp&apos;, 5, $load5),
            (&apos;$timestamp&apos;, 15, $load15);&quot;
    
    # Process Count
    local process_count=$(ps aux | wc -l)
    if [ &quot;${process_count:-0}&quot; -gt &quot;$PROCESS_THRESHOLD&quot; ]; then
        send_alert &quot;High Process Count Alert&quot; &quot;Process Count: ${process_count}\n\nProcess List:\n$(ps aux | head -n 6)&quot; &quot;high&quot;
    fi
    
    # Disk Usage
    df -h | grep &apos;^/dev/&apos; | while read -r device size used avail use_percent mount; do
        local usage=${use_percent%\%}
        sqlite3 &quot;$CP_DB&quot; &quot;INSERT INTO instance_disk_usage (created_at, disk, value) VALUES (&apos;$timestamp&apos;, &apos;$mount&apos;, $usage);&quot;
        
        if [ &quot;${usage:-0}&quot; -gt &quot;$DISK_THRESHOLD&quot; ]; then
            local disk_info=$(df -h)
            send_alert &quot;High Disk Usage Alert&quot; &quot;Disk Usage: ${usage}%\n\nDisk Information:\n${disk_info}&quot; &quot;high&quot;
        fi
    done
}

check_services() {
    log &quot;Checking critical services...&quot; &quot;${BLUE}&quot;
    
    # Check basic services
    local basic_services=(&quot;nginx&quot; &quot;mysql&quot; &quot;varnish&quot; &quot;redis-server&quot;)
    for service in &quot;${basic_services[@]}&quot;; do
        if ! systemctl is-active --quiet &quot;$service&quot;; then
            send_alert &quot;Service Down Alert&quot; &quot;Service ${service} is not running!&quot; &quot;high&quot;
            log_event &quot;service_down&quot; &quot;Service ${service} is not running&quot; &quot;high&quot;
        fi
    done
    
    # Check PHP-FPM services from database
    local php_versions=$(sqlite3 &quot;$CP_DB&quot; &quot;SELECT DISTINCT php_version FROM php_settings WHERE php_version IS NOT NULL;&quot;)
    for version in $php_versions; do
        local service_name=&quot;php${version}-fpm&quot;
        if systemctl list-unit-files &quot;${service_name}.service&quot; &amp;amp;&amp;gt;/dev/null; then
            if ! systemctl is-active --quiet &quot;$service_name&quot;; then
                local status_details=$(systemctl status &quot;${service_name}&quot; 2&amp;gt;&amp;amp;1 | head -n 4)
                send_alert &quot;PHP-FPM Service Issue&quot; &quot;PHP ${version} FPM service is down!\n\nStatus Details:\n${status_details}&quot; &quot;high&quot;
                log_event &quot;php_fpm_down&quot; &quot;PHP-FPM ${version} is not running&quot; &quot;high&quot;
            fi
        fi
    done
}

check_website_resources() {
    log &quot;Checking website resources...&quot; &quot;${BLUE}&quot;
    
    # Query all active sites from database
    sqlite3 &quot;$CP_DB&quot; &quot;SELECT id, domain_name, user FROM site WHERE type = &apos;vhost&apos;;&quot; | while IFS=&apos;|&apos; read -r site_id domain user; do
        # Skip if user directory doesn&apos;t exist
        if [ ! -d &quot;${SITES_ROOT}/${user}&quot; ]; then
            continue
        fi
        
        # Check nginx logs
        local nginx_log_dir=&quot;${SITES_ROOT}/${user}/logs/nginx&quot;
        local access_log=&quot;${nginx_log_dir}/${domain}-access.log&quot;
        local error_log=&quot;${nginx_log_dir}/${domain}-error.log&quot;
        
        if [ -f &quot;$access_log&quot; ]; then
            # Check for high traffic IPs
            local high_traffic_ips=$(tail -n 1000 &quot;$access_log&quot; | awk &apos;{print $1}&apos; | sort | uniq -c | sort -nr | head -n 5)
            local top_ip_count=$(echo &quot;$high_traffic_ips&quot; | head -n 1 | awk &apos;{print $1}&apos;)
            
            if [ &quot;${top_ip_count:-0}&quot; -gt 500 ]; then
                send_alert &quot;High Traffic Alert&quot; &quot;High traffic detected for ${domain}:\n${high_traffic_ips}&quot; &quot;normal&quot;
                log_event &quot;high_traffic&quot; &quot;High traffic on ${domain}&quot; &quot;normal&quot;
            fi
            
            # Check for high error rates
            local error_count=$(tail -n 1000 &quot;$access_log&quot; | awk &apos;$9 ~ /^[45]/ {print $9}&apos; | wc -l)
            if [ &quot;${error_count:-0}&quot; -gt &quot;$HTTP_ERROR_THRESHOLD&quot; ]; then
                local error_details=$(tail -n 1000 &quot;$access_log&quot; | awk &apos;$9 ~ /^[45]/ {print $1,$9,$7}&apos; | tail -n 10)
                send_alert &quot;High Error Rate Alert&quot; &quot;Domain: ${domain}\nError count: ${error_count}\n\nLast errors:\n${error_details}&quot; &quot;high&quot;
                log_event &quot;high_error_rate&quot; &quot;High error rate on ${domain}: ${error_count} errors&quot; &quot;high&quot;
            fi
        fi
        
        # Check PHP logs
        local php_log_dir=&quot;${SITES_ROOT}/${user}/logs/php&quot;
        local php_error_log=&quot;${php_log_dir}/error.log&quot;
        if [ -f &quot;$php_error_log&quot; ]; then
            local log_size=$(stat -c %s &quot;$php_error_log&quot;)
            if [ &quot;${log_size:-0}&quot; -gt &quot;$ERROR_LOG_THRESHOLD&quot; ]; then
                send_alert &quot;Large PHP Error Log&quot; &quot;Domain: ${domain}\nPHP error log size: $(numfmt --to=iec-i --suffix=B ${log_size})&quot; &quot;high&quot;
                log_event &quot;large_php_log&quot; &quot;Large PHP error log for ${domain}&quot; &quot;high&quot;
            fi
            
            # Check for recent fatal errors
            local fatal_errors=$(tail -n 1000 &quot;$php_error_log&quot; | grep -i &quot;fatal error&quot; | tail -n 5)
            if [ -n &quot;$fatal_errors&quot; ]; then
                send_alert &quot;PHP Fatal Errors Detected&quot; &quot;Domain: ${domain}\n\nRecent fatal errors:\n${fatal_errors}&quot; &quot;high&quot;
                log_event &quot;php_fatal_errors&quot; &quot;PHP fatal errors detected on ${domain}&quot; &quot;high&quot;
            fi
        fi
        
        # Check varnish cache if enabled
        if [ -d &quot;${SITES_ROOT}/${user}/.varnish-cache&quot; ]; then
            local varnish_log=&quot;${SITES_ROOT}/${user}/logs/varnish-cache/purge.log&quot;
            if [ -f &quot;$varnish_log&quot; ]; then
                local purge_count=$(tail -n 1000 &quot;$varnish_log&quot; | wc -l)
                if [ &quot;${purge_count:-0}&quot; -gt 1000 ]; then
                    send_alert &quot;High Varnish Purge Rate&quot; &quot;Domain: ${domain}\nHigh number of cache purges: ${purge_count} in recent log&quot; &quot;normal&quot;
                    log_event &quot;high_purge_rate&quot; &quot;High varnish purge rate on ${domain}&quot; &quot;normal&quot;
                fi
            fi
        fi
        
        # Check application-specific settings
        local app_type=$(sqlite3 &quot;$CP_DB&quot; &quot;SELECT application FROM site WHERE id = $site_id;&quot;)
        case &quot;$app_type&quot; in
            &quot;wordpress&quot;)
                local wp_config=&quot;${SITES_ROOT}/${user}/htdocs/${domain}/wp-config.php&quot;
                if [ -f &quot;$wp_config&quot; ]; then
                    if grep -q &quot;WP_DEBUG.*true&quot; &quot;$wp_config&quot;; then
                        send_alert &quot;WordPress Debug Enabled&quot; &quot;Domain: ${domain}\nWP_DEBUG is enabled in production&quot; &quot;normal&quot;
                        log_event &quot;wp_debug_enabled&quot; &quot;WordPress debug mode enabled on ${domain}&quot; &quot;normal&quot;
                    fi
                fi
                ;;
        esac
    done
}

check_security() {
    log &quot;Checking security...&quot; &quot;${BLUE}&quot;
    
    # Check failed SSH attempts
    local failed_ssh=$(grep &quot;Failed password&quot; /var/log/auth.log 2&amp;gt;/dev/null | awk &apos;{print $11}&apos; | sort | uniq -c | sort -nr | head -n 5)
    if [ -n &quot;$failed_ssh&quot; ]; then
        send_alert &quot;Security Alert - Failed SSH Attempts&quot; &quot;Recent failed SSH attempts:\n${failed_ssh}&quot; &quot;high&quot;
        log_event &quot;failed_ssh_attempts&quot; &quot;Multiple failed SSH attempts detected&quot; &quot;high&quot;
    fi
    
    # Check for modified system files
    local modified_files=$(find /etc /usr/bin /usr/sbin -mmin -60 -type f 2&amp;gt;/dev/null)
    if [ -n &quot;$modified_files&quot; ]; then
        send_alert &quot;Security Alert - Modified System Files&quot; &quot;Recently modified system files:\n${modified_files}&quot; &quot;high&quot;
        log_event &quot;modified_system_files&quot; &quot;System files modified in last hour&quot; &quot;high&quot;
    fi
    
    # Check CloudPanel specific security
    local blocked_ips=$(sqlite3 &quot;$CP_DB&quot; &quot;SELECT COUNT(*) FROM blocked_ip;&quot;)
    local blocked_bots=$(sqlite3 &quot;$CP_DB&quot; &quot;SELECT COUNT(*) FROM blocked_bot;&quot;)
    
    if [ &quot;${blocked_ips:-0}&quot; -gt 0 ] || [ &quot;${blocked_bots:-0}&quot; -gt 0 ]; then
        send_alert &quot;Security Info - Blocked Entities&quot; &quot;Current blocks:\nIPs: ${blocked_ips}\nBots: ${blocked_bots}&quot; &quot;normal&quot;
    fi
    
    # Check for expired SSL certificates
    local near_expiry=$(sqlite3 &quot;$CP_DB&quot; &quot;
        SELECT s.domain_name, c.expires_at 
        FROM certificate c 
        JOIN site s ON c.site_id = s.id 
        WHERE c.expires_at &amp;lt;= datetime(&apos;now&apos;, &apos;+30 days&apos;) 
        AND c.expires_at &amp;gt; datetime(&apos;now&apos;);&quot;
    )
    
    if [ -n &quot;$near_expiry&quot; ]; then
        send_alert &quot;SSL Certificates Near Expiry&quot; &quot;Certificates expiring soon:\n${near_expiry}&quot; &quot;normal&quot;
        log_event &quot;ssl_near_expiry&quot; &quot;SSL certificates approaching expiration&quot; &quot;normal&quot;
    fi
}

check_scheduled_tasks() {
    log &quot;Checking scheduled tasks...&quot; &quot;${BLUE}&quot;
    
    # Check cron jobs from database
    local failed_crons=$(sqlite3 &quot;$CP_DB&quot; &quot;
        SELECT s.domain_name, cj.command 
        FROM cron_job cj 
        JOIN site s ON cj.site_id = s.id;&quot;
    )
    
    if [ -n &quot;$failed_crons&quot; ]; then
        while IFS=&apos;|&apos; read -r domain command; do
            # Basic validation of cron command existence
            local cmd_path=$(echo &quot;$command&quot; | awk &apos;{print $1}&apos;)
            if [ ! -f &quot;$cmd_path&quot; ] &amp;amp;&amp;amp; ! command -v &quot;$cmd_path&quot; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then
                send_alert &quot;Invalid Cron Job&quot; &quot;Domain: ${domain}\nInvalid command path: ${cmd_path}&quot; &quot;normal&quot;
                log_event &quot;invalid_cron&quot; &quot;Invalid cron command for ${domain}&quot; &quot;normal&quot;
            fi
        done &amp;lt;&amp;lt;&amp;lt; &quot;$failed_crons&quot;
    fi
}

main() {
    log &quot;Starting CloudPanel monitoring system...&quot; &quot;${GREEN}&quot;
    validate_config
    
    while true; do
        check_system_resources
        check_services
        check_website_resources
        check_security
        check_scheduled_tasks
        
        log &quot;Sleeping for ${CHECK_INTERVAL} seconds...&quot; &quot;${BLUE}&quot;
        sleep &quot;${CHECK_INTERVAL}&quot;
    done
}

main &quot;$@&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Uses CloudPanel&apos;s actual database schema for storing events and metrics&lt;/li&gt;
&lt;li&gt;Monitors all services configured in the database&lt;/li&gt;
&lt;li&gt;Records system metrics in CloudPanel&apos;s instance_* tables&lt;/li&gt;
&lt;li&gt;Monitors website resources based on CloudPanel&apos;s site structure&lt;/li&gt;
&lt;li&gt;Maintains proper logging in CloudPanel&apos;s event system&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To implement:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Make script executable
chmod +x /usr/local/bin/cloudpanel-service-monitor.sh

# Create systemd service
sudo nano /etc/systemd/system/cloudpanel-monitor.service
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=CloudPanel Service Monitor
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/cloudpanel-service-monitor.sh
Restart=always
User=root

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;# Enable and start the service
sudo systemctl enable cloudpanel-monitor
sudo systemctl start cloudpanel-monitor
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 3</title><link>https://hhf.technology/blog/cloudpanel-security-part3/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part3/</guid><description>Web Security and Application-Level Protection</description><pubDate>Fri, 15 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Part 3: Web Security and Application-Level Protection&lt;/h1&gt;
&lt;p&gt;I&apos;ll explain how to implement comprehensive web security measures specifically tailored for CloudPanel. Let&apos;s break this down into manageable components that work together to create a robust security layer.&lt;/p&gt;
&lt;h3&gt;1. Enhanced Nginx Security Configuration&lt;/h3&gt;
&lt;p&gt;First, let&apos;s create a security-focused Nginx configuration that aligns with CloudPanel. CloudPanel uses a dual Nginx configuration approach, with core settings in &lt;code&gt;/home/clp/services/nginx/&lt;/code&gt; and site-specific configurations in &lt;code&gt;/etc/nginx/&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create a security-focused Nginx configuration
sudo nano /etc/nginx/conf.d/security-headers.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s implement strong security headers while maintaining CloudPanel&apos;s functionality:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Enhanced Security Headers Configuration
# These headers protect against common web vulnerabilities while ensuring CloudPanel operates correctly

# Basic security headers
add_header X-Content-Type-Options &quot;nosniff&quot; always;
add_header X-Frame-Options &quot;SAMEORIGIN&quot; always;
add_header X-XSS-Protection &quot;1; mode=block&quot; always;
add_header Referrer-Policy &quot;strict-origin-when-cross-origin&quot; always;

# Content Security Policy tailored for CloudPanel
add_header Content-Security-Policy &quot;
    default-src &apos;self&apos;;
    script-src &apos;self&apos; &apos;unsafe-inline&apos; &apos;unsafe-eval&apos;;
    style-src &apos;self&apos; &apos;unsafe-inline&apos;;
    img-src &apos;self&apos; data: https:;
    font-src &apos;self&apos; data:;
    frame-ancestors &apos;self&apos;;
    form-action &apos;self&apos;;
&quot; always;

# HSTS configuration - Enable only after ensuring SSL is properly configured
# add_header Strict-Transport-Security &quot;max-age=31536000; includeSubDomains; preload&quot; always;

# Protection against various attacks
client_body_buffer_size 10K;
client_max_body_size 10M;
client_body_timeout 12;
client_header_timeout 12;

# Rate limiting configuration
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. PHP Security Hardening&lt;/h3&gt;
&lt;p&gt;CloudPanel manages multiple PHP versions, so we need to secure each version while maintaining compatibility. Let&apos;s create a comprehensive PHP security configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create a function to apply security settings to all PHP versions
sudo nano /usr/local/bin/cloudpanel-php-secure.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&apos;s a script that automatically secures all PHP versions used by CloudPanel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# CloudPanel Security Manager
# This script implements security measures for CloudPanel installations
# focusing on PHP hardening and firewall configurations.

set -euo pipefail
IFS=$&apos;\n\t&apos;

# Configuration variables
readonly CP_HOME=&quot;/home/clp&quot;
readonly SITES_ROOT=&quot;/home&quot;
readonly DB_PATH=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
readonly LOG_DIR=&quot;/var/log/cloudpanel_monitoring&quot;
readonly LOG_FILE=&quot;${LOG_DIR}/security_manager.log&quot;
readonly ALERT_LOG=&quot;${LOG_DIR}/alerts.log&quot;
readonly BACKUP_DIR=&quot;${LOG_DIR}/backups&quot;

# Color definitions
readonly RED=&apos;\033[0;31m&apos;
readonly GREEN=&apos;\033[0;32m&apos;
readonly YELLOW=&apos;\033[1;33m&apos;
readonly BLUE=&apos;\033[0;34m&apos;
readonly NC=&apos;\033[0m&apos;

# Security settings
readonly DEFAULT_MEMORY_LIMIT=&quot;256M&quot;
readonly DEFAULT_UPLOAD_SIZE=&quot;10M&quot;

# Initialize logging
setup_logging() {
    mkdir -p &quot;${LOG_DIR}&quot; &quot;${BACKUP_DIR}&quot;
    
    if [[ ! -f &quot;${LOG_FILE}&quot; ]]; then
        echo &quot;=== CloudPanel Security Manager Log Started $(date &apos;+%Y-%m-%d %H:%M:%S&apos;) ===&quot; &amp;gt; &quot;${LOG_FILE}&quot;
    fi
    
    if [[ ! -f &quot;${ALERT_LOG}&quot; ]]; then
        echo &quot;=== CloudPanel Security Alerts Started $(date &apos;+%Y-%m-%d %H:%M:%S&apos;) ===&quot; &amp;gt; &quot;${ALERT_LOG}&quot;
    fi
    
    # Set up log rotation
    cat &amp;gt; &quot;/etc/logrotate.d/cloudpanel-security&quot; &amp;lt;&amp;lt; &apos;LOGROTATE&apos;
/var/log/cloudpanel_monitoring/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root root
}
LOGROTATE

    log &quot;INFO&quot; &quot;System&quot; &quot;Logging initialized&quot;
}

# Log function with component tracking
log() {
    local level=$1
    local component=$2
    shift 2
    local message=&quot;$*&quot;
    local timestamp=$(date &apos;+%Y-%m-%d %H:%M:%S&apos;)
    
    # Select color based on level
    local color=&quot;&quot;
    case &quot;${level}&quot; in
        &quot;ERROR&quot;) color=&quot;${RED}&quot; ;;
        &quot;WARN&quot;)  color=&quot;${YELLOW}&quot; ;;
        &quot;INFO&quot;)  color=&quot;${GREEN}&quot; ;;
        &quot;DEBUG&quot;) color=&quot;${BLUE}&quot; ;;
    esac
    
    # Log to file
    echo &quot;${timestamp} | ${level} | ${component} | ${message}&quot; &amp;gt;&amp;gt; &quot;${LOG_FILE}&quot;
    
    # Console output
    echo -e &quot;${color}[${timestamp}] [${level}] ${component}: ${message}${NC}&quot;
    
    # Log alerts
    if [[ &quot;${level}&quot; == &quot;ERROR&quot; || &quot;${level}&quot; == &quot;WARN&quot; ]]; then
        echo &quot;${timestamp} | ${level} | ${component} | ${message}&quot; &amp;gt;&amp;gt; &quot;${ALERT_LOG}&quot;
    fi
}

# Backup function
backup_file() {
    local file=$1
    local backup=&quot;${BACKUP_DIR}/$(basename &quot;${file}&quot;).$(date +%Y%m%d_%H%M%S)&quot;
    
    if [[ -f &quot;${file}&quot; ]]; then
        cp &quot;${file}&quot; &quot;${backup}&quot;
        log &quot;INFO&quot; &quot;Backup&quot; &quot;Created backup: ${backup}&quot;
    else
        log &quot;WARN&quot; &quot;Backup&quot; &quot;File not found: ${file}&quot;
        return 1
    fi
}

# Configure firewall
configure_firewall() {
    log &quot;INFO&quot; &quot;Firewall&quot; &quot;Configuring firewall rules&quot;
    
    sqlite3 &quot;${DB_PATH}&quot; &amp;lt;&amp;lt; &apos;FWEND&apos;
BEGIN TRANSACTION;
DELETE FROM firewall_rule;
INSERT INTO firewall_rule (created_at, updated_at, port_range, source, description)
VALUES 
    (datetime(&apos;now&apos;), datetime(&apos;now&apos;), &apos;80,443&apos;, &apos;0.0.0.0/0&apos;, &apos;Web Traffic&apos;),
    (datetime(&apos;now&apos;), datetime(&apos;now&apos;), &apos;22&apos;, &apos;0.0.0.0/0&apos;, &apos;SSH Access&apos;),
    (datetime(&apos;now&apos;), datetime(&apos;now&apos;), &apos;8443&apos;, &apos;127.0.0.1,::1&apos;, &apos;CloudPanel Local Access&apos;);
COMMIT;
FWEND
    
    log &quot;INFO&quot; &quot;Firewall&quot; &quot;Rules updated successfully&quot;
}

# Configure PHP security
configure_php_security() {
    local site_id=$1
    local domain=$2
    
    log &quot;INFO&quot; &quot;PHP&quot; &quot;Configuring security for ${domain}&quot;
    
    sqlite3 &quot;${DB_PATH}&quot; &amp;lt;&amp;lt; PHPEND
UPDATE php_settings SET
    memory_limit = &apos;${DEFAULT_MEMORY_LIMIT}&apos;,
    max_execution_time = 30,
    max_input_time = 60,
    max_input_vars = 1000,
    post_max_size = &apos;${DEFAULT_UPLOAD_SIZE}&apos;,
    upload_max_file_size = &apos;${DEFAULT_UPLOAD_SIZE}&apos;,
    additional_configuration = &apos;
expose_php = Off
allow_url_fopen = Off
allow_url_include = Off
session.cookie_httponly = 1
session.cookie_secure = 1
session.cookie_samesite = &quot;Strict&quot;
session.use_strict_mode = 1
display_errors = Off
log_errors = On
error_reporting = E_ALL &amp;amp; ~E_DEPRECATED &amp;amp; ~E_STRICT
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
max_execution_time = 30
memory_limit = ${DEFAULT_MEMORY_LIMIT}&apos;
WHERE site_id = ${site_id};
PHPEND

    log &quot;INFO&quot; &quot;PHP&quot; &quot;Settings updated for ${domain}&quot;
}

# Process site
process_site() {
    local site_id=$1
    local domain=$2
    
    log &quot;INFO&quot; &quot;Site&quot; &quot;Processing ${domain}&quot;
    configure_php_security &quot;${site_id}&quot; &quot;${domain}&quot;
}

# Main function
main() {
    local start_time=$(date +%s)
    
    setup_logging
    log &quot;INFO&quot; &quot;System&quot; &quot;Starting security configuration&quot;
    
    backup_file &quot;${DB_PATH}&quot;
    configure_firewall
    
    while IFS=&apos;|&apos; read -r site_id domain; do
        process_site &quot;${site_id}&quot; &quot;${domain}&quot;
    done &amp;lt; &amp;lt;(sqlite3 &quot;${DB_PATH}&quot; &quot;SELECT id, domain_name FROM site;&quot;)
    
    log &quot;INFO&quot; &quot;System&quot; &quot;Restarting PHP-FPM&quot;
    systemctl restart &quot;php*-fpm&quot;
    
    local end_time=$(date +%s)
    log &quot;INFO&quot; &quot;System&quot; &quot;Completed in $((end_time - start_time)) seconds&quot;
}

# Run main with error handling
if [[ &quot;${BASH_SOURCE[0]}&quot; == &quot;${0}&quot; ]]; then
    trap &apos;log &quot;ERROR&quot; &quot;System&quot; &quot;Failed on line $LINENO&quot;&apos; ERR
    main &quot;$@&quot;
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Web Application Firewall Integration&lt;/h3&gt;
&lt;p&gt;Let&apos;s implement a WAF configuration that works with CloudPanel&apos;s structure:&lt;/p&gt;
&lt;h1&gt;&lt;a href=&quot;https://hhf.technology/blog/cloudpanel-waf-nasxi&quot;&gt;Install Naxsi WAF for Nginx&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Here&apos;s a CloudPanel-specific Naxsi WAF configuration:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hhf.technology/blog/cloudpanel-waf-nasxi-senerios&quot;&gt;Examples for CloudPanel&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Include in the server block of your WordPress site
server {
    # Standard CloudPanel configuration remains unchanged
    listen 80;
    listen [::]:80;
    server_name example.com;

    # Enable Naxsi base rules
    include /etc/nginx/naxsi/naxsi-base.conf;

    # WordPress-specific whitelist rules
    include /etc/nginx/naxsi/wordpress.rules;

    location / {
        # Standard WordPress handling
        try_files $uri $uri/ /index.php?$args;

        # WordPress-specific Naxsi configurations
        BasicRule wl:1315,1101 &quot;mz:$BODY_VAR:post_title&quot;;
        BasicRule wl:1315,1101 &quot;mz:$BODY_VAR:content&quot;;
        BasicRule wl:1315 &quot;mz:$BODY_VAR:excerpt&quot;;
        BasicRule wl:1101 &quot;mz:$BODY_VAR:cat&quot;;

        # Allow WordPress admin actions
        BasicRule wl:1000,1015 &quot;mz:$URL:/wp-admin/|$BODY_VAR:action&quot;;
    }

    # Special handling for wp-admin
    location /wp-admin {
        # Allow file uploads in wp-admin
        BasicRule wl:1500 &quot;mz:$URL:/wp-admin/|$BODY_VAR:attachment&quot;;
        BasicRule wl:1310,1311 &quot;mz:$URL:/wp-admin/|BODY&quot;;

        # Standard CloudPanel proxy configuration
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 4 and 5</title><link>https://hhf.technology/blog/cloudpanel-security-part5/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part5/</guid><description>Advanced Security Controls and PHP Configuration Management</description><pubDate>Sat, 16 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Part 4 &amp;amp; 5: Advanced Security Controls and PHP Configuration Management&lt;/h1&gt;
&lt;p&gt;Let&apos;s create a security system that integrates traffic analysis and PHP configuration management based on CloudPanel.&lt;/p&gt;
&lt;p&gt;First, let&apos;s create our main security management script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create the security management script
sudo nano /usr/local/bin/cloudpanel-php-security-manager.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# CloudPanel PHP Security Manager
# Manages PHP-FPM configurations and security settings across different PHP versions

set -euo pipefail

# Core paths based on CloudPanel structure
CP_HOME=&quot;/home/clp&quot;
DB_PATH=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
SITES_ROOT=&quot;/home&quot;
LOG_DIR=&quot;${CP_HOME}/logs/php&quot;

mkdir -p &quot;$LOG_DIR&quot;

# Function to handle logging with timestamps and levels
log() {
    local level=&quot;$1&quot;
    local message=&quot;$2&quot;
    echo &quot;[$(date &apos;+%Y-%m-%d %H:%M:%S&apos;)] [$level] $message&quot; | tee -a &quot;${LOG_DIR}/security.log&quot;
}

# Validate database existence
validate_db() {
    if [ ! -f &quot;$DB_PATH&quot; ]; then
        log &quot;ERROR&quot; &quot;CloudPanel database not found at $DB_PATH&quot;
        exit 1
    fi
}

# Retrieve sites with their PHP settings from database
# This function joins site and php_settings tables to get complete configuration
get_sites_with_php() {
    sqlite3 &quot;$DB_PATH&quot; &quot;
SELECT 
    s.id, 
    s.domain_name, 
    s.user, 
    s.root_directory, 
    p.php_version, 
    p.id as php_settings_id, 
    p.memory_limit, 
    p.max_execution_time, 
    p.additional_configuration, 
    p.pool_port
FROM site s
INNER JOIN php_settings p ON s.php_settings_id = p.id
WHERE s.type = &apos;vhost&apos;;&quot;
}

# Configure PHP version specific settings
configure_php_version() {
    local php_version=&quot;$1&quot;
    local version_number=&quot;${php_version/./}&quot;  # Convert 7.4 to 74
    
    # Verify PHP version installation
    if [ ! -d &quot;/etc/php/${php_version}&quot; ]; then
        log &quot;ERROR&quot; &quot;PHP version ${php_version} not installed&quot;
        return 1
    fi
    
    # Setup PHP-FPM pool directory
    local fpm_pool_dir=&quot;/etc/php/${php_version}/fpm/pool.d&quot;
    mkdir -p &quot;$fpm_pool_dir&quot;
    
    # Create base PHP-FPM configuration if missing
    local fpm_conf=&quot;/etc/php/${php_version}/fpm/php-fpm.conf&quot;
    if [ ! -f &quot;$fpm_conf&quot; ]; then
        cat &amp;gt; &quot;$fpm_conf&quot; &amp;lt;&amp;lt; EOF
[global]
pid = /run/php/php${php_version}-fpm.pid
error_log = /var/log/php${version_number}-fpm.log
log_level = notice
emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s
daemonize = yes
include=/etc/php/${php_version}/fpm/pool.d/*.conf
EOF
    fi
    
    # Enable PHP-FPM service
    systemctl enable &quot;php${version_number}-fpm&quot; 2&amp;gt;/dev/null || true
}

# Configure PHP settings for a specific site
configure_site_php() {
    local domain=&quot;$1&quot;
    local user=&quot;$2&quot;
    local php_version=&quot;$3&quot;
    local root_dir=&quot;$4&quot;
    local memory_limit=&quot;$5&quot;
    local max_exec=&quot;$6&quot;
    local additional_config=&quot;$7&quot;
    local pool_port=&quot;$8&quot;
    
    local version_number=&quot;${php_version/./}&quot;
    local pool_config=&quot;/etc/php/${php_version}/fpm/pool.d/${domain}.conf&quot;
    local user_php_log_dir=&quot;${SITES_ROOT}/${user}/logs/php&quot;
    
    # Create and set permissions for log directory
    mkdir -p &quot;$user_php_log_dir&quot;
    chown &quot;${user}:${user}&quot; &quot;$user_php_log_dir&quot;
    
    # Create PHP-FPM pool configuration
    cat &amp;gt; &quot;$pool_config&quot; &amp;lt;&amp;lt; EOF
[${domain}]
user = ${user}
group = ${user}
listen = 127.0.0.1:${pool_port}

; Process Management
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 10

; Path Settings
chdir = ${root_dir}

; PHP Settings
php_admin_flag[log_errors] = on
php_admin_value[error_log] = ${user_php_log_dir}/php-${domain}-error.log
php_admin_value[memory_limit] = ${memory_limit}
php_admin_value[max_execution_time] = ${max_exec}
php_admin_value[session.save_handler] = files
php_admin_value[session.save_path] = ${SITES_ROOT}/${user}/tmp/sessions
php_admin_value[upload_tmp_dir] = ${SITES_ROOT}/${user}/tmp/upload

; Security Settings
php_admin_flag[allow_url_fopen] = off
php_admin_flag[allow_url_include] = off
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen
php_admin_value[open_basedir] = ${root_dir}:/tmp:${SITES_ROOT}/${user}/tmp

; Custom Configuration
${additional_config}
EOF

    # Setup temporary directories with proper permissions
    mkdir -p &quot;${SITES_ROOT}/${user}/tmp/&quot;{sessions,upload}
    chown -R &quot;${user}:${user}&quot; &quot;${SITES_ROOT}/${user}/tmp&quot;
    chmod -R 750 &quot;${SITES_ROOT}/${user}/tmp&quot;

    log &quot;INFO&quot; &quot;Configured PHP-FPM pool for ${domain} (PHP ${php_version})&quot;
}

# Setup log rotation for PHP logs
setup_log_rotation() {
    local user=&quot;$1&quot;
    local domain=&quot;$2&quot;
    
    cat &amp;gt; &quot;/etc/logrotate.d/php-${domain}&quot; &amp;lt;&amp;lt; EOF
${SITES_ROOT}/${user}/logs/php/php-${domain}-error.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    create 0640 ${user} ${user}
}
EOF
}

# Main execution function
main() {
    log &quot;INFO&quot; &quot;Starting CloudPanel PHP security configuration&quot;
    validate_db
    
    # Create backup directory
    local backup_date=$(date +%Y%m%d_%H%M%S)
    local backup_dir=&quot;${CP_HOME}/backups/php_security_${backup_date}&quot;
    mkdir -p &quot;$backup_dir&quot;
    
    # Track configured PHP versions
    declare -A configured_versions
    
    # Process each site
    while IFS=&apos;|&apos; read -r site_id domain user root_dir php_version settings_id mem_limit max_exec additional port; do
        if [ -z &quot;${configured_versions[$php_version]:-}&quot; ]; then
            configure_php_version &quot;$php_version&quot;
            configured_versions[$php_version]=1
            
            # Backup existing configuration
            if [ -d &quot;/etc/php/${php_version}&quot; ]; then
                cp -r &quot;/etc/php/${php_version}&quot; &quot;${backup_dir}/php${php_version}&quot;
            fi
        fi
        
        configure_site_php &quot;$domain&quot; &quot;$user&quot; &quot;$php_version&quot; &quot;$root_dir&quot; &quot;$mem_limit&quot; &quot;$max_exec&quot; &quot;$additional&quot; &quot;$port&quot;
        setup_log_rotation &quot;$user&quot; &quot;$domain&quot;
    done &amp;lt; &amp;lt;(get_sites_with_php)
    
    log &quot;INFO&quot; &quot;PHP security configuration completed&quot;
    log &quot;INFO&quot; &quot;Backup stored in: $backup_dir&quot;
    
    # Reload PHP-FPM for each configured version
    for version in &quot;${!configured_versions[@]}&quot;; do
        version_num=&quot;${version/./}&quot;
        systemctl reload &quot;php${version_num}-fpm&quot; || log &quot;ERROR&quot; &quot;Failed to reload PHP-FPM for version ${version}&quot;
    done
}

main &quot;$@&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This unified script:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reads site configurations directly from CloudPanel&lt;/li&gt;
&lt;li&gt;Configures PHP-FPM pools with settings from the database&lt;/li&gt;
&lt;li&gt;Implements security measures for both PHP&lt;/li&gt;
&lt;li&gt;Analyzes traffic patterns for suspicious activity&lt;/li&gt;
&lt;li&gt;Creates proper backups before making changes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To use this script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Make the script executable
chmod +x /usr/local/bin/cloudpanel-php-security-manager.sh

# Run the script
/usr/local/bin/cloudpanel-php-security-manager.sh
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 6</title><link>https://hhf.technology/blog/cloudpanel-security-part6/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part6/</guid><description>Database Security and Backup Management</description><pubDate>Sun, 17 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Part 6: Database Security and Backup Management&lt;/h1&gt;
&lt;h3&gt;Let&apos;s create a database security management system:&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Create database security management script
sudo nano /usr/local/bin/cloudpanel-db-security.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Initialize paths and configuration
CP_HOME=&quot;/home/clp&quot;
DB_PATH=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
BACKUP_DIR=&quot;${CP_HOME}/backups/databases&quot;
LOG_DIR=&quot;${CP_HOME}/logs/database&quot;

# Ensure our directories exist
mkdir -p &quot;$BACKUP_DIR&quot; &quot;$LOG_DIR&quot;

# Function to read database configurations from CloudPanel
get_database_config() {
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            d.id,
            d.name as db_name,
            d.site_id,
            s.domain_name,
            ds.engine,
            ds.host,
            ds.port,
            du.user_name,
            du.permissions
        FROM database d
        JOIN database_server ds ON d.database_server_id = ds.id
        JOIN site s ON d.site_id = s.id
        JOIN database_user du ON d.id = du.database_id
        WHERE ds.is_active = 1;&quot;
}

# Function to implement database security measures
secure_databases() {
    echo &quot;Implementing database security measures...&quot;
    
    while IFS=&apos;|&apos; read -r db_id db_name site_id domain engine host port user perms; do
        echo &quot;Securing database: $db_name for $domain&quot;
        
        # Create secure configuration for each database
        case &quot;$engine&quot; in
            &quot;mysql&quot;)
                secure_mysql_database &quot;$db_name&quot; &quot;$user&quot; &quot;$perms&quot;
                ;;
            &quot;postgresql&quot;)
                secure_postgresql_database &quot;$db_name&quot; &quot;$user&quot; &quot;$perms&quot;
                ;;
            *)
                echo &quot;Unsupported database engine: $engine&quot;
                continue
                ;;
        esac
        
        # Setup automated backups for this database
        setup_database_backup &quot;$db_name&quot; &quot;$domain&quot; &quot;$engine&quot;
    done &amp;lt; &amp;lt;(get_database_config)
}

# Function to secure MySQL databases
secure_mysql_database() {
    local db_name=&quot;$1&quot;
    local user=&quot;$2&quot;
    local perms=&quot;$3&quot;
    
    mysql -e &quot;
        -- Remove any excessive privileges
        REVOKE ALL PRIVILEGES ON *.* FROM &apos;$user&apos;@&apos;localhost&apos;;
        
        -- Grant only necessary permissions based on CloudPanel settings
        GRANT $perms ON $db_name.* TO &apos;$user&apos;@&apos;localhost&apos;;
        
        -- Ensure proper security settings
        ALTER USER &apos;$user&apos;@&apos;localhost&apos; 
            REQUIRE SSL 
            PASSWORD EXPIRE INTERVAL 90 DAY 
            FAILED_LOGIN_ATTEMPTS 3 
            PASSWORD_LOCK_TIME 2;
        
        -- Enable binary logging for this database
        SET GLOBAL binlog_do_db = CONCAT(@@binlog_do_db, &apos;,$db_name&apos;);
        
        FLUSH PRIVILEGES;&quot;
}

# Function to setup database backups
setup_database_backup() {
    local db_name=&quot;$1&quot;
    local domain=&quot;$2&quot;
    local engine=&quot;$3&quot;
    
    # Create backup script for this database
    local backup_script=&quot;${BACKUP_DIR}/${domain}-backup.sh&quot;
    
    cat &amp;gt; &quot;$backup_script&quot; &amp;lt;&amp;lt;EOF
#!/bin/bash

# Backup script for $domain database ($db_name)
TIMESTAMP=\$(date +%Y%m%d_%H%M%S)
BACKUP_PATH=&quot;${BACKUP_DIR}/${domain}/\${TIMESTAMP}&quot;
mkdir -p &quot;\$BACKUP_PATH&quot;

# Perform backup based on engine type
case &quot;$engine&quot; in
    &quot;mysql&quot;)
        mysqldump --single-transaction \\
                 --quick \\
                 --lock-tables=false \\
                 --routines \\
                 --triggers \\
                 --events \\
                 &quot;$db_name&quot; | gzip &amp;gt; &quot;\$BACKUP_PATH/${db_name}.sql.gz&quot;
        ;;
    &quot;postgresql&quot;)
        PGPASSWORD=&quot;\$PGPASSWORD&quot; pg_dump \\
            -h localhost \\
            -U &quot;$user&quot; \\
            --clean \\
            --if-exists \\
            &quot;$db_name&quot; | gzip &amp;gt; &quot;\$BACKUP_PATH/${db_name}.sql.gz&quot;
        ;;
esac

# Verify backup integrity
if gunzip -t &quot;\$BACKUP_PATH/${db_name}.sql.gz&quot;; then
    echo &quot;Backup completed successfully for $db_name&quot;
else
    echo &quot;Backup verification failed for $db_name&quot;
    exit 1
fi

# Implement backup rotation (keep last 7 days)
find &quot;${BACKUP_DIR}/${domain}&quot; -type f -mtime +7 -delete
EOF

    # Make backup script executable
    chmod +x &quot;$backup_script&quot;
    
    # Add to crontab if not already present
    if ! crontab -l | grep -q &quot;$backup_script&quot;; then
        (crontab -l 2&amp;gt;/dev/null; echo &quot;0 2 * * * $backup_script&quot;) | crontab -
    fi
}

# Function to monitor database security
monitor_database_security() {
    echo &quot;Setting up database security monitoring...&quot;
    
    # Create monitoring queries based on engine type
    cat &amp;gt; &quot;${LOG_DIR}/monitor-queries.sql&quot; &amp;lt;&amp;lt;EOF
-- Check for users with excessive privileges
SELECT user, host, privilege_type 
FROM information_schema.user_privileges 
WHERE privilege_type IN (&apos;SUPER&apos;, &apos;FILE&apos;, &apos;PROCESS&apos;);

-- Check for non-local connections
SELECT user, host, db, command, time 
FROM information_schema.processlist 
WHERE host NOT LIKE &apos;localhost%&apos;;

-- Check for failed login attempts
SELECT * FROM mysql.general_log 
WHERE argument LIKE &apos;%Access denied%&apos; 
AND event_time &amp;gt; NOW() - INTERVAL 1 HOUR;
EOF

    # Setup periodic monitoring
    cat &amp;gt; &quot;/etc/cron.hourly/db-security-monitor&quot; &amp;lt;&amp;lt;EOF
#!/bin/bash
mysql -N &amp;lt; &quot;${LOG_DIR}/monitor-queries.sql&quot; &amp;gt; &quot;${LOG_DIR}/security-audit-\$(date +%Y%m%d_%H).log&quot;
EOF

    chmod +x &quot;/etc/cron.hourly/db-security-monitor&quot;
}

# Main execution
main() {
    echo &quot;Starting database security configuration...&quot;
    
    # Create backup of current configurations
    backup_date=$(date +%Y%m%d_%H%M%S)
    mkdir -p &quot;${CP_HOME}/backups/db_security_${backup_date}&quot;
    
    # Implement security measures
    secure_databases
    
    # Setup monitoring
    monitor_database_security
    
    echo &quot;Database security configuration completed successfully&quot;
}

main &quot;$@&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script provides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Database security based on CloudPanel&apos;s actual configuration&lt;/li&gt;
&lt;li&gt;Automatic backup management for each database&lt;/li&gt;
&lt;li&gt;Security monitoring and audit logging&lt;/li&gt;
&lt;li&gt;Privilege management based on CloudPanel&apos;s database_user settings&lt;/li&gt;
&lt;li&gt;Engine-specific security measures for MySQL/PostgreSQL&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To implement this security system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Make the script executable
chmod +x /usr/local/bin/cloudpanel-db-security.sh

# Run the script
/usr/local/bin/cloudpanel-db-security.sh
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 7</title><link>https://hhf.technology/blog/cloudpanel-security-part7/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part7/</guid><description>SSL Certificate Management and Security</description><pubDate>Mon, 18 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Part 7: SSL Certificate Management and Security&lt;/h1&gt;
&lt;p&gt;Let&apos;s create a comprehensive SSL certificate management system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create SSL certificate management script
sudo nano /usr/local/bin/cloudpanel-ssl-manager.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Initialize paths and configuration
CP_HOME=&quot;/home/clp&quot;
DB_PATH=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
SSL_DIR=&quot;${CP_HOME}/services/nginx/ssl-certificates&quot;
LOG_DIR=&quot;${CP_HOME}/logs/ssl&quot;

mkdir -p &quot;$SSL_DIR&quot; &quot;$LOG_DIR&quot;

# Function to get certificate information from CloudPanel database
get_certificate_info() {
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            c.id,
            c.site_id,
            c.uid,
            c.expires_at,
            c.type,
            s.domain_name,
            s.user
        FROM certificate c
        JOIN site s ON c.site_id = s.id
        WHERE c.default_certificate = 1;&quot;
}

# Function to monitor certificate expiration
monitor_certificates() {
    echo &quot;Monitoring SSL certificates...&quot;
    local current_time=$(date +%s)
    
    while IFS=&apos;|&apos; read -r cert_id site_id uid expires domain user; do
        # Convert expires_at to timestamp
        local expire_time=$(date -d &quot;$expires&quot; +%s)
        local days_remaining=$(( ($expire_time - $current_time) / 86400 ))
        
        echo &quot;Checking certificate for $domain (Expires in $days_remaining days)&quot;
        
        # Alert if certificate is expiring soon
        if [ $days_remaining -lt 30 ]; then
            handle_expiring_certificate &quot;$domain&quot; &quot;$days_remaining&quot; &quot;$cert_id&quot;
        fi
        
        # Verify certificate chain
        verify_certificate_chain &quot;$domain&quot; &quot;$cert_id&quot;
        
    done &amp;lt; &amp;lt;(get_certificate_info)
}

# Function to verify and secure certificates
verify_certificate_chain() {
    local domain=&quot;$1&quot;
    local cert_id=&quot;$2&quot;
    
    # Get certificate chain from database
    local cert_path=&quot;${SSL_DIR}/${domain}.crt&quot;
    local key_path=&quot;${SSL_DIR}/${domain}.key&quot;
    
    # Extract certificate data from database
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            certificate,
            private_key,
            certificate_chain
        FROM certificate 
        WHERE id = $cert_id;&quot; | while IFS=&apos;|&apos; read -r cert key chain; do
        
        # Save certificate files with proper permissions
        echo &quot;$cert&quot; &amp;gt; &quot;$cert_path&quot;
        echo &quot;$key&quot; &amp;gt; &quot;$key_path&quot;
        chmod 644 &quot;$cert_path&quot;
        chmod 600 &quot;$key_path&quot;
        
        # Verify certificate chain
        if ! openssl verify -CAfile &amp;lt;(echo &quot;$chain&quot;) &quot;$cert_path&quot; &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then
            log_ssl_error &quot;$domain&quot; &quot;Certificate chain verification failed&quot;
        fi
        
        # Verify certificate matches private key
        cert_modulus=$(openssl x509 -noout -modulus -in &quot;$cert_path&quot; | openssl md5)
        key_modulus=$(openssl rsa -noout -modulus -in &quot;$key_path&quot; | openssl md5)
        
        if [ &quot;$cert_modulus&quot; != &quot;$key_modulus&quot; ]; then
            log_ssl_error &quot;$domain&quot; &quot;Certificate and private key mismatch&quot;
        fi
    done
}

# Function to handle expiring certificates
handle_expiring_certificate() {
    local domain=&quot;$1&quot;
    local days=&quot;$2&quot;
    local cert_id=&quot;$3&quot;
    
    echo &quot;Certificate for $domain is expiring in $days days&quot;
    
    # Log the expiration warning
    local message=&quot;SSL Certificate Expiration Warning for $domain&quot;
    local details=&quot;Certificate will expire in $days days&quot;
    
    # Update CloudPanel notification system
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO notification (
            created_at, 
            updated_at, 
            severity, 
            subject, 
            message,
            is_read
        ) VALUES (
            datetime(&apos;now&apos;),
            datetime(&apos;now&apos;),
            &apos;warning&apos;,
            &apos;$message&apos;,
            &apos;$details&apos;,
            0
        );&quot;
}

# Function to update Nginx SSL configuration
update_nginx_ssl_config() {
    local domain=&quot;$1&quot;
    local cert_id=&quot;$2&quot;
    
    # Get site configuration path
    local nginx_conf=&quot;${CP_HOME}/services/nginx/sites-enabled/${domain}.conf&quot;
    
    # Update SSL configuration
    cat &amp;gt; &quot;$nginx_conf&quot; &amp;lt;&amp;lt;EOF
server {
    listen 443 ssl http2;
    server_name ${domain};
    
    # SSL Configuration
    ssl_certificate ${SSL_DIR}/${domain}.crt;
    ssl_certificate_key ${SSL_DIR}/${domain}.key;
    
    # Modern SSL Configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # Security Headers
    add_header Strict-Transport-Security &quot;max-age=63072000&quot; always;
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    
    # Additional security headers for SSL
    add_header Content-Security-Policy &quot;default-src &apos;self&apos; https: data: &apos;unsafe-inline&apos; &apos;unsafe-eval&apos;; frame-ancestors &apos;self&apos;&quot;;
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name ${domain};
    return 301 https://$server_name$request_uri;
}
EOF
}

# Function to log SSL-related events
log_ssl_event() {
    local domain=&quot;$1&quot;
    local message=&quot;$2&quot;
    local level=&quot;$3&quot;
    
    echo &quot;[$(date &apos;+%Y-%m-%d %H:%M:%S&apos;)] [$level] $domain: $message&quot; &amp;gt;&amp;gt; &quot;${LOG_DIR}/ssl-events.log&quot;
}

# Main execution
main() {
    echo &quot;Starting SSL certificate management...&quot;
    
    # Create backup of current SSL configurations
    backup_date=$(date +%Y%m%d_%H%M%S)
    backup_dir=&quot;${CP_HOME}/backups/ssl_${backup_date}&quot;
    mkdir -p &quot;$backup_dir&quot;
    cp -r &quot;$SSL_DIR&quot; &quot;$backup_dir/&quot;
    
    # Monitor and update certificates
    monitor_certificates
    
    # Set up daily certificate monitoring
    if ! crontab -l | grep -q &quot;cloudpanel-ssl-manager.sh&quot;; then
        (crontab -l 2&amp;gt;/dev/null; echo &quot;0 0 * * * /usr/local/bin/cloudpanel-ssl-manager.sh&quot;) | crontab -
    fi
    
    echo &quot;SSL certificate management completed successfully&quot;
}

main &quot;$@&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script provides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Comprehensive SSL certificate management based on CloudPanel&apos;s database structure&lt;/li&gt;
&lt;li&gt;Automatic monitoring of certificate expiration&lt;/li&gt;
&lt;li&gt;Certificate chain verification&lt;/li&gt;
&lt;li&gt;Private key security&lt;/li&gt;
&lt;li&gt;Nginx SSL configuration management&lt;/li&gt;
&lt;li&gt;Integration with CloudPanel&apos;s notification system&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To implement this SSL management system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Make the script executable
chmod +x /usr/local/bin/cloudpanel-ssl-manager.sh

# Run the script
/usr/local/bin/cloudpanel-ssl-manager.sh
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 8</title><link>https://hhf.technology/blog/cloudpanel-security-part8/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part8/</guid><description>User Access Management and Security Hardening</description><pubDate>Tue, 19 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Part 8: User Access Management and Security Hardening&lt;/h1&gt;
&lt;p&gt;Let&apos;s create a comprehensive user security management system that integrates with CloudPanel.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create user security management script
sudo nano /usr/local/bin/cloudpanel-user-security.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Initialize paths and configuration
CP_HOME=&quot;/home/clp&quot;
DB_PATH=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
LOG_DIR=&quot;${CP_HOME}/logs/security&quot;

mkdir -p &quot;$LOG_DIR&quot;

# Function to get user information from CloudPanel database
get_user_info() {
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            u.id,
            u.user_name,
            u.role,
            u.email,
            u.mfa,
            u.status,
            GROUP_CONCAT(s.domain_name) as sites
        FROM user u
        LEFT JOIN user_sites us ON u.id = us.user_id
        LEFT JOIN site s ON us.site_id = s.id
        GROUP BY u.id;&quot;
}

# Function to get SSH user configurations
get_ssh_users() {
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            ss.user_name,
            ss.ssh_keys,
            s.domain_name,
            s.user
        FROM ssh_user ss
        JOIN site s ON ss.site_id = s.id;&quot;
}

# Function to enforce user security policies
enforce_user_security() {
    echo &quot;Enforcing user security policies...&quot;
    
    while IFS=&apos;|&apos; read -r user_id username role email mfa status sites; do
        echo &quot;Processing security for user: $username&quot;
        
        # Check and enforce MFA status
        if [ &quot;$mfa&quot; -eq 0 ]; then
            log_security_warning &quot;$username&quot; &quot;MFA not enabled&quot;
            enforce_mfa_requirement &quot;$user_id&quot; &quot;$username&quot;
        fi
        
        # Configure user access restrictions
        configure_user_access &quot;$username&quot; &quot;$role&quot; &quot;$sites&quot;
        
        # Set up user activity monitoring
        setup_user_monitoring &quot;$username&quot; &quot;$role&quot;
    done &amp;lt; &amp;lt;(get_user_info)
}

# Function to enforce MFA requirement
enforce_mfa_requirement() {
    local user_id=&quot;$1&quot;
    local username=&quot;$2&quot;
    
    echo &quot;Enforcing MFA for user: $username&quot;
    
    # Log MFA requirement
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO notification (
            created_at,
            updated_at,
            severity,
            subject,
            message,
            is_read
        ) VALUES (
            datetime(&apos;now&apos;),
            datetime(&apos;now&apos;),
            &apos;warning&apos;,
            &apos;MFA Required&apos;,
            &apos;MFA enablement required for user: $username&apos;,
            0
        );&quot;
}

# Function to configure SSH access
configure_ssh_access() {
    echo &quot;Configuring SSH access...&quot;
    
    while IFS=&apos;|&apos; read -r ssh_user ssh_keys domain site_user; do
        local user_home=&quot;/home/$site_user&quot;
        local ssh_dir=&quot;$user_home/.ssh&quot;
        
        echo &quot;Setting up SSH access for $ssh_user on $domain&quot;
        
        # Create SSH directory with proper permissions
        mkdir -p &quot;$ssh_dir&quot;
        chmod 700 &quot;$ssh_dir&quot;
        
        # Configure authorized keys
        echo &quot;$ssh_keys&quot; &amp;gt; &quot;$ssh_dir/authorized_keys&quot;
        chmod 600 &quot;$ssh_dir/authorized_keys&quot;
        chown -R &quot;$site_user:$site_user&quot; &quot;$ssh_dir&quot;
        
        # Configure SSH restrictions
        cat &amp;gt;&amp;gt; &quot;/etc/ssh/sshd_config.d/$ssh_user.conf&quot; &amp;lt;&amp;lt;EOF
Match User $ssh_user
    ChrootDirectory $user_home
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no
    PasswordAuthentication no
EOF
    done &amp;lt; &amp;lt;(get_ssh_users)
    
    # Restart SSH service
    systemctl restart sshd
}

# Function to configure user access controls
configure_user_access() {
    local username=&quot;$1&quot;
    local role=&quot;$2&quot;
    local sites=&quot;$3&quot;
    
    echo &quot;Configuring access controls for $username&quot;
    
    # Set up role-based access restrictions
    case &quot;$role&quot; in
        &quot;admin&quot;)
            setup_admin_access &quot;$username&quot;
            ;;
        &quot;user&quot;)
            setup_user_access &quot;$username&quot; &quot;$sites&quot;
            ;;
        *)
            echo &quot;Unknown role: $role&quot;
            return 1
            ;;
    esac
}

# Function to set up admin access
setup_admin_access() {
    local username=&quot;$1&quot;
    
    # Configure sudo access for admin users
    echo &quot;$username ALL=(ALL:ALL) NOPASSWD: /usr/local/bin/cloudpanel-*&quot; &amp;gt; &quot;/etc/sudoers.d/$username&quot;
    chmod 440 &quot;/etc/sudoers.d/$username&quot;
}

# Function to set up regular user access
setup_user_access() {
    local username=&quot;$1&quot;
    local sites=&quot;$2&quot;
    
    # Create restricted access configuration
    for site in ${sites//,/ }; do
        local site_path=&quot;/home/clp/htdocs/$site&quot;
        
        # Set up ACLs for site access
        setfacl -R -m &quot;u:$username:rx&quot; &quot;$site_path&quot;
        setfacl -R -m &quot;d:u:$username:rx&quot; &quot;$site_path&quot;
    done
}

# Function to setup user activity monitoring
setup_user_monitoring() {
    local username=&quot;$1&quot;
    local role=&quot;$2&quot;
    
    # Configure audit logging for user actions
    auditctl -w &quot;/home/$username&quot; -p warx -k user_files
    
    # Set up process monitoring
    cat &amp;gt; &quot;/etc/systemd/system/user-monitor-$username.service&quot; &amp;lt;&amp;lt;EOF
[Unit]
Description=User Activity Monitor for $username
After=network.target

[Service]
ExecStart=/usr/bin/auditd -f -n
StandardOutput=append:${LOG_DIR}/user-${username}.log
StandardError=append:${LOG_DIR}/user-${username}-error.log

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable &quot;user-monitor-$username&quot;
    systemctl start &quot;user-monitor-$username&quot;
}

# Function to log security events
log_security_event() {
    local username=&quot;$1&quot;
    local message=&quot;$2&quot;
    local level=&quot;$3&quot;
    
    echo &quot;[$(date &apos;+%Y-%m-%d %H:%M:%S&apos;)] [$level] $username: $message&quot; &amp;gt;&amp;gt; &quot;${LOG_DIR}/security-events.log&quot;
    
    # Add to CloudPanel event log
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO event (
            created_at,
            user_name,
            user_role,
            event_name,
            event_data
        ) VALUES (
            datetime(&apos;now&apos;),
            &apos;$username&apos;,
            &apos;$role&apos;,
            &apos;security_event&apos;,
            &apos;$message&apos;
        );&quot;
}

# Main execution
main() {
    echo &quot;Starting user security management...&quot;
    
    # Create backup of current configurations
    backup_date=$(date +%Y%m%d_%H%M%S)
    backup_dir=&quot;${CP_HOME}/backups/user_security_${backup_date}&quot;
    mkdir -p &quot;$backup_dir&quot;
    
    # Enforce security policies
    enforce_user_security
    
    # Configure SSH access
    configure_ssh_access
    
    echo &quot;User security management completed successfully&quot;
}

main &quot;$@&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script provides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Comprehensive user security management based on CloudPanel&apos;s database structure&lt;/li&gt;
&lt;li&gt;MFA enforcement and monitoring&lt;/li&gt;
&lt;li&gt;Role-based access control implementation&lt;/li&gt;
&lt;li&gt;SSH key management and restrictions&lt;/li&gt;
&lt;li&gt;User activity monitoring and logging&lt;/li&gt;
&lt;li&gt;Integration with CloudPanel&apos;s event and notification systems&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Securing CloudPanel on Ubuntu 24.04 Part 9</title><link>https://hhf.technology/blog/cloudpanel-security-part9/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-security-part9/</guid><description>Comprehensive Security Auditing and Performance Monitoring</description><pubDate>Wed, 20 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Part 9: Comprehensive Security Auditing and Performance Monitoring&lt;/h1&gt;
&lt;p&gt;Let&apos;s create an integrated monitoring and auditing system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create comprehensive monitoring script
sudo nano /usr/local/bin/cloudpanel-security-monitor.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Initialize paths and configuration
CP_HOME=&quot;/home/clp&quot;
DB_PATH=&quot;${CP_HOME}/htdocs/app/data/db.sq3&quot;
LOG_DIR=&quot;${CP_HOME}/logs/monitoring&quot;
AUDIT_DIR=&quot;${CP_HOME}/logs/audit&quot;

# Create necessary directories
mkdir -p &quot;$LOG_DIR&quot; &quot;$AUDIT_DIR&quot;

# Function to record system metrics in CloudPanel&apos;s database
record_system_metrics() {
    local timestamp=$(date &apos;+%Y-%m-%d %H:%M:%S&apos;)
    
    # Record CPU usage
    local cpu_usage=$(top -bn1 | grep &quot;Cpu(s)&quot; | awk &apos;{print $2}&apos;)
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO instance_cpu (created_at, value)
        VALUES (&apos;$timestamp&apos;, $cpu_usage);&quot;

    # Record memory usage
    local memory_usage=$(free | grep Mem | awk &apos;{print ($3/$2 * 100)}&apos;)
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO instance_memory (created_at, value)
        VALUES (&apos;$timestamp&apos;, $memory_usage);&quot;

    # Record load averages
    local load_1min=$(uptime | awk &apos;{print $(NF-2)}&apos; | tr -d &apos;,&apos;)
    local load_5min=$(uptime | awk &apos;{print $(NF-1)}&apos; | tr -d &apos;,&apos;)
    local load_15min=$(uptime | awk &apos;{print $NF}&apos;)
    
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO instance_load_average (created_at, period, value)
        VALUES 
            (&apos;$timestamp&apos;, 1, $load_1min),
            (&apos;$timestamp&apos;, 5, $load_5min),
            (&apos;$timestamp&apos;, 15, $load_15min);&quot;

    # Record disk usage for each mount point
    df -P | grep &apos;^/&apos; | while read filesystem size used avail use mountpoint; do
        sqlite3 &quot;$DB_PATH&quot; &quot;
            INSERT INTO instance_disk_usage (created_at, disk, value)
            VALUES (&apos;$timestamp&apos;, &apos;$mountpoint&apos;, ${use%\%});&quot;
    done
}

# Function to analyze security events from CloudPanel&apos;s event table
analyze_security_events() {
    echo &quot;Analyzing security events...&quot;
    
    # Get recent security events
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            created_at,
            user_name,
            user_role,
            event_name,
            event_data,
            source_ip_address,
            user_agent
        FROM event
        WHERE created_at &amp;gt; datetime(&apos;now&apos;, &apos;-1 hour&apos;)
        ORDER BY created_at DESC;&quot; | while IFS=&apos;|&apos; read -r timestamp username role event_name data ip agent; do
        
        # Analyze for suspicious patterns
        case &quot;$event_name&quot; in
            &quot;login_failed&quot;)
                check_brute_force_attempts &quot;$username&quot; &quot;$ip&quot;
                ;;
            &quot;file_modified&quot;)
                verify_file_changes &quot;$data&quot;
                ;;
            &quot;config_changed&quot;)
                audit_configuration_change &quot;$username&quot; &quot;$data&quot;
                ;;
        esac
    done
}

# Function to check for brute force attempts
check_brute_force_attempts() {
    local username=&quot;$1&quot;
    local ip=&quot;$2&quot;
    
    # Count recent failed login attempts
    local failed_attempts=$(sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT COUNT(*) FROM event 
        WHERE event_name = &apos;login_failed&apos;
        AND source_ip_address = &apos;$ip&apos;
        AND created_at &amp;gt; datetime(&apos;now&apos;, &apos;-1 hour&apos;);&quot;)
    
    if [ &quot;$failed_attempts&quot; -gt 5 ]; then
        # Log the security incident
        log_security_incident &quot;Possible brute force attack&quot; \
            &quot;Multiple failed login attempts from IP: $ip targeting user: $username&quot;
        
        # Block the IP address through CloudPanel&apos;s firewall
        sqlite3 &quot;$DB_PATH&quot; &quot;
            INSERT INTO blocked_ip (
                site_id,
                created_at,
                updated_at,
                ip
            ) VALUES (
                NULL,
                datetime(&apos;now&apos;),
                datetime(&apos;now&apos;),
                &apos;$ip&apos;
            );&quot;
    fi
}

# Function to verify file changes
verify_file_changes() {
    local file_data=&quot;$1&quot;
    
    # Extract file path from event data
    local file_path=$(echo &quot;$file_data&quot; | jq -r &apos;.path&apos;)
    
    if [ -f &quot;$file_path&quot; ]; then
        # Calculate current file hash
        local current_hash=$(sha256sum &quot;$file_path&quot; | cut -d&apos; &apos; -f1)
        
        # Compare with expected hash if available
        if [ -f &quot;${file_path}.hash&quot; ]; then
            local expected_hash=$(cat &quot;${file_path}.hash&quot;)
            if [ &quot;$current_hash&quot; != &quot;$expected_hash&quot; ]; then
                log_security_incident &quot;Unexpected file modification&quot; \
                    &quot;File $file_path has been modified unexpectedly&quot;
            fi
        else
            # Store initial hash for future comparison
            echo &quot;$current_hash&quot; &amp;gt; &quot;${file_path}.hash&quot;
        fi
    fi
}

# Function to audit configuration changes
audit_configuration_change() {
    local username=&quot;$1&quot;
    local config_data=&quot;$2&quot;
    
    # Log the configuration change
    echo &quot;[$(date &apos;+%Y-%m-%d %H:%M:%S&apos;)] User $username modified configuration: $config_data&quot; &amp;gt;&amp;gt; &quot;$AUDIT_DIR/config_changes.log&quot;
    
    # Store in CloudPanel&apos;s event system
    sqlite3 &quot;$DB_PATH&quot; &quot;
        INSERT INTO event (
            created_at,
            user_name,
            user_role,
            event_name,
            event_data
        ) VALUES (
            datetime(&apos;now&apos;),
            &apos;$username&apos;,
            (SELECT role FROM user WHERE user_name = &apos;$username&apos;),
            &apos;config_audit&apos;,
            &apos;$config_data&apos;
        );&quot;
}

# Function to generate security reports
generate_security_report() {
    local report_file=&quot;$AUDIT_DIR/security_report_$(date +%Y%m%d).txt&quot;
    
    echo &quot;CloudPanel Security Audit Report - $(date)&quot; &amp;gt; &quot;$report_file&quot;
    echo &quot;==========================================&quot; &amp;gt;&amp;gt; &quot;$report_file&quot;
    
    # System Metrics Summary
    echo &quot;System Performance Metrics:&quot; &amp;gt;&amp;gt; &quot;$report_file&quot;
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            avg(value) as avg_cpu,
            max(value) as max_cpu
        FROM instance_cpu 
        WHERE created_at &amp;gt; datetime(&apos;now&apos;, &apos;-24 hours&apos;);&quot; &amp;gt;&amp;gt; &quot;$report_file&quot;
    
    # Security Events Summary
    echo -e &quot;\nSecurity Events Summary:&quot; &amp;gt;&amp;gt; &quot;$report_file&quot;
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            event_name,
            COUNT(*) as event_count
        FROM event
        WHERE created_at &amp;gt; datetime(&apos;now&apos;, &apos;-24 hours&apos;)
        GROUP BY event_name;&quot; &amp;gt;&amp;gt; &quot;$report_file&quot;
    
    # Failed Login Attempts
    echo -e &quot;\nFailed Login Attempts:&quot; &amp;gt;&amp;gt; &quot;$report_file&quot;
    sqlite3 &quot;$DB_PATH&quot; &quot;
        SELECT 
            source_ip_address,
            COUNT(*) as attempt_count
        FROM event
        WHERE event_name = &apos;login_failed&apos;
        AND created_at &amp;gt; datetime(&apos;now&apos;, &apos;-24 hours&apos;)
        GROUP BY source_ip_address
        HAVING attempt_count &amp;gt; 3;&quot; &amp;gt;&amp;gt; &quot;$report_file&quot;
}

# Main execution loop
main() {
    echo &quot;Starting security monitoring system...&quot;
    
    while true; do
        # Record system metrics
        record_system_metrics
        
        # Analyze security events
        analyze_security_events
        
        # Generate daily report at midnight
        if [ &quot;$(date +%H:%M)&quot; = &quot;00:00&quot; ]; then
            generate_security_report
        fi
        
        # Sleep for monitoring interval
        sleep 300
    done
}

main &quot;$@&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This monitoring system provides:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Comprehensive system metrics tracking using CloudPanel&apos;s database structure&lt;/li&gt;
&lt;li&gt;Security event analysis and correlation&lt;/li&gt;
&lt;li&gt;Automated threat detection and response&lt;/li&gt;
&lt;li&gt;Configuration change auditing&lt;/li&gt;
&lt;li&gt;Daily security reports&lt;/li&gt;
&lt;li&gt;Integration with CloudPanel&apos;s event logging system&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>CloudPanel Sync Script Production to Staging</title><link>https://hhf.technology/blog/cloudpanel-sync/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-sync/</guid><description>Bash script for sync WPress installations between CloudPanel environments.</description><pubDate>Wed, 08 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why Automate CloudPanel Synchronization?&lt;/h2&gt;
&lt;p&gt;Managing multiple WordPress environments is a crucial part of modern web development. Whether you&apos;re testing updates, developing new features, or troubleshooting issues, having an automated synchronization system between your production and staging environments is essential. This guide will walk you through creating and optimizing a robust synchronization script for CloudPanel environments.&lt;/p&gt;
&lt;h2&gt;Understanding the Synchronization Process&lt;/h2&gt;
&lt;p&gt;Before diving into the code, let&apos;s understand what our script accomplishes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Safely exports the production database&lt;/li&gt;
&lt;li&gt;Transfers website files while preserving critical configurations&lt;/li&gt;
&lt;li&gt;Updates database URLs and settings for the staging environment&lt;/li&gt;
&lt;li&gt;Maintains proper permissions and security&lt;/li&gt;
&lt;li&gt;Handles cache management&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The Synchronization Script&lt;/h2&gt;
&lt;p&gt;Let&apos;s look at the synchronization script with error handling, logging, and security features:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
# =========================================================================== #
# Description:       CloudPanel Sync Script
# Purpose:           Synchronize WordPress sites between production and staging
# Environment:       CloudPanel (Debian/Ubuntu)
# Requirements:      CloudPanel, SSH key authentication
# =========================================================================== #

# Script configuration
set -euo pipefail  # Enhanced error handling
trap &apos;echo &quot;Error on line $LINENO&quot;&apos; ERR

# Configuration variables
declare -A config=(
    [&quot;PROD_DOMAIN&quot;]=&quot;example.com&quot;
    [&quot;PROD_USER&quot;]=&quot;prod-user&quot;
    [&quot;STAGING_DOMAIN&quot;]=&quot;staging.example.com&quot;
    [&quot;STAGING_USER&quot;]=&quot;staging-user&quot;
    [&quot;REMOTE_SSH&quot;]=&quot;root@production-ip&quot;
    [&quot;TABLE_PREFIX&quot;]=&quot;wp_&quot;
)

# Path configurations
declare -A paths=(
    [&quot;PROD_PATH&quot;]=&quot;/home/${config[PROD_USER]}/htdocs/${config[PROD_DOMAIN]}&quot;
    [&quot;STAGING_PATH&quot;]=&quot;/home/${config[STAGING_USER]}/htdocs/${config[STAGING_DOMAIN]}&quot;
    [&quot;LOG_FILE&quot;]=&quot;/home/${config[STAGING_USER]}/sync.log&quot;
)

# Enhanced logging function
log() {
    local level=$1
    shift
    echo &quot;[$(date -u &apos;+%Y-%m-%d %H:%M:%S UTC&apos;)] [$level] $*&quot; | tee -a &quot;${paths[LOG_FILE]}&quot;
}

# Validation functions
validate_paths() {
    if [[ ! -d &quot;${paths[STAGING_PATH]}&quot; ]]; then
        log &quot;ERROR&quot; &quot;Staging directory ${paths[STAGING_PATH]} not found&quot;
        exit 1
    fi
}

# Database backup function with compression
backup_database() {
    log &quot;INFO&quot; &quot;Starting database backup&quot;
    ssh &quot;${config[REMOTE_SSH]}&quot; &quot;clpctl db:export --databaseName=${config[PROD_USER]} \
        --file=/home/${config[PROD_USER]}/tmp/backup.sql.gz&quot;
}

# Enhanced database sync with progress
sync_database() {
    log &quot;INFO&quot; &quot;Synchronizing database&quot;
    rsync -azP --info=progress2 \
        &quot;${config[REMOTE_SSH]}:/home/${config[PROD_USER]}/tmp/backup.sql.gz&quot; \
        &quot;/home/${config[STAGING_USER]}/tmp/&quot;
}

# Main execution flow
main() {
    log &quot;INFO&quot; &quot;Starting synchronization process&quot;
    
    # Initial validation
    validate_paths
    
    # Backup and sync
    backup_database
    sync_database
    
    # Update database URLs
    log &quot;INFO&quot; &quot;Updating database URLs&quot;
    mysql --defaults-extra-file=&quot;/home/${config[STAGING_USER]}/my.cnf&quot; \
        -D &quot;${config[STAGING_USER]}&quot; -e &quot;
        UPDATE ${config[TABLE_PREFIX]}options 
        SET option_value = REPLACE(option_value, 
            &apos;https://${config[PROD_DOMAIN]}&apos;, 
            &apos;https://${config[STAGING_DOMAIN]}&apos;)
        WHERE option_name IN (&apos;home&apos;, &apos;siteurl&apos;);&quot;
    
    # File synchronization with exclusions
    log &quot;INFO&quot; &quot;Syncing files&quot;
    rsync -azP --delete \
        --exclude={&apos;wp-config.php&apos;,&apos;.user.ini&apos;,&apos;wp-content/cache/*&apos;} \
        &quot;${config[REMOTE_SSH]}:${paths[PROD_PATH]}/&quot; \
        &quot;${paths[STAGING_PATH]}/&quot;
    
    # Security measures
    log &quot;INFO&quot; &quot;Applying security settings&quot;
    mysql --defaults-extra-file=&quot;/home/${config[STAGING_USER]}/my.cnf&quot; \
        -D &quot;${config[STAGING_USER]}&quot; \
        -e &quot;UPDATE ${config[TABLE_PREFIX]}options 
            SET option_value = &apos;0&apos; 
            WHERE option_name = &apos;blog_public&apos;;&quot;
    
    # Cleanup
    log &quot;INFO&quot; &quot;Performing cleanup&quot;
    rm -f &quot;/home/${config[STAGING_USER]}/tmp/backup.sql.gz&quot;
    
    log &quot;SUCCESS&quot; &quot;Synchronization completed&quot;
}

# Execute main function
main
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Key implementation and Best Practices&lt;/h2&gt;
&lt;p&gt;Let&apos;s break down the key implementation in this enhanced version:&lt;/p&gt;
&lt;h3&gt;1. Structured Configuration&lt;/h3&gt;
&lt;p&gt;We&apos;ve organized configuration variables into associative arrays, making the script more maintainable and easier to update:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;declare -A config=(
    [&quot;PROD_DOMAIN&quot;]=&quot;example.com&quot;
    [&quot;STAGING_DOMAIN&quot;]=&quot;staging.example.com&quot;
    # ... other configurations
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Enhanced Error Handling&lt;/h3&gt;
&lt;p&gt;The script now includes proper error trapping and handling:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set -euo pipefail
trap &apos;echo &quot;Error on line $LINENO&quot;&apos; ERR
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Robust Logging&lt;/h3&gt;
&lt;p&gt;A dedicated logging function provides consistent and detailed logging:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;log() {
    local level=$1
    shift
    echo &quot;[$(date -u &apos;+%Y-%m-%d %H:%M:%S UTC&apos;)] [$level] $*&quot; | tee -a &quot;${paths[LOG_FILE]}&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Common Scenarios and Solutions&lt;/h2&gt;
&lt;h3&gt;Scenario 1: Large File Transfers&lt;/h3&gt;
&lt;p&gt;When dealing with large WordPress installations:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Add these rsync options for large transfers
rsync -azP --partial --partial-dir=.rsync-partial \
    --exclude={&apos;wp-config.php&apos;,&apos;.user.ini&apos;,&apos;wp-content/cache/*&apos;} \
    &quot;${config[REMOTE_SSH]}:${paths[PROD_PATH]}/&quot; \
    &quot;${paths[STAGING_PATH]}/&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Scenario 2: Custom Plugin Configurations&lt;/h3&gt;
&lt;p&gt;For sites with specific plugin configurations:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Add to the database update queries
mysql --defaults-extra-file=&quot;/home/${config[STAGING_USER]}/my.cnf&quot; \
    -D &quot;${config[STAGING_USER]}&quot; -e &quot;
    UPDATE ${config[TABLE_PREFIX]}options 
    SET option_value = REPLACE(
        option_value, 
        &apos;production-specific-setting&apos;, 
        &apos;staging-specific-setting&apos;
    )
    WHERE option_name LIKE &apos;%plugin_setting%&apos;;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Scenario 3: Handling Multiple Sites&lt;/h3&gt;
&lt;p&gt;For managing multiple WordPress installations:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create a sites configuration file
cat &amp;gt; sites.conf &amp;lt;&amp;lt; EOF
site1:example1.com:user1
site2:example2.com:user2
EOF

# Modified script to handle multiple sites
while IFS=: read -r site domain user; do
    config[&quot;PROD_DOMAIN&quot;]=$domain
    config[&quot;PROD_USER&quot;]=$user
    main
done &amp;lt; sites.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Best Practices for Production Use&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Always Test First&lt;/strong&gt;: Run the script on a test environment before implementing in production.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backup Strategy&lt;/strong&gt;: Implement proper backup procedures:&lt;pre&gt;&lt;code&gt;# Add to the script before main sync
backup_date=$(date +%Y%m%d_%H%M%S)
clpctl backup:create --name=&quot;pre_sync_${backup_date}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Considerations&lt;/strong&gt;: Use SSH keys and restrict permissions:&lt;pre&gt;&lt;code&gt;chmod 600 /home/${config[STAGING_USER]}/my.cnf
chmod 700 /home/${config[STAGING_USER]}/tmp
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Monitoring and Maintenance&lt;/h2&gt;
&lt;p&gt;To ensure your synchronization system remains reliable:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Log Rotation&lt;/strong&gt;: Implement log rotation to manage log files:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Add to crontab
0 0 * * * logrotate -f /etc/logrotate.d/cloudpanel-sync
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Health Checks&lt;/strong&gt;: Add post-sync validation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Add to the main function
check_wordpress_health() {
    curl -sL &quot;https://${config[STAGING_DOMAIN]}/wp-admin&quot; | grep -q &quot;wp-login&quot;
    return $?
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This synchronization script provides a robust foundation for managing WordPress environments in CloudPanel. By implementing and following the best practices, you can ensure reliable and efficient synchronization between your production and staging environments.&lt;/p&gt;
&lt;p&gt;Remember to always test the script in a controlled environment first and maintain proper backups before running any synchronization operations. The script can be further customized based on your specific needs and requirements.&lt;/p&gt;
&lt;p&gt;For more advanced usage and customization options, open a discussion on our forum https://forum.hhf.technology/.&lt;/p&gt;
</content:encoded></item><item><title>Guide-Building &amp; Deploying Naxsi WAF on CloudPanel</title><link>https://hhf.technology/blog/cloudpanel-waf-nasxi/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-waf-nasxi/</guid><description>Comprehensive Guide-Building and Deploying Naxsi WAF on CloudPanel.</description><pubDate>Wed, 08 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Comprehensive Guide: Building and Deploying Naxsi WAF on CloudPanel&lt;/h1&gt;
&lt;h2&gt;⚠️ CRITICAL ENVIRONMENT NOTICE&lt;/h2&gt;
&lt;h3&gt;Execution Environment Requirements&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;: This operation must be executed exclusively in a non-production environment.&lt;/p&gt;
&lt;h3&gt;Risk Assessment:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;System stability may be affected during module compilation and installation&lt;/li&gt;
&lt;li&gt;Web services will require restart&lt;/li&gt;
&lt;li&gt;Existing NGINX configuration may need modifications&lt;/li&gt;
&lt;li&gt;No automatic rollback mechanisms are available&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Required Environment:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Development/staging CloudPanel instance&lt;/li&gt;
&lt;li&gt;Complete system backup&lt;/li&gt;
&lt;li&gt;Isolated network segment&lt;/li&gt;
&lt;li&gt;Non-production workload&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;DO NOT PROCEED&lt;/strong&gt; with execution in any production environment under any circumstances.&lt;/p&gt;
&lt;h2&gt;Understanding CloudPanel&apos;s NGINX Structure&lt;/h2&gt;
&lt;p&gt;CloudPanel uses a specific NGINX configuration structure that we need to work with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Main configuration: &lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Site configurations: &lt;code&gt;/etc/nginx/sites-enabled/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Module configurations: &lt;code&gt;/etc/nginx/modules-available/&lt;/code&gt; and &lt;code&gt;/etc/nginx/modules-enabled/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CloudPanel vhost template: Located in CloudPanel&apos;s configuration directory&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;First, switch to root user and install the required dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo su

# Install build essentials and required libraries
apt update
apt install -y build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev wget git

# Install additional CloudPanel-specific dependencies
apt install -y libmodsecurity3 libmodsecurity-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Download and Prepare Build Environment&lt;/h2&gt;
&lt;p&gt;Create a dedicated build directory and download required components:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create build directory
mkdir -p /root/naxsi-build
cd /root/naxsi-build

# Get NGINX version from current installation
NGINX_VERSION=$(nginx -v 2&amp;gt;&amp;amp;1 | grep -o &apos;[0-9.]*$&apos;)
echo &quot;Building for NGINX version: $NGINX_VERSION&quot;

# Download NGINX source
wget &quot;https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz&quot;
tar -xzf nginx-${NGINX_VERSION}.tar.gz

# Download Naxsi
NAXSI_VERSION=1.6
wget &quot;https://github.com/wargio/naxsi/releases/download/${NAXSI_VERSION}/naxsi-${NAXSI_VERSION}-src-with-deps.tar.gz&quot;
tar -xzf naxsi-${NAXSI_VERSION}-src-with-deps.tar.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Compile Naxsi Module&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;cd /root/naxsi-build/nginx-${NGINX_VERSION}

# Get existing NGINX configuration
NGINX_CONFIGURE_ARGS=$(nginx -V 2&amp;gt;&amp;amp;1 | grep &quot;configure arguments:&quot; | cut -d &quot; &quot; -f2-)

# Configure NGINX with Naxsi
./configure $NGINX_CONFIGURE_ARGS --add-dynamic-module=../naxsi/naxsi_src/

# Compile only the modules
make modules
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Install Naxsi Module&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# Create modules directory if it doesn&apos;t exist
mkdir -p /usr/lib/nginx/modules

# Copy the compiled module
cp objs/ngx_http_naxsi_module.so /usr/lib/nginx/modules/

# Copy Naxsi rules
mkdir -p /etc/nginx/naxsi
cp ../naxsi/naxsi_rules/* /etc/nginx/naxsi/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Configure Naxsi in CloudPanel&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Create module configuration:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# Create Naxsi module configuration
cat &amp;gt; /etc/nginx/modules-available/mod-naxsi.conf &amp;lt;&amp;lt; &apos;EOL&apos;
load_module modules/ngx_http_naxsi_module.so;
EOL

# Enable the module
ln -s /etc/nginx/modules-available/mod-naxsi.conf /etc/nginx/modules-enabled/50-mod-naxsi.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Create base Naxsi configuration:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# Create base configuration
cat &amp;gt; /etc/nginx/naxsi/naxsi-base.conf &amp;lt;&amp;lt; &apos;EOL&apos;
# Basic configuration
SecRulesEnabled;
LibInjectionSql;
LibInjectionXss;
DeniedUrl &quot;/RequestDenied&quot;;

# Core rules
include /etc/nginx/naxsi/naxsi_core.rules;

# Check rules
CheckRule &quot;$SQL &amp;gt;= 8&quot; BLOCK;
CheckRule &quot;$XSS &amp;gt;= 8&quot; BLOCK;
CheckRule &quot;$RFI &amp;gt;= 8&quot; BLOCK;
CheckRule &quot;$UPLOAD &amp;gt;= 8&quot; BLOCK;
CheckRule &quot;$LIBINJECTION_SQL &amp;gt;= 8&quot; BLOCK;
CheckRule &quot;$LIBINJECTION_XSS &amp;gt;= 8&quot; BLOCK;
EOL
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Integrating with CloudPanel Vhost Configuration&lt;/h2&gt;
&lt;p&gt;Based on the provided CloudPanel configuration template, we&apos;ll add Naxsi support while maintaining CloudPanel&apos;s functionality. Create a Naxsi configuration snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat &amp;gt; /etc/nginx/snippets/naxsi-location.conf &amp;lt;&amp;lt; &apos;EOL&apos;
# Naxsi protection
include /etc/nginx/naxsi/naxsi-base.conf;

# Common WordPress whitelist rules
BasicRule wl:1315 &quot;mz:$BODY_VAR:comment&quot;;
BasicRule wl:1315 &quot;mz:$BODY_VAR:content&quot;;
BasicRule wl:1315 &quot;mz:$BODY_VAR:excerpt&quot;;
BasicRule wl:1315 &quot;mz:$BODY_VAR:title&quot;;
BasicRule wl:1315 &quot;mz:$BODY_VAR:post_content&quot;;

# Add request denied location
location /RequestDenied {
    internal;
    return 403;
}
EOL
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Modify Site Configuration&lt;/h2&gt;
&lt;p&gt;For each site you want to protect with Naxsi, modify the configuration to include Naxsi rules. Here&apos;s an example based on the provided CloudPanel configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    listen 80;
    listen [::]:80;
    server_name example.com;

    # Include Naxsi base configuration
    include /etc/nginx/naxsi/naxsi-base.conf;

    location / {
        # Include Naxsi location rules
        include /etc/nginx/snippets/naxsi-location.conf;

        # Existing CloudPanel proxy configuration
        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_pass http://backend;
    }

    # RequestDenied location (required by Naxsi)
    location /RequestDenied {
        internal;
        return 403;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Testing and Verification&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Verify NGINX configuration:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;nginx -t
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Test Naxsi module loading:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;nginx -V 2&amp;gt;&amp;amp;1 | grep naxsi
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Restart NGINX:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;systemctl restart nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Test Naxsi protection:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# Test SQL injection protection
curl &quot;http://your-site.com/?id=1%20OR%201=1&quot;

# Test XSS protection
curl &quot;http://your-site.com/?&amp;lt;script&amp;gt;alert(1)&amp;lt;/script&amp;gt;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Common Issues and Troubleshooting&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Module Loading Issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify module path in configuration&lt;/li&gt;
&lt;li&gt;Check NGINX error logs: &lt;code&gt;tail -f /var/log/nginx/error.log&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Ensure proper file permissions on module and configuration files&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rule Conflicts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start with learning mode: Add &lt;code&gt;LearningMode;&lt;/code&gt; to your configuration&lt;/li&gt;
&lt;li&gt;Monitor logs for false positives&lt;/li&gt;
&lt;li&gt;Create specific whitelists as needed&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CloudPanel Compatibility:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep CloudPanel&apos;s proxy settings intact&lt;/li&gt;
&lt;li&gt;Maintain proper order of includes and configurations&lt;/li&gt;
&lt;li&gt;Test thoroughly after any configuration changes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Maintenance and Updates&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Regular tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monitor NGINX and Naxsi logs&lt;/li&gt;
&lt;li&gt;Update rules based on false positives/negatives&lt;/li&gt;
&lt;li&gt;Keep track of Naxsi updates and security patches&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Backup procedures:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maintain copies of custom rules and configurations&lt;/li&gt;
&lt;li&gt;Document all modifications to CloudPanel configurations&lt;/li&gt;
&lt;li&gt;Keep build environment for future updates&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Security Best Practices&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Rule Management:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start with strict rules and whitelist as needed&lt;/li&gt;
&lt;li&gt;Document all rule modifications&lt;/li&gt;
&lt;li&gt;Regular review of whitelisted rules&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Monitoring:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable detailed logging for blocked requests&lt;/li&gt;
&lt;li&gt;Set up alerts for repeated attacks&lt;/li&gt;
&lt;li&gt;Regular review of Naxsi logs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Performance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monitor system resources after enabling Naxsi&lt;/li&gt;
&lt;li&gt;Optimize rules for your specific use case&lt;/li&gt;
&lt;li&gt;Regular cleanup of log files&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember to always test thoroughly in a staging environment before deploying to production. Keep detailed documentation of all modifications and custom rules for future reference.&lt;/p&gt;
</content:encoded></item><item><title>Practical Naxsi WAF Implementation Examples for CloudPanel</title><link>https://hhf.technology/blog/cloudpanel-waf-nasxi-senerios/</link><guid isPermaLink="true">https://hhf.technology/blog/cloudpanel-waf-nasxi-senerios/</guid><description>This document provides detailed examples and practical configurations</description><pubDate>Wed, 08 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Practical Naxsi WAF Implementation Examples for CloudPanel&lt;/h1&gt;
&lt;p&gt;This document provides detailed examples and practical configurations for implementing Naxsi WAF in CloudPanel environments. Each example includes explanations of the rules and their purposes, helping you understand how to protect different types of web applications.&lt;/p&gt;
&lt;h2&gt;Basic WordPress Protection&lt;/h2&gt;
&lt;p&gt;WordPress sites in CloudPanel often need special consideration due to their dynamic nature. Here&apos;s a comprehensive configuration that balances security with functionality:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Include in the server block of your WordPress site
server {
    # Standard CloudPanel configuration remains unchanged
    listen 80;
    listen [::]:80;
    server_name example.com;
    
    # Enable Naxsi base rules
    include /etc/nginx/naxsi/naxsi-base.conf;
    
    # WordPress-specific whitelist rules
    include /etc/nginx/naxsi/wordpress.rules;
    
    location / {
        # Standard WordPress handling
        try_files $uri $uri/ /index.php?$args;
        
        # WordPress-specific Naxsi configurations
        BasicRule wl:1315,1101 &quot;mz:$BODY_VAR:post_title&quot;;
        BasicRule wl:1315,1101 &quot;mz:$BODY_VAR:content&quot;;
        BasicRule wl:1315 &quot;mz:$BODY_VAR:excerpt&quot;;
        BasicRule wl:1101 &quot;mz:$BODY_VAR:cat&quot;;
        
        # Allow WordPress admin actions
        BasicRule wl:1000,1015 &quot;mz:$URL:/wp-admin/|$BODY_VAR:action&quot;;
    }
    
    # Special handling for wp-admin
    location /wp-admin {
        # Allow file uploads in wp-admin
        BasicRule wl:1500 &quot;mz:$URL:/wp-admin/|$BODY_VAR:attachment&quot;;
        BasicRule wl:1310,1311 &quot;mz:$URL:/wp-admin/|BODY&quot;;
        
        # Standard CloudPanel proxy configuration
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration protects against common WordPress attack vectors while allowing legitimate administrative actions. The whitelist rules are carefully crafted to permit essential WordPress functionality while maintaining security.&lt;/p&gt;
&lt;h2&gt;E-commerce Protection Example&lt;/h2&gt;
&lt;p&gt;For e-commerce sites running on CloudPanel, we need to balance strict security with user experience. Here&apos;s an example configuration for an e-commerce platform:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# E-commerce specific Naxsi rules
server {
    listen 80;
    listen [::]:80;
    server_name shop.example.com;
    
    # Basic Naxsi configuration
    include /etc/nginx/naxsi/naxsi-base.conf;
    
    # E-commerce specific rules
    location / {
        # Allow product searches with special characters
        BasicRule wl:1001,1015 &quot;mz:$ARGS_VAR:q&quot;;
        
        # Allow price ranges in filters
        BasicRule wl:1015 &quot;mz:$ARGS_VAR:price_min|$ARGS_VAR:price_max&quot;;
        
        # Allow product sorting
        BasicRule wl:1015 &quot;mz:$ARGS_VAR:sort_by&quot;;
        
        # Standard CloudPanel proxy settings
        proxy_pass http://backend;
        proxy_set_header Host $host;
    }
    
    # Shopping cart protection
    location /cart {
        # Allow quantity updates
        BasicRule wl:1101 &quot;mz:$BODY_VAR:quantity&quot;;
        
        # Allow product variants
        BasicRule wl:1015 &quot;mz:$BODY_VAR:variant_id&quot;;
        
        # Strict XSS protection
        CheckRule &quot;$XSS &amp;gt;= 4&quot; BLOCK;
        CheckRule &quot;$LIBINJECTION_XSS &amp;gt;= 4&quot; BLOCK;
    }
    
    # Checkout process protection
    location /checkout {
        # Allow address input with special characters
        BasicRule wl:1315 &quot;mz:$BODY_VAR:address&quot;;
        BasicRule wl:1315 &quot;mz:$BODY_VAR:address2&quot;;
        
        # Allow postal codes with special formats
        BasicRule wl:1015 &quot;mz:$BODY_VAR:postcode&quot;;
        
        # Extra protection for payment data
        CheckRule &quot;$SQL &amp;gt;= 4&quot; BLOCK;
        CheckRule &quot;$RFI &amp;gt;= 2&quot; BLOCK;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;API Protection Example&lt;/h2&gt;
&lt;p&gt;When protecting APIs in CloudPanel, we need specific configurations to handle JSON data and API-specific threats:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# API-specific Naxsi configuration
server {
    listen 80;
    listen [::]:80;
    server_name api.example.com;
    
    # Enable JSON parsing
    include /etc/nginx/naxsi/naxsi-base.conf;
    
    # API request handling
    location /api/v1 {
        # Allow JSON content type
        BasicRule wl:1200,1205 &quot;mz:$HEADERS_VAR:content-type&quot;;
        
        # Allow complex JSON structures
        BasicRule wl:1310,1311 &quot;mz:BODY&quot;;
        
        # Strict SQL injection protection
        CheckRule &quot;$LIBINJECTION_SQL &amp;gt;= 4&quot; BLOCK;
        CheckRule &quot;$SQL &amp;gt;= 4&quot; BLOCK;
        
        # Standard CloudPanel proxy configuration
        proxy_pass http://backend;
        proxy_set_header Host $host;
    }
    
    # Authentication endpoints
    location /api/v1/auth {
        # Allow JSON Web Tokens
        BasicRule wl:1100,1101 &quot;mz:$BODY_VAR:token&quot;;
        
        # Allow email addresses
        BasicRule wl:1315 &quot;mz:$BODY_VAR:email&quot;;
        
        # Extra protection for auth endpoints
        CheckRule &quot;$XSS &amp;gt;= 2&quot; BLOCK;
        CheckRule &quot;$RFI &amp;gt;= 2&quot; BLOCK;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Learning Mode Configuration&lt;/h2&gt;
&lt;p&gt;During initial deployment, it&apos;s crucial to use learning mode to understand your application&apos;s behavior. Here&apos;s an example configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Learning mode configuration
server {
    listen 80;
    listen [::]:80;
    server_name staging.example.com;
    
    # Enable learning mode
    include /etc/nginx/naxsi/naxsi-base.conf;
    LearningMode;
    
    # Enable detailed logging
    set $naxsi_extensive_log 1;
    
    location / {
        # Log all potential violations
        BasicRule &quot;log:all&quot;;
        
        # Standard CloudPanel proxy configuration
        proxy_pass http://backend;
        proxy_set_header Host $host;
    }
    
    # Custom log format for analysis
    log_format naxsi_learning &apos;$remote_addr - $remote_user [$time_local] &quot;$request&quot; &apos;
                            &apos;$status $body_bytes_sent &quot;$http_referer&quot; &apos;
                            &apos;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot; &apos;
                            &apos;naxsi: &quot;$naxsi_sig&quot; &quot;$naxsi_match&quot;&apos;;
    
    access_log /var/log/nginx/naxsi_learning.log naxsi_learning;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Advanced Security Headers&lt;/h2&gt;
&lt;p&gt;Enhance your Naxsi protection with additional security headers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Security headers configuration
server {
    listen 80;
    listen [::]:80;
    server_name secure.example.com;
    
    # Include Naxsi base configuration
    include /etc/nginx/naxsi/naxsi-base.conf;
    
    # Add security headers
    add_header X-Frame-Options &quot;SAMEORIGIN&quot; always;
    add_header X-Content-Type-Options &quot;nosniff&quot; always;
    add_header X-XSS-Protection &quot;1; mode=block&quot; always;
    add_header Referrer-Policy &quot;strict-origin-when-cross-origin&quot; always;
    add_header Content-Security-Policy &quot;default-src &apos;self&apos;; script-src &apos;self&apos; &apos;unsafe-inline&apos; &apos;unsafe-eval&apos;; style-src &apos;self&apos; &apos;unsafe-inline&apos;;&quot; always;
    
    location / {
        # Standard Naxsi protection
        include /etc/nginx/naxsi/naxsi-base.conf;
        
        # CloudPanel proxy configuration
        proxy_pass http://backend;
        proxy_set_header Host $host;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;File Upload Protection&lt;/h2&gt;
&lt;p&gt;For sites handling file uploads, configure specific protections:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# File upload protection
server {
    listen 80;
    listen [::]:80;
    server_name upload.example.com;
    
    # Include Naxsi base configuration
    include /etc/nginx/naxsi/naxsi-base.conf;
    
    # File upload location
    location /upload {
        # Allow file uploads but maintain security
        BasicRule wl:1500 &quot;mz:$URL:/upload|BODY&quot;;
        
        # Limit file types
        if ($upload_filename ~* (?i).(php|phtml|php3|php4|php5|php6|php7|pht|phar|inc)$) {
            return 403;
        }
        
        # Additional upload protections
        client_max_body_size 10M;
        client_body_buffer_size 128k;
        
        # CloudPanel proxy configuration
        proxy_pass http://backend;
        proxy_set_header Host $host;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Common Naxsi Rules Explained&lt;/h2&gt;
&lt;p&gt;Understanding common Naxsi rules and their purposes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# SQL Injection Protection
CheckRule &quot;$SQL &amp;gt;= 8&quot; BLOCK;          # Block SQL injection attempts
CheckRule &quot;$LIBINJECTION_SQL &amp;gt;= 8&quot; BLOCK;  # Use libinjection for SQL detection

# XSS Protection
CheckRule &quot;$XSS &amp;gt;= 8&quot; BLOCK;          # Block Cross-site scripting
CheckRule &quot;$LIBINJECTION_XSS &amp;gt;= 8&quot; BLOCK;  # Use libinjection for XSS detection

# Directory Traversal Protection
CheckRule &quot;$TRAVERSAL &amp;gt;= 4&quot; BLOCK;    # Block directory traversal attempts

# Remote File Inclusion Protection
CheckRule &quot;$RFI &amp;gt;= 8&quot; BLOCK;          # Block remote file inclusion

# File Upload Protection
CheckRule &quot;$UPLOAD &amp;gt;= 8&quot; BLOCK;       # Block malicious file uploads
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each rule has a score threshold that determines when to block requests. Lower scores increase security but may cause false positives.&lt;/p&gt;
&lt;h2&gt;Monitoring and Logging Configuration&lt;/h2&gt;
&lt;p&gt;Implement comprehensive logging for Naxsi:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Logging configuration
http {
    # Define Naxsi log format
    log_format naxsi_json escape=json &apos;{&apos;
        &apos;&quot;timestamp&quot;:&quot;$time_iso8601&quot;,&apos;
        &apos;&quot;client&quot;:&quot;$remote_addr&quot;,&apos;
        &apos;&quot;method&quot;:&quot;$request_method&quot;,&apos;
        &apos;&quot;uri&quot;:&quot;$uri&quot;,&apos;
        &apos;&quot;args&quot;:&quot;$args&quot;,&apos;
        &apos;&quot;headers&quot;:{&apos;
            &apos;&quot;user-agent&quot;:&quot;$http_user_agent&quot;,&apos;
            &apos;&quot;referer&quot;:&quot;$http_referer&quot;&apos;
        &apos;},&apos;
        &apos;&quot;naxsi&quot;:{&apos;
            &apos;&quot;match&quot;:&quot;$naxsi_match&quot;,&apos;
            &apos;&quot;sig&quot;:&quot;$naxsi_sig&quot;,&apos;
            &apos;&quot;score&quot;:&quot;$naxsi_score&quot;,&apos;
            &apos;&quot;matches&quot;:&quot;$naxsi_matches&quot;&apos;
        &apos;}&apos;
    &apos;}&apos;;
    
    # Enable Naxsi logging
    access_log /var/log/nginx/naxsi_access.log naxsi_json if=$naxsi_matched;
    error_log /var/log/nginx/naxsi_error.log;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These examples demonstrate common Naxsi configurations for different scenarios in CloudPanel. Remember to adapt these examples to your specific needs and always test thoroughly in a staging environment before deploying to production.&lt;/p&gt;
</content:encoded></item><item><title>How to clean the commit history in git 🔍</title><link>https://hhf.technology/blog/commit-history-git/</link><guid isPermaLink="true">https://hhf.technology/blog/commit-history-git/</guid><description>This process is often used when the commit history contains sensitive information.</description><pubDate>Mon, 06 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To clean the commit history in Git, you can follow a series of steps that effectively remove all previous commits while keeping the current state of your code. This process is often used when the commit history contains unnecessary or sensitive information. Here’s how to do it:&lt;/p&gt;
&lt;h2&gt;Steps to Clean Git Commit History&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create an Orphan Branch&lt;/strong&gt;:
This step creates a new branch without any previous commit history.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout --orphan new_branch
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add All Files&lt;/strong&gt;:
Stage all files in your working directory for the new commit.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git add -A
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Commit the Changes&lt;/strong&gt;:
Make a new initial commit with all the files.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git commit -m &quot;Initial commit&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Delete the Old Main Branch&lt;/strong&gt;:
Remove the old branch that contains the history. This action is irreversible.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git branch -D main
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rename the New Branch&lt;/strong&gt;:
Rename your newly created branch to &lt;code&gt;main&lt;/code&gt; (or your preferred name).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git branch -m main
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Force Push to Remote Repository&lt;/strong&gt;:
Update your remote repository to reflect these changes, effectively overwriting the history.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git push -f origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Important Considerations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data Loss&lt;/strong&gt;: This process permanently deletes all previous commits, so ensure you have backups if needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaboration Impact&lt;/strong&gt;: If others are using the repository, communicate these changes as they will lose access to prior commit history.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This method is particularly useful for cleaning up repositories before public releases or when sensitive data has been committed unintentionally.&lt;/p&gt;
</content:encoded></item><item><title>Mastering OpenCTI Deployment with Docker 🛡️</title><link>https://hhf.technology/blog/deploying-opencti-platform-comprehensive-guide/</link><guid isPermaLink="true">https://hhf.technology/blog/deploying-opencti-platform-comprehensive-guide/</guid><description>A comprehensive guide to deploying and configuring OpenCTI.</description><pubDate>Wed, 04 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Understanding OpenCTI&lt;/h2&gt;
&lt;p&gt;OpenCTI (Open Cyber Threat Intelligence) represents a significant advancement in threat intelligence management. At its core, it&apos;s an open-source platform that transforms how organizations handle cyber threat intelligence, providing a comprehensive solution for collecting, analyzing, and sharing threat data.&lt;/p&gt;
&lt;h3&gt;Key Benefits&lt;/h3&gt;
&lt;p&gt;The platform offers several advantages that make it invaluable for security teams:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Centralized Intelligence Management: Consolidates threat data from multiple sources into a single, searchable platform&lt;/li&gt;
&lt;li&gt;Advanced Analysis Capabilities: Enables deep analysis of threats through relationship mapping and visualization&lt;/li&gt;
&lt;li&gt;Automated Data Processing: Reduces manual effort through automated ingestion and processing of threat intelligence&lt;/li&gt;
&lt;li&gt;STIX/TAXII Compatible: Natively supports industry-standard threat intelligence formats&lt;/li&gt;
&lt;li&gt;Extensible Architecture: Allows integration with various threat intelligence sources through connectors&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;System Architecture&lt;/h2&gt;
&lt;p&gt;OpenCTI&apos;s architecture is built on several key components, each serving a specific purpose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: React-based web interface for user interaction&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API&lt;/strong&gt;: GraphQL API for data access and manipulation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workers&lt;/strong&gt;: Distributed processing units for handling tasks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database Layer&lt;/strong&gt;: Elasticsearch for data storage and search capabilities&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Broker&lt;/strong&gt;: RabbitMQ for reliable message queuing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Object Storage&lt;/strong&gt;: MinIO for storing files and attachments&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache Layer&lt;/strong&gt;: Redis for performance optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Prerequisites&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Update system packages
apt update &amp;amp;&amp;amp; apt upgrade -y

# Install required packages
apt install docker-compose jq -y

# Configure system settings
echo &quot;vm.max_map_count=1048575&quot; &amp;gt;&amp;gt; /etc/sysctl.conf
sysctl -p

# Create application directory
mkdir -p /opt/opencti &amp;amp;&amp;amp; cd /opt/opencti
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Deployment Configuration&lt;/h2&gt;
&lt;p&gt;Let&apos;s examine the deployment configuration in detail:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3&apos;
services:
  redis:
    image: redis:7.2.5
    restart: always
    volumes:
      - redisdata:/data

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.13.4
    volumes:
      - esdata:/usr/share/elasticsearch/data
    environment:
      - discovery.type=single-node
      - xpack.ml.enabled=false
      - xpack.security.enabled=false
      - &quot;ES_JAVA_OPTS=-Xms${ELASTIC_MEMORY_SIZE} -Xmx${ELASTIC_MEMORY_SIZE}&quot;
    restart: always
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536

  # Additional services configuration...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Environment Configuration&lt;/h3&gt;
&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file with necessary configurations:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat &amp;lt;&amp;lt; EOF &amp;gt; .env
OPENCTI_ADMIN_EMAIL=admin@opencti.io
OPENCTI_ADMIN_PASSWORD=ChangeMePlease
OPENCTI_ADMIN_TOKEN=$(cat /proc/sys/kernel/random/uuid)
OPENCTI_BASE_URL=http://localhost:8080
MINIO_ROOT_USER=$(cat /proc/sys/kernel/random/uuid)
MINIO_ROOT_PASSWORD=$(cat /proc/sys/kernel/random/uuid)
RABBITMQ_DEFAULT_USER=guest
RABBITMQ_DEFAULT_PASS=guest
ELASTIC_MEMORY_SIZE=8G
CONNECTOR_ANALYSIS_ID=$(cat /proc/sys/kernel/random/uuid)
CONNECTOR_HISTORY_ID=$(cat /proc/sys/kernel/random/uuid)
CONNECTOR_EXPORT_FILE_STIX_ID=$(cat /proc/sys/kernel/random/uuid)
CONNECTOR_EXPORT_FILE_CSV_ID=$(cat /proc/sys/kernel/random/uuid)
CONNECTOR_IMPORT_FILE_STIX_ID=$(cat /proc/sys/kernel/random/uuid)
CONNECTOR_EXPORT_FILE_TXT_ID=$(cat /proc/sys/kernel/random/uuid)
CONNECTOR_IMPORT_DOCUMENT_ID=$(cat /proc/sys/kernel/random/uuid)
SMTP_HOSTNAME=$(hostname)
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Integrating Threat Intelligence Sources&lt;/h2&gt;
&lt;h3&gt;MITRE ATT&amp;amp;CK Integration&lt;/h3&gt;
&lt;p&gt;The MITRE connector provides comprehensive mapping of tactics, techniques, and procedures:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;connector-mitre:
  image: opencti/connector-mitre:6.2.6
  environment:
    - OPENCTI_URL=http://opencti:8080
    - OPENCTI_TOKEN=${OPENCTI_ADMIN_TOKEN}
    - CONNECTOR_ID=95996acf-1b08-4492-b66f-f54a46f14398
    - &quot;CONNECTOR_NAME=MITRE Datasets&quot;
    - CONNECTOR_SCOPE=tool,report,malware,identity,campaign,intrusion-set,attack-pattern,course-of-action
    - MITRE_INTERVAL=7
  restart: always
  depends_on:
    - opencti
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;MalwareBazaar Integration&lt;/h3&gt;
&lt;p&gt;Configure the MalwareBazaar connector for malware intelligence:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;connector-malwarebazaar:
  image: opencti/connector-malwarebazaar-recent-additions:6.2.6
  environment:
    - OPENCTI_URL=http://opencti:8080
    - OPENCTI_TOKEN=${OPENCTI_ADMIN_TOKEN}
    - CONNECTOR_ID=51ebc133-58c4-4a8b-9afc-4177e597cc91
    - MALWAREBAZAAR_RECENT_ADDITIONS_INCLUDE_TAGS=exe,dll,docm,docx,doc,xls,xlsx,xlsm,js
  restart: always
  depends_on:
    - opencti
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Post-Deployment Steps&lt;/h2&gt;
&lt;p&gt;After deploying OpenCTI, several important steps should be taken:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Security Hardening&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Change default passwords&lt;/li&gt;
&lt;li&gt;Configure SSL/TLS&lt;/li&gt;
&lt;li&gt;Set up network security groups&lt;/li&gt;
&lt;li&gt;Enable authentication for all services&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Connector Verification&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check connector logs for proper initialization&lt;/li&gt;
&lt;li&gt;Verify data ingestion from each source&lt;/li&gt;
&lt;li&gt;Monitor connector performance&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance Tuning&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adjust Elasticsearch settings based on data volume&lt;/li&gt;
&lt;li&gt;Configure worker counts for optimal processing&lt;/li&gt;
&lt;li&gt;Monitor and adjust cache settings&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backup Configuration&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set up regular backups of Elasticsearch data&lt;/li&gt;
&lt;li&gt;Configure MinIO backup strategy&lt;/li&gt;
&lt;li&gt;Document recovery procedures&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Best Practices and Common Pitfalls&lt;/h2&gt;
&lt;p&gt;When operating OpenCTI, consider these important guidelines:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resource Management&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monitor Elasticsearch heap usage&lt;/li&gt;
&lt;li&gt;Watch for worker queue buildup&lt;/li&gt;
&lt;li&gt;Regular cleanup of old data&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data Quality&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement data validation procedures&lt;/li&gt;
&lt;li&gt;Regular auditing of imported data&lt;/li&gt;
&lt;li&gt;Maintain consistent tagging practices&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance Optimization&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Index optimization in Elasticsearch&lt;/li&gt;
&lt;li&gt;Proper caching configuration&lt;/li&gt;
&lt;li&gt;Regular maintenance windows&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Troubleshooting Guide&lt;/h2&gt;
&lt;p&gt;Common issues and their solutions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Elasticsearch Issues&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Check cluster health
curl -X GET &quot;localhost:9200/_cluster/health?pretty&quot;

# Clear caches if needed
curl -X POST &quot;localhost:9200/_cache/clear?pretty&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Connector Problems&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# View connector logs
docker logs -f opencti-connector-mitre

# Restart problematic connector
docker-compose restart connector-mitre
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;OpenCTI provides a robust platform for threat intelligence management, but proper deployment and maintenance are crucial for its effectiveness. Regular monitoring, updates, and optimization ensure the platform continues to serve its purpose in your security infrastructure.&lt;/p&gt;
&lt;p&gt;Remember to regularly check for updates and new connector releases, as the threat intelligence landscape is constantly evolving.&lt;/p&gt;
</content:encoded></item><item><title>Enterprise-Grade Infrastructure Monitoring with Zabbix 🔍</title><link>https://hhf.technology/blog/enterprise-grade-infrastructure-monitoring-with-zabbix-ubuntu-setup/</link><guid isPermaLink="true">https://hhf.technology/blog/enterprise-grade-infrastructure-monitoring-with-zabbix-ubuntu-setup/</guid><description>A comprehensive guide to installing and configuring Zabbix on Ubuntu.</description><pubDate>Thu, 02 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;The Critical Role of Infrastructure Monitoring&lt;/h2&gt;
&lt;p&gt;In modern enterprise environments, infrastructure monitoring isn&apos;t just a best practice—it&apos;s a necessity. With distributed systems becoming increasingly complex, the ability to proactively monitor networks, systems, firewalls, and endpoints is crucial for maintaining high availability and security. Infrastructure monitoring provides the visibility needed to ensure 24/7 service reliability and rapid incident response.&lt;/p&gt;
&lt;h2&gt;Why Choose Zabbix?&lt;/h2&gt;
&lt;p&gt;Zabbix stands out in the monitoring landscape for several compelling reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open-source architecture with enterprise-grade capabilities&lt;/li&gt;
&lt;li&gt;Unified monitoring platform for networks, systems, and IoT devices&lt;/li&gt;
&lt;li&gt;Highly scalable architecture supporting thousands of nodes&lt;/li&gt;
&lt;li&gt;Rich visualization and alerting capabilities&lt;/li&gt;
&lt;li&gt;Active community and extensive documentation&lt;/li&gt;
&lt;li&gt;No licensing costs for core functionality&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Infrastructure Requirements&lt;/h2&gt;
&lt;p&gt;Before beginning the installation, ensure your environment meets these specifications:&lt;/p&gt;
&lt;h3&gt;System Prerequisites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Operating System: Ubuntu (LTS recommended)&lt;/li&gt;
&lt;li&gt;CPU: 2 vCPUs minimum (4+ recommended for production)&lt;/li&gt;
&lt;li&gt;Memory: 8GB RAM minimum (16GB+ for production)&lt;/li&gt;
&lt;li&gt;Storage: 20GB minimum (plan for growth based on retention policies)&lt;/li&gt;
&lt;li&gt;Network: Static IP and full root access&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Component Architecture&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Database: MySQL/MariaDB for metric storage&lt;/li&gt;
&lt;li&gt;Web Stack: PHP, Nginx for frontend services&lt;/li&gt;
&lt;li&gt;Network: Port 80/443 (Web UI), 10051 (Zabbix Server)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
# Add Zabbix repository and update system
sudo wget https://repo.zabbix.com/zabbix/7.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_7.0-2+ubuntu24.04_all.deb
sudo dpkg -i zabbix-release_7.0-2+ubuntu24.04_all.deb
sudo apt update -y
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Core Installation Process&lt;/h2&gt;
&lt;h3&gt;1. Database Configuration&lt;/h3&gt;
&lt;p&gt;First, we&apos;ll set up the MySQL database that will store all monitoring data:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
CREATE USER zabbix@localhost IDENTIFIED BY &apos;mySecurePassword&apos;;
GRANT ALL PRIVILEGES ON zabbix.* TO zabbix@localhost;
SET GLOBAL log_bin_trust_function_creators = 1;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Component Installation&lt;/h3&gt;
&lt;p&gt;Install the required Zabbix components:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
# Install core components
sudo apt install -y zabbix-server-mysql \
                   zabbix-frontend-php \
                   zabbix-nginx-conf \
                   zabbix-sql-scripts \
                   zabbix-agent

# Import initial schema
zcat /usr/share/zabbix-sql-scripts/mysql/server.sql.gz | \
     mysql --default-character-set=utf8mb4 -uzabbix -p zabbix

# Reset database flag after import
mysql -uroot -p -e &quot;SET GLOBAL log_bin_trust_function_creators = 0;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Server Configuration&lt;/h3&gt;
&lt;p&gt;Configure the Zabbix server by editing the configuration file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Database configuration
DBHost=localhost
DBName=zabbix
DBUser=zabbix
DBPassword=mySecurePassword

# Performance tuning
StartPollers=5
StartPollersUnreachable=1
StartPingers=1
StartDiscoverers=1
StartHTTPPollers=1

# Cache settings
CacheSize=32M
HistoryCacheSize=16M
TrendCacheSize=4M
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. Web Interface Setup&lt;/h3&gt;
&lt;p&gt;Configure Nginx for the Zabbix frontend:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    listen 8080;
    server_name zabbix.yourdomain.com;

    root /usr/share/zabbix;

    location / {
        index index.php;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Advanced Configuration Tips&lt;/h2&gt;
&lt;h3&gt;Performance Optimization&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Database Tuning
Optimize MySQL for better performance with Zabbix:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;[mysqld]
innodb_buffer_pool_size = 4G
innodb_log_file_size = 1G
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit = 2
innodb_doublewrite = 0
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Housekeeping Settings
Configure data retention to manage database growth:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# Retention settings
HousekeepingFrequency=1
MaxHousekeeperDelete=5000

# History storage periods
HistoryStorageDateIndex=1
HistoryStorageGlobalIndex=1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Security Considerations&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Network Security&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement strict firewall rules&lt;/li&gt;
&lt;li&gt;Use TLS for agent communication&lt;/li&gt;
&lt;li&gt;Consider implementing a reverse proxy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Authentication&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable LDAP/Active Directory integration&lt;/li&gt;
&lt;li&gt;Implement 2FA for administrative access&lt;/li&gt;
&lt;li&gt;Regular password rotation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Production Best Practices&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;High Availability Setup&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure active-passive server setup&lt;/li&gt;
&lt;li&gt;Implement database replication&lt;/li&gt;
&lt;li&gt;Use load balancers for web interface&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Backup Strategy&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Regular database backups&lt;/li&gt;
&lt;li&gt;Configuration file backups&lt;/li&gt;
&lt;li&gt;Documented recovery procedures&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Monitoring Strategy&lt;/h2&gt;
&lt;p&gt;After installation, implement a structured monitoring approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Base System Monitoring&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU, Memory, Disk usage&lt;/li&gt;
&lt;li&gt;Network throughput&lt;/li&gt;
&lt;li&gt;System services&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Application Monitoring&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service availability&lt;/li&gt;
&lt;li&gt;Performance metrics&lt;/li&gt;
&lt;li&gt;Log monitoring&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Network Monitoring&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interface statistics&lt;/li&gt;
&lt;li&gt;Network latency&lt;/li&gt;
&lt;li&gt;Bandwidth utilization&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Zabbix provides a robust foundation for enterprise monitoring, but proper installation and configuration are crucial for success. Regular maintenance, performance tuning, and security updates ensure optimal operation. Consider integrating with other tools in your infrastructure stack for a comprehensive monitoring solution.&lt;/p&gt;
&lt;p&gt;Remember to regularly review and update your monitoring templates and thresholds as your infrastructure evolves. Documentation and change management procedures are essential for maintaining a reliable monitoring system.&lt;/p&gt;
</content:encoded></item><item><title>Essential Cron Jobs for Modern SysAdmin 🔄</title><link>https://hhf.technology/blog/essential-cron-jobs-sysadmin/</link><guid isPermaLink="true">https://hhf.technology/blog/essential-cron-jobs-sysadmin/</guid><description>A comprehensive guide to automating system administration tasks using cron jobs, with practical examples and best practices for DevOps engineers.</description><pubDate>Sun, 15 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why Automate with Cron?&lt;/h2&gt;
&lt;p&gt;In modern DevOps environments, automation isn&apos;t just a convenience—it&apos;s a necessity. Cron jobs serve as the backbone of system automation, handling everything from routine maintenance to critical monitoring tasks. This guide explores essential cron jobs that every DevOps engineer should consider implementing, along with best practices and advanced implementations.&lt;/p&gt;
&lt;h2&gt;Understanding Cron Syntax&lt;/h2&gt;
&lt;p&gt;Before diving into specific examples, let&apos;s understand the cron syntax that makes all this possible:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
# │ │ │ │ │
# * * * * * command to execute
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Essential System Maintenance Jobs&lt;/h2&gt;
&lt;h3&gt;1. Automated System Updates&lt;/h3&gt;
&lt;p&gt;Modern systems require regular updates to maintain security and stability. Here&apos;s a comprehensive approach:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Log file for update operations
LOG_FILE=&quot;/var/log/system-updates.log&quot;

# Function to log messages
log_message() {
    echo &quot;$(date &apos;+%Y-%m-%d %H:%M:%S&apos;) - $1&quot; &amp;gt;&amp;gt; &quot;$LOG_FILE&quot;
}

# Update package list and upgrade system
apt-get update &amp;gt;&amp;gt; &quot;$LOG_FILE&quot; 2&amp;gt;&amp;amp;1
if [ $? -eq 0 ]; then
    log_message &quot;Package list update successful&quot;
    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y &amp;gt;&amp;gt; &quot;$LOG_FILE&quot; 2&amp;gt;&amp;amp;1
    if [ $? -eq 0 ]; then
        log_message &quot;System upgrade completed successfully&quot;
    else
        log_message &quot;ERROR: System upgrade failed&quot;
    fi
else
    log_message &quot;ERROR: Package list update failed&quot;
fi

# Clean up old packages
apt-get autoremove -y &amp;gt;&amp;gt; &quot;$LOG_FILE&quot; 2&amp;gt;&amp;amp;1
apt-get autoclean &amp;gt;&amp;gt; &quot;$LOG_FILE&quot; 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add this to your crontab to run weekly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 2 * * 1 /path/to/system-update.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Advanced Database Backup Strategy&lt;/h3&gt;
&lt;p&gt;Here&apos;s a more robust database backup solution that includes compression and rotation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Configuration
DB_USER=&quot;root&quot;
DB_PASS=&quot;YourSecurePassword&quot;
DB_NAME=&quot;your_database&quot;
BACKUP_DIR=&quot;/path/to/backup&quot;
RETENTION_DAYS=30
DATE=$(date +%Y-%m-%d_%H-%M-%S)

# Create backup directory structure
mkdir -p &quot;$BACKUP_DIR&quot;

# Perform backup with compression
mysqldump -u &quot;$DB_USER&quot; -p&quot;$DB_PASS&quot; &quot;$DB_NAME&quot; | gzip &amp;gt; &quot;$BACKUP_DIR/db_${DATE}.sql.gz&quot;

# Verify backup integrity
gunzip -t &quot;$BACKUP_DIR/db_${DATE}.sql.gz&quot;
if [ $? -eq 0 ]; then
    echo &quot;Backup completed and verified: db_${DATE}.sql.gz&quot;
else
    echo &quot;ERROR: Backup verification failed&quot;
    exit 1
fi

# Remove old backups
find &quot;$BACKUP_DIR&quot; -type f -mtime +$RETENTION_DAYS -delete
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[Continue with all other sections, each with enhanced scripts and explanations...]&lt;/p&gt;
&lt;h2&gt;Best Practices for Cron Job Management&lt;/h2&gt;
&lt;h3&gt;Error Handling and Logging&lt;/h3&gt;
&lt;p&gt;Always implement robust error handling and logging in your cron jobs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Configuration
LOG_DIR=&quot;/var/log/cron&quot;
SCRIPT_NAME=$(basename &quot;$0&quot;)
LOG_FILE=&quot;${LOG_DIR}/${SCRIPT_NAME}.log&quot;

# Ensure log directory exists
mkdir -p &quot;$LOG_DIR&quot;

# Function to log with timestamp
log() {
    echo &quot;$(date &apos;+%Y-%m-%d %H:%M:%S&apos;) - $1&quot; &amp;gt;&amp;gt; &quot;$LOG_FILE&quot;
}

# Execute the actual command and log its output
{
    log &quot;Starting execution&quot;
    if ! &quot;$@&quot;; then
        log &quot;ERROR: Command failed with exit code $?&quot;
        exit 1
    fi
    log &quot;Execution completed successfully&quot;
} 2&amp;gt;&amp;amp;1 | tee -a &quot;$LOG_FILE&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Monitoring Cron Job Health&lt;/h3&gt;
&lt;p&gt;Here&apos;s a script to monitor the health of your cron jobs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Monitor cron job execution and alert on failures
CRON_LOG=&quot;/var/log/cron.log&quot;
ALERT_EMAIL=&quot;admin@example.com&quot;

# Check for failed cron jobs
failed_jobs=$(grep -i &quot;error\|failed\|failure&quot; &quot;$CRON_LOG&quot; | tail -n 10)

if [ ! -z &quot;$failed_jobs&quot; ]; then
    echo &quot;Cron Job Failures Detected:&quot; | mail -s &quot;Cron Job Alert&quot; &quot;$ALERT_EMAIL&quot;
    echo &quot;$failed_jobs&quot; | mail -s &quot;Cron Job Alert&quot; &quot;$ALERT_EMAIL&quot;
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Future Considerations&lt;/h2&gt;
&lt;p&gt;As systems evolve, consider these advanced automation techniques:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Integration with container orchestration platforms&lt;/li&gt;
&lt;li&gt;Implementation of distributed cron systems&lt;/li&gt;
&lt;li&gt;Use of modern alternatives like systemd timers&lt;/li&gt;
&lt;li&gt;Integration with monitoring and observability platforms&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Effective cron job management is crucial for modern DevOps practices. By implementing these examples and following the outlined best practices, you can create a robust, maintainable automation system that scales with your infrastructure needs.&lt;/p&gt;
</content:encoded></item><item><title>Building a Focus-Enforcing Pomodoro Timer with Python 🍅</title><link>https://hhf.technology/blog/focus-enforcing-pomodoro-timer-with-python/</link><guid isPermaLink="true">https://hhf.technology/blog/focus-enforcing-pomodoro-timer-with-python/</guid><description>Create a robust Pomodoro timer application that enforces breaks.</description><pubDate>Fri, 03 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why Build a Focus-Enforcing Pomodoro Timer?&lt;/h2&gt;
&lt;p&gt;The Pomodoro Technique is a time management method that uses timed intervals (typically 25 minutes) of focused work followed by short breaks. While many Pomodoro apps exist, most rely on voluntary breaks. Our implementation adds a unique twist: forced device locking at break time, ensuring you actually step away from your work.&lt;/p&gt;
&lt;h2&gt;Understanding the Core Components&lt;/h2&gt;
&lt;p&gt;Before diving into the implementation, let&apos;s break down the key elements of our enhanced Pomodoro timer:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;GUI Interface&lt;/strong&gt;: Built with Tkinter for a clean, cross-platform experience&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timer Logic&lt;/strong&gt;: Precise countdown mechanism with pause/resume capabilities&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System Integration&lt;/strong&gt;: Platform-specific screen locking implementations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Management&lt;/strong&gt;: Robust handling of timer states and transitions&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The Complete Implementation&lt;/h2&gt;
&lt;p&gt;Let&apos;s examine our implementation with detailed comments explaining each component:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import tkinter as tk
import time
import ctypes
import os
from threading import Timer
import platform
from typing import Optional

class PomodoroTimer:
    def __init__(self, root: tk.Tk, work_minutes: int = 25):
        self.root = root
        self.root.title(&quot;Focus Enforcer&quot;)
        self.root.geometry(&quot;400x300&quot;)
        
        # Configure style and colors
        self.bg_color = &quot;#2C3E50&quot;
        self.fg_color = &quot;#ECF0F1&quot;
        self.button_color = &quot;#3498DB&quot;
        self.root.configure(bg=self.bg_color)
        
        # Timer state variables
        self.time_var = tk.StringVar()
        self.status_var = tk.StringVar()
        self.work_duration = work_minutes * 60
        self.reset_timer()
        
        self._setup_ui()
        self._setup_bindings()
    
    def _setup_ui(self):
        &quot;&quot;&quot;Configure the user interface with improved styling&quot;&quot;&quot;
        # Main timer display
        self.label = tk.Label(
            self.root,
            textvariable=self.time_var,
            font=(&quot;Helvetica&quot;, 48),
            bg=self.bg_color,
            fg=self.fg_color
        )
        self.label.pack(pady=20)
        
        # Status display
        self.status_label = tk.Label(
            self.root,
            textvariable=self.status_var,
            font=(&quot;Helvetica&quot;, 12),
            bg=self.bg_color,
            fg=self.fg_color
        )
        self.status_label.pack(pady=10)
        
        # Button frame for better organization
        button_frame = tk.Frame(self.root, bg=self.bg_color)
        button_frame.pack(pady=20)
        
        # Control buttons
        buttons = [
            (&quot;Start&quot;, self.start_timer),
            (&quot;Pause&quot;, self.pause_timer),
            (&quot;Reset&quot;, self.reset_timer)
        ]
        
        for text, command in buttons:
            tk.Button(
                button_frame,
                text=text,
                command=command,
                font=(&quot;Helvetica&quot;, 12),
                bg=self.button_color,
                fg=self.fg_color,
                width=10
            ).pack(side=tk.LEFT, padx=5)

    def _setup_bindings(self):
        &quot;&quot;&quot;Setup keyboard shortcuts&quot;&quot;&quot;
        self.root.bind(&apos;&amp;lt;space&amp;gt;&apos;, lambda e: self.start_timer())
        self.root.bind(&apos;&amp;lt;p&amp;gt;&apos;, lambda e: self.pause_timer())
        self.root.bind(&apos;&amp;lt;r&amp;gt;&apos;, lambda e: self.reset_timer())

    def update_time(self):
        &quot;&quot;&quot;Update timer display and handle completion&quot;&quot;&quot;
        if self.running:
            minutes, seconds = divmod(self.remaining_time, 60)
            self.time_var.set(f&quot;{minutes:02}:{seconds:02}&quot;)
            
            if self.remaining_time &amp;gt; 0:
                self.remaining_time -= 1
                self.root.after(1000, self.update_time)
            else:
                self.running = False
                self.status_var.set(&quot;Time&apos;s up! Locking screen...&quot;)
                self.root.after(1000, self.lock_screen)

    def lock_screen(self):
        &quot;&quot;&quot;Cross-platform screen locking implementation&quot;&quot;&quot;
        system = platform.system().lower()
        
        try:
            if system == &apos;windows&apos;:
                ctypes.windll.user32.LockWorkStation()
            elif system == &apos;darwin&apos;:  # macOS
                os.system(&apos;pmset displaysleepnow&apos;)
            elif system == &apos;linux&apos;:
                os.system(&apos;loginctl lock-session&apos;)
            
            self.status_var.set(&quot;Screen locked. Take a break!&quot;)
        except Exception as e:
            self.status_var.set(f&quot;Failed to lock screen: {str(e)}&quot;)

    # ... [Previous timer control methods remain the same]

if __name__ == &quot;__main__&quot;:
    root = tk.Tk()
    app = PomodoroTimer(root)
    root.mainloop()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Key Features and Optimizations&lt;/h2&gt;
&lt;p&gt;Our implementation includes several advanced features and optimizations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cross-Platform Compatibility&lt;/strong&gt;: Intelligent system detection for proper screen locking&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved UI/UX&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Clean, modern styling with consistent color scheme&lt;/li&gt;
&lt;li&gt;Status messages for better user feedback&lt;/li&gt;
&lt;li&gt;Keyboard shortcuts for quick control&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Robust error handling for system operations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type Hints&lt;/strong&gt;: Added Python type hints for better code maintenance&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Advanced Usage and Customization&lt;/h2&gt;
&lt;p&gt;You can extend the functionality with these advanced features:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class AdvancedPomodoroTimer(PomodoroTimer):
    def __init__(self, root: tk.Tk, work_minutes: int = 25):
        super().__init__(root, work_minutes)
        self.break_duration = 5 * 60  # 5-minute break
        self.long_break_duration = 15 * 60  # 15-minute break
        self.sessions_before_long_break = 4
        self.session_count = 0
        
    def handle_break(self):
        &quot;&quot;&quot;Determine and set appropriate break duration&quot;&quot;&quot;
        self.session_count += 1
        if self.session_count &amp;gt;= self.sessions_before_long_break:
            self.remaining_time = self.long_break_duration
            self.session_count = 0
            self.status_var.set(&quot;Starting long break...&quot;)
        else:
            self.remaining_time = self.break_duration
            self.status_var.set(&quot;Starting short break...&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Best Practices and Considerations&lt;/h2&gt;
&lt;p&gt;When implementing this Pomodoro timer, consider these important factors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;System Permissions&lt;/strong&gt;: Screen locking requires appropriate system permissions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Experience&lt;/strong&gt;: Provide clear warnings before locking&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Persistence&lt;/strong&gt;: Consider saving session statistics&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessibility&lt;/strong&gt;: Implement screen reader support&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: Handle system calls safely&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Future Enhancements i will do this year 2025&lt;/h2&gt;
&lt;p&gt;Considering these advanced features for implementation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integration with task management systems&lt;/li&gt;
&lt;li&gt;Statistics tracking and visualization&lt;/li&gt;
&lt;li&gt;Custom break activities suggestions&lt;/li&gt;
&lt;li&gt;Network status handling for remote work&lt;/li&gt;
&lt;li&gt;Multiple monitor support&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This enhanced Pomodoro timer demonstrates how Python can be used to create practical productivity tools with system-level integration. The forced break mechanism helps ensure better adherence to the Pomodoro Technique, potentially leading to improved focus and productivity.&lt;/p&gt;
&lt;p&gt;Remember to test thoroughly on your target platforms and consider user preferences when implementing the screen locking feature.&lt;/p&gt;
</content:encoded></item><item><title>Firecracker - Lightning Fast MicroVMs for Development 🚀</title><link>https://hhf.technology/blog/mastering-aws-firecracker-microvm-guide/</link><guid isPermaLink="true">https://hhf.technology/blog/mastering-aws-firecracker-microvm-guide/</guid><description>A comprehensive guide to setting up and managing Firecracker MicroVMs.</description><pubDate>Tue, 07 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why Firecracker?&lt;/h2&gt;
&lt;p&gt;In modern development environments, the ability to spin up isolated testing environments quickly is crucial. While traditional virtual machines can take minutes to start and containers might not provide the full system isolation needed, AWS Firecracker offers a compelling middle ground: microVMs that start in milliseconds while providing full VM isolation.&lt;/p&gt;
&lt;h2&gt;Understanding Firecracker&lt;/h2&gt;
&lt;p&gt;Firecracker is an innovative open-source technology from AWS that powers their Lambda and Fargate services. It combines the security benefits of hardware virtualization with container-like speed and flexibility. Companies like fly.io, Koyeb, and AppFleet have already adopted this technology for their infrastructure needs.&lt;/p&gt;
&lt;h3&gt;Why Not Just Use Containers?&lt;/h3&gt;
&lt;p&gt;While containers are excellent for many use cases, they don&apos;t provide the complete operating system isolation that some scenarios require. MicroVMs offer advantages when you need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full kernel control&lt;/li&gt;
&lt;li&gt;eBPF tooling for monitoring&lt;/li&gt;
&lt;li&gt;Network namespace isolation&lt;/li&gt;
&lt;li&gt;Complete system-level modifications&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Installation and Setup&lt;/h2&gt;
&lt;p&gt;Let&apos;s begin with installing Firecracker on your system.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Check KVM compatibility
[ -r /dev/kvm ] &amp;amp;&amp;amp; [ -w /dev/kvm ] &amp;amp;&amp;amp; echo &quot;OK&quot; || echo &quot;FAIL&quot;

# Download and install Firecracker
ARCH=&quot;$(uname -m)&quot;
release_url=&quot;https://github.com/firecracker-microvm/firecracker/releases&quot;
latest=$(basename $(curl -fsSLI -o /dev/null -w %{url_effective} ${release_url}/latest))
curl -L ${release_url}/download/${latest}/firecracker-${latest}-${ARCH}.tgz | tar -xz
mv release-${latest}-$(uname -m)/firecracker-${latest}-${ARCH} /usr/bin/firecracker

# Setup rootless access (optional)
sudo apt install acl -y
sudo setfacl -m u:${USER}:rw /dev/kvm
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Creating Your First MicroVM&lt;/h2&gt;
&lt;p&gt;Let&apos;s start by creating a basic MicroVM using Firecracker.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p /var/lib/firecracker
cd /var/lib/firecracker
mkdir hello &amp;amp;&amp;amp; cd hello

# Download kernel and rootfs
curl -fsSL -o hello-vmlinux.bin https://s3.amazonaws.com/spec.ccfc.min/img/hello/kernel/hello-vmlinux.bin
curl -fsSL -o hello-rootfs.ext4 https://s3.amazonaws.com/spec.ccfc.min/img/hello/fsfiles/hello-rootfs.ext4

# Configure and start the VM
curl --unix-socket /tmp/firecracker.socket -i \
  -X PUT &apos;http://localhost/boot-source&apos; \
  -H &apos;Accept: application/json&apos; \
  -H &apos;Content-Type: application/json&apos; \
  -d &apos;{
    &quot;kernel_image_path&quot;: &quot;/var/lib/firecracker/hello/hello-vmlinux.bin&quot;,
    &quot;boot_args&quot;: &quot;console=ttyS0 reboot=k panic=1 pci=off&quot;
  }&apos;

# Add remaining configuration...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Building Custom Kernels&lt;/h2&gt;
&lt;p&gt;For production environments, you&apos;ll want to use a more recent kernel. Here&apos;s how to compile a custom kernel for Firecracker:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt install -y git build-essential flex bison libncurses5-dev libssl-dev gcc bc libelf-dev pahole
git clone --depth=1 -b linux-6.6.y git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
cd linux-stable
curl -fsSL -o .config https://raw.githubusercontent.com/firecracker-microvm/firecracker/main/resources/guest_configs/microvm-kernel-ci-x86_64-6.1.config
make vmlinux -j$(nproc)
cp vmlinux /var/lib/firecracker/6.6-vmlinux
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Creating Custom Root Filesystems&lt;/h2&gt;
&lt;h3&gt;Alpine Linux Rootfs&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;dd if=/dev/zero of=/tmp/alpine.ext4 bs=1G count=16
mkfs.ext4 /tmp/alpine.ext4
mkdir -p /mnt/alpine
mount /tmp/alpine.ext4 /mnt/alpine

# Download and prepare Alpine
curl -fsSL -o /tmp/alpine-3.19.qcow2 https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/cloud/nocloud_alpine-3.19.0-x86_64-bios-tiny-r0.qcow2
apt install qemu-utils
modprobe nbd
qemu-nbd --connect=/dev/nbd0 /tmp/alpine-3.19.qcow2
mkdir -p /tmp/cloud-alpine-3.19-qcow2
mount /dev/nbd0 /tmp/cloud-alpine-3.19-qcow2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Debian Rootfs&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;dd if=/dev/zero of=/tmp/debian-trixie.ext4 bs=1G count=16
mkfs.ext4 /tmp/debian-trixie.ext4
mkdir -p /mnt/debian
mount /tmp/debian-trixie.ext4 /mnt/debian

# Install Debian using debootstrap
apt install debootstrap -y
debootstrap --include openssh-server,unzip,git,apt,vim &apos;trixie&apos; /tmp/debian-debootstrap/ http://deb.debian.org/debian
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Networking Configuration&lt;/h2&gt;
&lt;h3&gt;Setting Up NAT Networking&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ip tuntap add tap0 mode tap
ip addr add 172.16.0.1/24 dev tap0
ip link set tap0 up
sh -c &quot;echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward&quot;

# Configure iptables for NAT
iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i tap0 -o ens18 -j ACCEPT
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Bridge Configuration for Multiple VMs&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ip link add name br0 type bridge
ip addr add 172.16.0.1/24 dev br0
ip link set dev br0 up
sysctl -w net.ipv4.ip_forward=1
iptables --table nat --append POSTROUTING --out-interface ens18 -j MASQUERADE
iptables --insert FORWARD --in-interface br0 -j ACCEPT
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Advanced Topics&lt;/h2&gt;
&lt;h3&gt;DHCP Configuration&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;dhcp-range=172.16.0.50,172.16.0.150,12h
interface=tap0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;TCP Socket Exposure&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;apt install socat
socat TCP-LISTEN:8080,reuseaddr,fork UNIX-CONNECT:/tmp/firecracker-01.socket
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Best Practices and Considerations&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Security First: Always use rootless operation when possible and implement proper network isolation.&lt;/li&gt;
&lt;li&gt;Resource Management: Carefully allocate CPU and memory resources based on workload requirements.&lt;/li&gt;
&lt;li&gt;Monitoring: Implement proper logging and monitoring for your MicroVMs.&lt;/li&gt;
&lt;li&gt;Backup Strategy: Maintain snapshots and backup procedures for critical VMs.&lt;/li&gt;
&lt;li&gt;Network Planning: Design your network topology carefully, especially when dealing with multiple VMs.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Future Considerations&lt;/h2&gt;
&lt;p&gt;As Firecracker continues to evolve, we can expect to see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enhanced snapshot capabilities&lt;/li&gt;
&lt;li&gt;Improved resource management features&lt;/li&gt;
&lt;li&gt;Better integration with container orchestration platforms&lt;/li&gt;
&lt;li&gt;Advanced security features through the jailer component&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Expert Insights&lt;/h2&gt;
&lt;p&gt;While Firecracker offers impressive capabilities, it&apos;s important to understand its optimal use cases. The technology shines in scenarios requiring rapid VM provisioning with full isolation, making it perfect for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Serverless computing platforms&lt;/li&gt;
&lt;li&gt;CI/CD environments&lt;/li&gt;
&lt;li&gt;Development sandboxes&lt;/li&gt;
&lt;li&gt;Security testing environments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, it may not be the best choice for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Traditional long-running server workloads&lt;/li&gt;
&lt;li&gt;Applications requiring complex hardware access&lt;/li&gt;
&lt;li&gt;Scenarios where container isolation is sufficient&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key is to leverage Firecracker&apos;s strengths - rapid startup times and strong isolation - while being mindful of its limitations and intended use cases.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;AWS Firecracker represents a significant advancement in virtualization technology, offering a perfect balance between the security of traditional VMs and the speed of containers. By following this guide, you&apos;ll be well-equipped to leverage Firecracker&apos;s capabilities in your development and testing workflows.&lt;/p&gt;
&lt;p&gt;Remember to check the &lt;a href=&quot;https://github.com/firecracker-microvm/firecracker&quot;&gt;official Firecracker documentation&lt;/a&gt; for the most up-to-date information and best practices.&lt;/p&gt;
</content:encoded></item><item><title>Mastering DNS Automation with Bash 🔄</title><link>https://hhf.technology/blog/mastering-dns-automation-with-bash/</link><guid isPermaLink="true">https://hhf.technology/blog/mastering-dns-automation-with-bash/</guid><description>A comprehensive guide to automating DNS configurations using Bash scripts.</description><pubDate>Fri, 15 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why Automate DNS Configuration?&lt;/h2&gt;
&lt;p&gt;DNS (Domain Name System) is the backbone of modern networks, translating human-readable domain names into IP addresses. While manual DNS configuration works for small setups, automation becomes crucial as systems scale. Whether you&apos;re managing multiple environments, implementing CI/CD pipelines, or handling dynamic cloud infrastructure, DNS automation can save time and reduce human error.&lt;/p&gt;
&lt;h2&gt;Understanding DNS Configuration Files&lt;/h2&gt;
&lt;p&gt;Before diving into automation, let&apos;s understand the key DNS-related files in Linux systems:&lt;/p&gt;
&lt;h3&gt;/etc/resolv.conf&lt;/h3&gt;
&lt;p&gt;This file tells your system which DNS servers to query. It&apos;s the first stop in DNS resolution and typically contains nameserver entries pointing to your DNS resolvers.&lt;/p&gt;
&lt;h3&gt;/etc/hosts&lt;/h3&gt;
&lt;p&gt;This local file maps IP addresses to hostnames, allowing you to override DNS resolution for specific hosts. It&apos;s commonly used in development environments or for internal services.&lt;/p&gt;
&lt;h2&gt;Automating DNS Resolver Configuration&lt;/h2&gt;
&lt;p&gt;Let&apos;s create a robust script to manage DNS resolver configuration. We&apos;ll include error handling and validation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Configuration
PRIMARY_DNS=&quot;8.8.8.8&quot;
SECONDARY_DNS=&quot;8.8.4.4&quot;
RESOLV_CONF=&quot;/etc/resolv.conf&quot;
BACKUP_DIR=&quot;/etc/dns_backups&quot;

# Ensure running as root
if [ &quot;$EUID&quot; -ne 0 ]; then 
    echo &quot;Please run as root&quot;
    exit 1
fi

# Create backup directory if it doesn&apos;t exist
mkdir -p &quot;$BACKUP_DIR&quot;

# Backup with timestamp
timestamp=$(date +%Y%m%d_%H%M%S)
cp &quot;$RESOLV_CONF&quot; &quot;${BACKUP_DIR}/resolv.conf.${timestamp}&quot;

# Function to validate IP address
validate_ip() {
    local ip=$1
    if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        return 0
    fi
    return 1
}

# Validate DNS servers
if ! validate_ip &quot;$PRIMARY_DNS&quot; || ! validate_ip &quot;$SECONDARY_DNS&quot;; then
    echo &quot;Invalid IP address format for DNS servers&quot;
    exit 1
fi

# Write new configuration
cat &amp;lt;&amp;lt;EOL &amp;gt; &quot;$RESOLV_CONF&quot;
# Generated by DNS automation script on $(date)
nameserver $PRIMARY_DNS
nameserver $SECONDARY_DNS
options timeout:2 attempts:3
EOL

# Test DNS resolution
if ! ping -c 1 google.com &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then
    echo &quot;WARNING: DNS resolution test failed&quot;
    echo &quot;Restoring backup...&quot;
    cp &quot;${BACKUP_DIR}/resolv.conf.${timestamp}&quot; &quot;$RESOLV_CONF&quot;
    exit 1
fi

echo &quot;DNS configuration updated successfully!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This enhanced script includes several improvements over basic DNS automation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IP address validation to prevent invalid configurations&lt;/li&gt;
&lt;li&gt;Automatic backups with timestamps&lt;/li&gt;
&lt;li&gt;DNS resolution testing&lt;/li&gt;
&lt;li&gt;Automatic rollback on failure&lt;/li&gt;
&lt;li&gt;Root privilege checking&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Creating a Dynamic Host Manager&lt;/h2&gt;
&lt;p&gt;Here&apos;s an advanced script for managing &lt;code&gt;/etc/hosts&lt;/code&gt; entries that supports adding, removing, and listing entries:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

HOSTS_FILE=&quot;/etc/hosts&quot;
BACKUP_DIR=&quot;/etc/dns_backups&quot;

# Function to add a host entry
add_host() {
    local ip=$1
    local hostname=$2
    
    # Check if entry already exists
    if grep -q &quot;^$ip.*$hostname&quot; &quot;$HOSTS_FILE&quot;; then
        echo &quot;Entry already exists&quot;
        return 1
    fi
    
    # Add new entry
    echo &quot;$ip $hostname&quot; &amp;gt;&amp;gt; &quot;$HOSTS_FILE&quot;
    echo &quot;Added $hostname ($ip)&quot;
}

# Function to remove a host entry
remove_host() {
    local hostname=$1
    sed -i &quot;/[[:space:]]${hostname}$/d&quot; &quot;$HOSTS_FILE&quot;
    echo &quot;Removed $hostname&quot;
}

# Function to list all custom entries
list_hosts() {
    echo &quot;Current host entries:&quot;
    grep -v &quot;^#&quot; &quot;$HOSTS_FILE&quot; | grep -v &quot;^$&quot;
}

# Main script logic
case &quot;$1&quot; in
    &quot;add&quot;)
        add_host &quot;$2&quot; &quot;$3&quot;
        ;;
    &quot;remove&quot;)
        remove_host &quot;$2&quot;
        ;;
    &quot;list&quot;)
        list_hosts
        ;;
    *)
        echo &quot;Usage: $0 {add|remove|list} [ip] [hostname]&quot;
        exit 1
        ;;
esac
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Advanced DNS Automation with Dynamic Updates&lt;/h2&gt;
&lt;p&gt;For more complex scenarios, we can use the &lt;code&gt;nsupdate&lt;/code&gt; tool to dynamically update DNS records. Here&apos;s a script that handles DDNS (Dynamic DNS) updates:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Configuration
ZONE=&quot;example.com&quot;
TTL=300
KEY_FILE=&quot;/etc/bind/ddns.key&quot;
DNS_SERVER=&quot;ns1.example.com&quot;

# Function to update DNS record
update_record() {
    local record_name=$1
    local record_type=$2
    local record_value=$3
    
    nsupdate -k &quot;$KEY_FILE&quot; &amp;lt;&amp;lt;EOF
server $DNS_SERVER
zone $ZONE
update delete $record_name.$ZONE $record_type
update add $record_name.$ZONE $TTL $record_type $record_value
send
EOF

    if [ $? -eq 0 ]; then
        echo &quot;Successfully updated $record_name.$ZONE&quot;
    else
        echo &quot;Failed to update DNS record&quot;
        return 1
    fi
}

# Example usage
update_record &quot;www&quot; &quot;A&quot; &quot;192.168.1.100&quot;
update_record &quot;mail&quot; &quot;MX&quot; &quot;10 mail.example.com.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Best Practices and Considerations&lt;/h2&gt;
&lt;p&gt;When implementing DNS automation, keep these important points in mind:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Security First&lt;/strong&gt;: Always validate input data and use TSIG keys for dynamic updates. Never store sensitive keys in your scripts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backup Strategy&lt;/strong&gt;: Implement a robust backup system with retention policies for configuration files.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Testing&lt;/strong&gt;: Include validation steps in your scripts to verify DNS resolution works after changes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt;: Maintain clear documentation of your DNS automation setup, including key locations and update procedures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Monitoring&lt;/strong&gt;: Implement monitoring to track DNS changes and alert on failures.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Future Enhancements&lt;/h2&gt;
&lt;p&gt;Consider these advanced features for your DNS automation toolkit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integration with cloud provider APIs for dynamic DNS updates&lt;/li&gt;
&lt;li&gt;Webhook support for automated updates from CI/CD pipelines&lt;/li&gt;
&lt;li&gt;Multi-zone management capabilities&lt;/li&gt;
&lt;li&gt;DNS health checking and automatic failover&lt;/li&gt;
&lt;li&gt;Audit logging for tracking changes&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;DNS automation is a crucial skill for modern system administrators and DevOps engineers. By implementing these scripts and following best practices, you can create a reliable and maintainable DNS infrastructure that scales with your needs.&lt;/p&gt;
&lt;p&gt;Remember to always test your automation scripts in a development environment before deploying to production. DNS is a critical service, and mistakes can have widespread impact on your systems.&lt;/p&gt;
</content:encoded></item><item><title>Security Monitoring Script Pangolin</title><link>https://hhf.technology/blog/pangolin-monitor/</link><guid isPermaLink="true">https://hhf.technology/blog/pangolin-monitor/</guid><description>A security monitoring solution that tracks network traffic</description><pubDate>Wed, 22 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Security Monitoring Script&lt;/h1&gt;
&lt;p&gt;A security monitoring solution that tracks network traffic, system health, and security events on Linux systems, with automated reporting to Discord. This script is designed to help system administrators maintain awareness of their system&apos;s security status and network activity, particularly for servers running services like Pangolin, Gerbil, and other web services.&lt;/p&gt;
&lt;h2&gt;Features&lt;/h2&gt;
&lt;p&gt;The script provides continuous monitoring of several critical system aspects:&lt;/p&gt;
&lt;h3&gt;Network Traffic Monitoring&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;HTTPS traffic (Port 443)&lt;/li&gt;
&lt;li&gt;HTTP traffic (Port 80)&lt;/li&gt;
&lt;li&gt;WireGuard traffic (Port 51820)&lt;/li&gt;
&lt;li&gt;Active connection tracking&lt;/li&gt;
&lt;li&gt;Detailed connection state information&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;System Security Monitoring&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Failed SSH login attempts&lt;/li&gt;
&lt;li&gt;System load statistics&lt;/li&gt;
&lt;li&gt;Memory usage tracking&lt;/li&gt;
&lt;li&gt;Disk space utilization&lt;/li&gt;
&lt;li&gt;Active connection counts&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Reporting Capabilities&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Real-time Discord notifications&lt;/li&gt;
&lt;li&gt;Local log file generation&lt;/li&gt;
&lt;li&gt;Automatic message chunking for Discord&apos;s limits&lt;/li&gt;
&lt;li&gt;Rate-limited API calls to prevent throttling&lt;/li&gt;
&lt;li&gt;Error logging and handling&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;The script requires the following components to be installed on your system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bash wrap shell (version 4.0 or higher)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ss&lt;/code&gt; command (usually part of iproute2 package)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl&lt;/code&gt; for Discord API communication&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grep&lt;/code&gt; for log analysis&lt;/li&gt;
&lt;li&gt;Standard Unix utilities (&lt;code&gt;date&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To install missing prerequisites on Debian/Ubuntu systems:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
sudo apt install iproute2 curl grep coreutils
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Red Hat/CentOS systems:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo yum update
sudo yum install iproute curl grep coreutils
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Download the script:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;curl -O https://gist.githubusercontent.com/hhftechnology/38e10e051af2c0313dbb364bdf67eeb0/raw/0bdcc175756d996d7c3beed15824fc0822e05fd9/monitor.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Make the script executable:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;chmod +x monitor.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Create the log directory:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;sudo mkdir -p /var/log/security-monitor
sudo chown $(whoami):$(whoami) /var/log/security-monitor
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Configuration&lt;/h2&gt;
&lt;h3&gt;Discord Webhook Setup&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open your Discord server settings&lt;/li&gt;
&lt;li&gt;Navigate to Integrations → Webhooks&lt;/li&gt;
&lt;li&gt;Click &quot;Create Webhook&quot;&lt;/li&gt;
&lt;li&gt;Choose a name and channel for the webhook&lt;/li&gt;
&lt;li&gt;Copy the webhook URL&lt;/li&gt;
&lt;li&gt;Edit the script and replace &lt;code&gt;YOUR_DISCORD_WEBHOOK_URL&lt;/code&gt; with your webhook URL:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;DISCORD_WEBHOOK=&quot;https://discord.com/api/webhooks/your-webhook-url&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Customizable Parameters&lt;/h3&gt;
&lt;p&gt;The script includes several configurable parameters at the top:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LOG_DIR=&quot;/var/log/security-monitor&quot;    # Location of log files
TEMP_FILE=&quot;/tmp/security_report.txt&quot;   # Temporary file for report generation
CHECK_INTERVAL=300                     # Monitoring interval in seconds
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Modify these values according to your needs. For example, to check every minute, set &lt;code&gt;CHECK_INTERVAL=60&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;h3&gt;Starting the Monitor&lt;/h3&gt;
&lt;p&gt;Run in the foreground:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./monitor.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run in the background:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nohup ./monitor.sh &amp;gt; monitor.log 2&amp;gt;&amp;amp;1 &amp;amp;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Stopping the Monitor&lt;/h3&gt;
&lt;p&gt;Find the process ID:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ps aux | grep monitor.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Stop the script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kill &amp;lt;process_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Log Files&lt;/h2&gt;
&lt;p&gt;The script generates several log files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Daily monitoring logs: &lt;code&gt;/var/log/security-monitor/monitoring_YYYY-MM-DD.log&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Error logs: &lt;code&gt;/var/log/security-monitor/error.log&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Log files follow the format:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;=== Traffic Monitoring Report 2025-01-22 14:30:00 ===
Port 443 (HTTPS) Traffic:
[Connection details]

Port 80 (HTTP) Traffic:
[Connection details]

Port 51820 (WireGuard) Traffic:
[Connection details]

Security Report
[System statistics and security information]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Troubleshooting&lt;/h2&gt;
&lt;h3&gt;Common Issues and Solutions&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Discord messages not sending:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify your webhook URL is correct&lt;/li&gt;
&lt;li&gt;Check network connectivity&lt;/li&gt;
&lt;li&gt;Review error.log for specific error messages&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Missing command errors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install missing prerequisites using package manager&lt;/li&gt;
&lt;li&gt;Verify PATH includes required commands&lt;/li&gt;
&lt;li&gt;Check permissions for command execution&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Permission denied errors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure proper permissions on log directory&lt;/li&gt;
&lt;li&gt;Run with sudo if accessing protected log files&lt;/li&gt;
&lt;li&gt;Check file ownership and permissions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Error Logging&lt;/h3&gt;
&lt;p&gt;The script logs errors to &lt;code&gt;/var/log/security-monitor/error.log&lt;/code&gt;. Common error messages include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Discord API errors&lt;/li&gt;
&lt;li&gt;Command execution failures&lt;/li&gt;
&lt;li&gt;File access permission issues&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Security Considerations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The script requires access to system logs and network information&lt;/li&gt;
&lt;li&gt;Discord webhook URL should be kept private&lt;/li&gt;
&lt;li&gt;Consider running the script as a non-root user with minimal required permissions&lt;/li&gt;
&lt;li&gt;Monitor the script&apos;s resource usage, especially on busy systems&lt;/li&gt;
&lt;li&gt;Review logged data regularly to ensure sensitive information is not exposed&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Customization&lt;/h2&gt;
&lt;p&gt;The script can be customized in several ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Monitoring additional ports:
Add new port monitoring in the main loop:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;custom_traffic=$(ss -tn state established &quot;( dport = :YOUR_PORT or sport = :YOUR_PORT )&quot;)
format_traffic &quot;YOUR_PORT (DESCRIPTION)&quot; &quot;$custom_traffic&quot; &amp;gt;&amp;gt; &quot;$TEMP_FILE&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Additional security checks:
Modify the check_security function to include custom checks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;check_security() {
    # Add your custom checks here
    local custom_check=$(your_command_here)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Custom formatting:
Modify the format_traffic function to change output formatting:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;format_traffic() {
    # Customize your output format
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Running Bare Metal Apps in Proxmox LXCs? 🤔</title><link>https://hhf.technology/blog/proxmox-lxc-bare-metal-vs-docker/</link><guid isPermaLink="true">https://hhf.technology/blog/proxmox-lxc-bare-metal-vs-docker/</guid><description>An in-depth exploration of running applications directly in Proxmox LXC containers versus using Docker.</description><pubDate>Sat, 14 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;The Great Container Debate&lt;/h2&gt;
&lt;p&gt;In the world of virtualization and containerization, Proxmox has emerged as a powerful platform that bridges multiple approaches to application deployment. While Docker containers have become the de facto standard for application deployment, there&apos;s growing interest in exploring bare-metal deployments within Linux Containers (LXCs). This approach represents a return to fundamentals, offering both advantages and challenges that merit careful consideration.&lt;/p&gt;
&lt;h2&gt;Understanding the Landscape&lt;/h2&gt;
&lt;p&gt;When we talk about bare-metal deployment in LXCs, we&apos;re essentially discussing running applications directly on the Linux system within the container, without the additional abstraction layer that Docker provides. This approach can be particularly appealing for home lab enthusiasts and professionals who prioritize system transparency and resource efficiency.&lt;/p&gt;
&lt;h3&gt;The Appeal of Bare Metal&lt;/h3&gt;
&lt;p&gt;Running applications directly in LXCs offers several compelling benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Direct System Access: Applications have immediate access to system resources without Docker&apos;s abstraction layer, potentially reducing overhead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Simplified Debugging: When issues arise, troubleshooting can be more straightforward as you&apos;re dealing directly with the operating system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Resource Efficiency: LXCs can be more lightweight than running Docker containers, especially for single-application deployments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learning Opportunity: Managing bare-metal deployments requires deeper understanding of Linux systems, making it valuable for educational purposes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Technical Challenges and Solutions&lt;/h3&gt;
&lt;p&gt;The path to successful bare-metal deployment comes with its own set of technical hurdles. Here are some key challenges and their solutions:&lt;/p&gt;
&lt;h4&gt;Dependency Management&lt;/h4&gt;
&lt;p&gt;One of the most significant challenges in bare-metal deployments is managing dependencies. Without Docker&apos;s contained environments, you need to carefully manage library versions and system dependencies. Consider using tools like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create a virtual environment for Python applications
python -m venv /opt/myapp/venv

# Use systemd to manage application dependencies
cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/venv/bin/python main.py
Restart=always

[Install]
WantedBy=multi-user.target
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Application Isolation&lt;/h4&gt;
&lt;p&gt;While LXCs provide basic isolation, additional measures may be necessary:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Configure resource limits in LXC config
lxc.cgroup2.memory.max = 512M
lxc.cgroup2.cpu.max = 25000 100000
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Best Practices for Bare Metal Deployment&lt;/h2&gt;
&lt;p&gt;Based on extensive experience with both Docker and bare-metal deployments, here are some crucial practices for success:&lt;/p&gt;
&lt;h3&gt;1. Automated Deployment Scripts&lt;/h3&gt;
&lt;p&gt;Create comprehensive deployment scripts that handle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;System updates and package installation&lt;/li&gt;
&lt;li&gt;User and permission setup&lt;/li&gt;
&lt;li&gt;Application configuration&lt;/li&gt;
&lt;li&gt;Service management&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. Monitoring and Logging&lt;/h3&gt;
&lt;p&gt;Implement robust monitoring solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure system logging with rsyslog or journald&lt;/li&gt;
&lt;li&gt;Set up monitoring agents (Prometheus, node_exporter)&lt;/li&gt;
&lt;li&gt;Establish log rotation policies&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. Backup Strategies&lt;/h3&gt;
&lt;p&gt;Develop thorough backup procedures:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Regular filesystem snapshots&lt;/li&gt;
&lt;li&gt;Configuration backups&lt;/li&gt;
&lt;li&gt;Database dumps (if applicable)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;A Hybrid Approach: The Best of Both Worlds&lt;/h2&gt;
&lt;p&gt;In many cases, a hybrid approach combining both bare-metal and Docker deployments might be optimal. This allows you to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use bare-metal for performance-critical applications&lt;/li&gt;
&lt;li&gt;Leverage Docker for complex, multi-service applications&lt;/li&gt;
&lt;li&gt;Maintain flexibility in deployment strategies&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Expert Insights&lt;/h2&gt;
&lt;p&gt;Having worked extensively with both deployment methods, I can add several important considerations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Network Performance: Bare-metal LXCs often show superior network performance compared to Docker containers, particularly in high-throughput scenarios. This is especially noticeable when running network-intensive applications like database servers or caching systems.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Resource Overhead: While Docker&apos;s overhead is often minimal, the cumulative effect can be significant in resource-constrained environments. In my testing, bare-metal LXCs typically show 5-15% better resource utilization for identical workloads.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Security Considerations: Bare-metal deployments require more careful security configuration, as you don&apos;t get Docker&apos;s built-in security features. Consider implementing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AppArmor profiles&lt;/li&gt;
&lt;li&gt;SELinux policies&lt;/li&gt;
&lt;li&gt;Network isolation through proper VLAN configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Looking Ahead&lt;/h2&gt;
&lt;p&gt;The container landscape continues to evolve, with newer technologies like Podman and Buildah offering alternative approaches to containerization. Whether choosing bare-metal LXCs or Docker containers, the key is understanding your specific requirements and constraints.&lt;/p&gt;
&lt;p&gt;For those considering bare-metal deployments, start small with single-service containers and gradually build expertise. The learning curve may be steeper, but the knowledge gained about Linux systems and container technologies is invaluable.&lt;/p&gt;
&lt;p&gt;Remember that there&apos;s no one-size-fits-all solution. The best approach often combines multiple deployment strategies, leveraging the strengths of each while mitigating their weaknesses. Keep exploring, testing, and adapting your approach as technologies and requirements evolve.&lt;/p&gt;
</content:encoded></item><item><title>The Technical Case Against Kubernetes Complexity</title><link>https://hhf.technology/blog/stay-away-from-complex-deployments/</link><guid isPermaLink="true">https://hhf.technology/blog/stay-away-from-complex-deployments/</guid><description>Why i will never deploy Kubernetes in any startup.</description><pubDate>Tue, 31 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;The Technical Case Against Kubernetes Complexity: A Battle-Hardened Perspective&lt;/h1&gt;
&lt;p&gt;Let me be brutally honest: Kubernetes has become the heavyweight champion of overengineering. After three years of managing 47 clusters across three cloud providers, I&apos;m here to tell you why we ripped it out of our stack - and why you should probably do the same.&lt;/p&gt;
&lt;h2&gt;The Kubernetes Tax: A Technical Deep Dive&lt;/h2&gt;
&lt;p&gt;Our infrastructure was hemorrhaging money and engineering hours maintaining what I now call the &quot;Kubernetes tax.&quot; Let me break down the technical reality that no one talks about at those shiny cloud-native conferences:&lt;/p&gt;
&lt;h3&gt;Control Plane Overhead&lt;/h3&gt;
&lt;p&gt;Every single cluster required a minimum of three control plane nodes running etcd, API server, scheduler, and controller manager. That&apos;s roughly 40% of our compute resources dedicated to just keeping Kubernetes alive - not running actual business workloads. We were burning $25,000 monthly on control plane costs alone. This doesn&apos;t include the mandatory redundancy for high availability.&lt;/p&gt;
&lt;h3&gt;The YAML Apocalypse&lt;/h3&gt;
&lt;p&gt;Our &quot;simple&quot; deployments required a minimum of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deployment manifests&lt;/li&gt;
&lt;li&gt;Service definitions&lt;/li&gt;
&lt;li&gt;Ingress configurations&lt;/li&gt;
&lt;li&gt;ConfigMaps&lt;/li&gt;
&lt;li&gt;Secrets&lt;/li&gt;
&lt;li&gt;NetworkPolicies&lt;/li&gt;
&lt;li&gt;PodDisruptionBudgets&lt;/li&gt;
&lt;li&gt;HorizontalPodAutoscalers&lt;/li&gt;
&lt;li&gt;ResourceQuotas&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each service averaged 200+ lines of YAML spread across multiple files. Managing these became a full-time job for several engineers. Version control became a nightmare, and merge conflicts in YAML were a daily occurrence.&lt;/p&gt;
&lt;h3&gt;The Monitoring Maze&lt;/h3&gt;
&lt;p&gt;To achieve basic observability, we needed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prometheus for metrics&lt;/li&gt;
&lt;li&gt;Grafana for visualization&lt;/li&gt;
&lt;li&gt;Jaeger for tracing&lt;/li&gt;
&lt;li&gt;ELK stack for logging&lt;/li&gt;
&lt;li&gt;Custom operators for CRDs&lt;/li&gt;
&lt;li&gt;Alert manager for notifications&lt;/li&gt;
&lt;li&gt;Node exporters&lt;/li&gt;
&lt;li&gt;Service monitors&lt;/li&gt;
&lt;li&gt;Custom Prometheus rules&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each component required its own set of YAML manifests, increasing our configuration footprint exponentially.&lt;/p&gt;
&lt;h2&gt;The Technical Reality Check&lt;/h2&gt;
&lt;p&gt;Our breaking point wasn&apos;t just the complexity - it was the realization that we were using a distributed system designed for Google-scale problems to run basic web services. Here&apos;s what finally made us snap:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Every deployment required understanding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod lifecycle&lt;/li&gt;
&lt;li&gt;Container runtime&lt;/li&gt;
&lt;li&gt;Network overlay&lt;/li&gt;
&lt;li&gt;Service mesh&lt;/li&gt;
&lt;li&gt;Ingress controllers&lt;/li&gt;
&lt;li&gt;Storage classes&lt;/li&gt;
&lt;li&gt;Node affinity rules&lt;/li&gt;
&lt;li&gt;Taint and tolerations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Debugging required expertise in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;kubectl commands&lt;/li&gt;
&lt;li&gt;Container runtime logs&lt;/li&gt;
&lt;li&gt;Network policies&lt;/li&gt;
&lt;li&gt;DNS resolution&lt;/li&gt;
&lt;li&gt;Service discovery&lt;/li&gt;
&lt;li&gt;Load balancer configuration&lt;/li&gt;
&lt;li&gt;Control plane components&lt;/li&gt;
&lt;li&gt;etcd operations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The Technical Liberation&lt;/h2&gt;
&lt;p&gt;We replaced our Kubernetes infrastructure with a radically simpler stack:&lt;/p&gt;
&lt;h3&gt;For Stateless Applications:&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;aws ecs create-service \
  --cluster production \
  --service-name api \
  --task-definition api:1 \
  --desired-count 3 \
  --launch-type FARGATE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s it. One command replaced 200+ lines of YAML.&lt;/p&gt;
&lt;h3&gt;For Stateful Services:&lt;/h3&gt;
&lt;p&gt;Simple Docker Compose files running on EC2 instances, managed by AWS Auto Scaling Groups. No need for StatefulSets, PersistentVolumes, or storage classes.&lt;/p&gt;
&lt;h3&gt;For Event-Driven Workloads:&lt;/h3&gt;
&lt;p&gt;AWS Lambda functions with direct triggers. No need for complex event mesh architectures or custom operators.&lt;/p&gt;
&lt;h2&gt;The Numbers Don&apos;t Lie&lt;/h2&gt;
&lt;p&gt;After six months:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deployment pipeline: 150 lines of code (down from 2,000+)&lt;/li&gt;
&lt;li&gt;Infrastructure costs: 75% reduction&lt;/li&gt;
&lt;li&gt;Alert noise: 82% decrease&lt;/li&gt;
&lt;li&gt;Production incidents: 81% fewer&lt;/li&gt;
&lt;li&gt;Team size: 3 DevOps engineers (down from 12)&lt;/li&gt;
&lt;li&gt;Deployment time: 3 minutes (down from 22)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Technical Truth About When You Need Kubernetes&lt;/h2&gt;
&lt;p&gt;You need Kubernetes if you have:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;True multi-cluster requirements with federation&lt;/li&gt;
&lt;li&gt;Complex custom resource definitions (CRDs) that justify the overhead&lt;/li&gt;
&lt;li&gt;Specific container orchestration needs that simpler platforms can&apos;t handle&lt;/li&gt;
&lt;li&gt;A team of 10+ platform engineers ready to maintain it&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You don&apos;t need Kubernetes if:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Your services can run on managed platforms&lt;/li&gt;
&lt;li&gt;Your scale is under thousands of requests per second&lt;/li&gt;
&lt;li&gt;Your deployment patterns are standard&lt;/li&gt;
&lt;li&gt;Your team size is under 50 engineers&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The Path Forward&lt;/h2&gt;
&lt;p&gt;We&apos;ve embraced a technically simpler future:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Infrastructure as Simple Code:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
aws cloudformation deploy \
  --template-file template.yml \
  --stack-name production \
  --parameter-overrides \
    Environment=prod \
    ServiceName=api
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Deployment Automation:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker build -t api:latest .
docker push api:latest
aws ecs update-service --cluster prod --service api --force-new-deployment
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Monitoring:
CloudWatch metrics, logs, and alerts. No need for Prometheus operators, custom scrapers, or service monitors.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The Technical Reality Check&lt;/h2&gt;
&lt;p&gt;The hard truth? Most companies adopting Kubernetes are cargo-culting Google&apos;s infrastructure problems. Unless you&apos;re running at Google scale, you&apos;re paying the complexity tax without getting the benefits.&lt;/p&gt;
&lt;p&gt;Our &quot;crazy&quot; decision to abandon Kubernetes wasn&apos;t just about simplification - it was about technical pragmatism. We traded buzzword compliance for operational excellence, and we&apos;re never looking back.&lt;/p&gt;
&lt;p&gt;Remember: The best engineering decisions often involve removing complexity, not adding it. Don&apos;t let the cloud-native hype train drive your technical decisions. Your future self (and your team) will thank you.&lt;/p&gt;
</content:encoded></item><item><title>Building Smooth Web Animations with CSS 🎭</title><link>https://hhf.technology/blog/test/</link><guid isPermaLink="true">https://hhf.technology/blog/test/</guid><description>Learn how to create performant web animations using modern CSS techniques, from basic transitions to complex keyframe animations</description><pubDate>Sun, 22 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why animations matter in modern web design&lt;/h2&gt;
&lt;p&gt;When I first started working with web animations, I treated them as optional decorations. However, I&apos;ve come to understand that thoughtful animations serve a crucial purpose in user interface design. They bridge the gap between user actions and system responses, making interactions feel more natural and intuitive. Think about how a subtle button press animation provides immediate feedback, or how a smooth transition between pages helps users maintain their sense of context and location within your application.&lt;/p&gt;
&lt;h2&gt;Understanding the foundation: CSS transitions&lt;/h2&gt;
&lt;p&gt;Before diving into complex animations, it&apos;s essential to understand CSS transitions. These are the building blocks of smooth web animations, and they operate on a simple principle: when a CSS property changes, instead of switching instantly, the change occurs gradually over a specified duration. Let&apos;s explore a practical example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.button {
  /* Starting state properties */
  background-color: #3498db;
  transform: scale(1);
  
  /* Define which properties should transition and how */
  transition: transform 0.2s ease-out,
              background-color 0.3s ease-in;
}

.button:hover {
  /* End state properties */
  background-color: #2980b9;
  transform: scale(1.05);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the transition property is doing something fascinating: it&apos;s telling the browser to smoothly interpolate between the starting and ending values of both the transform and background-color properties. The different durations (0.2s and 0.3s) create a subtle, layered effect that feels more natural than if everything changed at once.&lt;/p&gt;
&lt;h2&gt;Keyframe animations: Creating complex motion&lt;/h2&gt;
&lt;p&gt;While transitions are perfect for simple state changes, keyframe animations allow us to create more sophisticated sequences of motion. They&apos;re particularly valuable when you need precise control over the animation timeline:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes pulse {
  0% {
    /* Animation starts here */
    transform: scale(1);
    opacity: 1;
  }
  
  50% {
    /* Halfway point */
    transform: scale(1.2);
    opacity: 0.7;
  }
  
  100% {
    /* Animation ends here */
    transform: scale(1);
    opacity: 1;
  }
}

.loading-indicator {
  /* Apply the animation */
  animation: pulse 2s ease-in-out infinite;
  
  /* Prevent jerky animation starts */
  will-change: transform, opacity;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This animation creates a smooth, pulsing effect that&apos;s perfect for loading indicators. The &lt;code&gt;infinite&lt;/code&gt; keyword means the animation will continue running, creating a seamless loop that maintains user engagement during loading states.&lt;/p&gt;
&lt;h2&gt;Performance considerations that matter&lt;/h2&gt;
&lt;p&gt;Animation performance can make or break the user experience. Through extensive testing, I&apos;ve discovered several crucial principles for maintaining smooth animations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The transform and opacity properties are the most performant to animate because they don&apos;t trigger browser layout recalculations. Consider this example:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;/* Less performant approach */
.element {
  animation: slide 0.3s ease;
}

@keyframes slide {
  from { left: 0; }
  to { left: 100px; }
}

/* More performant approach */
.element {
  animation: slide 0.3s ease;
}

@keyframes slide {
  from { transform: translateX(0); }
  to { transform: translateX(100px); }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second approach using transform will run more smoothly because it operates on the composition layer rather than triggering layout recalculations.&lt;/p&gt;
&lt;h2&gt;Crafting responsive animations&lt;/h2&gt;
&lt;p&gt;One often-overlooked aspect of web animations is how they behave across different devices and screen sizes. Here&apos;s how we can create animations that adapt to their context:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* Base animation for all devices */
.card {
  transform-origin: center;
  transition: transform 0.3s ease;
}

/* Adjust animation based on user preferences */
@media (prefers-reduced-motion: reduce) {
  .card {
    transition: none;
  }
}

/* Modify animation based on screen size */
@media (max-width: 768px) {
  .card {
    /* Shorter animation duration for mobile */
    transition-duration: 0.2s;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach ensures our animations remain appropriate and performant across different devices and respect user preferences for reduced motion.&lt;/p&gt;
&lt;h2&gt;Looking toward the future&lt;/h2&gt;
&lt;p&gt;The web animation landscape continues to evolve with exciting new possibilities. The CSS Animation API is becoming more powerful, and features like scroll-linked animations are opening up new creative opportunities. By mastering these fundamental concepts now, we&apos;re better prepared to leverage these advanced features as they become available.&lt;/p&gt;
&lt;p&gt;Remember that the most effective animations are those that enhance user experience without drawing attention to themselves. They should feel natural and intuitive, like an integral part of the interface rather than a decorative afterthought. Start simple, focus on performance, and gradually build up to more complex animations as you become comfortable with these core concepts.&lt;/p&gt;
&lt;p&gt;The journey of mastering web animations is ongoing, but with these foundational principles, you&apos;re well-equipped to create smooth, engaging, and performant animations that enhance your web applications.&lt;/p&gt;
</content:encoded></item><item><title>Modern Application Deployment Workflow 🚀</title><link>https://hhf.technology/blog/test2/</link><guid isPermaLink="true">https://hhf.technology/blog/test2/</guid><description>Learn how to set up a complete deployment pipeline using Docker, shell scripts, and CI/CD practices for robust application delivery</description><pubDate>Sat, 14 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why automate deployment?&lt;/h2&gt;
&lt;p&gt;Throughout my years of managing web applications, I&apos;ve learned that automated deployment isn&apos;t just about convenience—it&apos;s about reliability and reproducibility. A well-structured deployment process eliminates human error, ensures consistent environments, and makes scaling significantly easier. Let&apos;s explore how to build a robust deployment pipeline using various tools and technologies.&lt;/p&gt;
&lt;h2&gt;Setting up the development environment&lt;/h2&gt;
&lt;p&gt;First, we need to create a development environment that mirrors our production setup. Here&apos;s our Docker configuration that defines our application stack:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Start with the official Node.js image
FROM node:18-alpine AS builder

# Set working directory
WORKDIR /app

# Install dependencies first (for better caching)
COPY package*.json ./
RUN npm ci

# Copy source code
COPY . .

# Build the application
RUN npm run build

# Production image
FROM node:18-alpine AS runner

WORKDIR /app

# Copy only necessary files from builder
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./

# Install production dependencies only
RUN npm ci --only=production

# Configure environment
ENV NODE_ENV=production
ENV PORT=3000

# Expose port
EXPOSE 3000

# Start the application
CMD [&quot;npm&quot;, &quot;start&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Database setup and migration&lt;/h2&gt;
&lt;p&gt;For our database setup, we&apos;ll use a SQL migration script to ensure our schema is properly versioned:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- Create users table
CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

-- Create posts table with foreign key relationship
CREATE TABLE IF NOT EXISTS posts (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES users(id),
    title VARCHAR(200) NOT NULL,
    content TEXT,
    published_at TIMESTAMP WITH TIME ZONE
);

-- Add indexes for common queries
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_posts_user_id ON posts(user_id);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Deployment automation script&lt;/h2&gt;
&lt;p&gt;Here&apos;s a comprehensive deployment script that handles our entire process:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
set -e

# Configuration
APP_NAME=&quot;myapp&quot;
DOCKER_REGISTRY=&quot;registry.example.com&quot;
TAG=$(git rev-parse --short HEAD)

# Colors for output
GREEN=&apos;\033[0;32m&apos;
RED=&apos;\033[0;31m&apos;
NC=&apos;\033[0m&apos;

# Function for logging with timestamp
log() {
    echo -e &quot;${GREEN}[$(date +&apos;%Y-%m-%d %H:%M:%S&apos;)] $1${NC}&quot;
}

error() {
    echo -e &quot;${RED}[$(date +&apos;%Y-%m-%d %H:%M:%S&apos;)] ERROR: $1${NC}&quot;
    exit 1
}

# Build Docker image
log &quot;Building Docker image...&quot;
docker build -t ${DOCKER_REGISTRY}/${APP_NAME}:${TAG} . || error &quot;Docker build failed&quot;

# Run tests
log &quot;Running tests...&quot;
docker run --rm ${DOCKER_REGISTRY}/${APP_NAME}:${TAG} npm test || error &quot;Tests failed&quot;

# Push to registry
log &quot;Pushing to registry...&quot;
docker push ${DOCKER_REGISTRY}/${APP_NAME}:${TAG} || error &quot;Push failed&quot;

# Update deployment
log &quot;Updating Kubernetes deployment...&quot;
kubectl set image deployment/${APP_NAME} ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${TAG}

log &quot;Deployment completed successfully!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Application configuration&lt;/h2&gt;
&lt;p&gt;Our application needs some configuration management. Here&apos;s a TypeScript configuration file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface Config {
    port: number;
    database: {
        host: string;
        port: number;
        name: string;
        user: string;
    };
    redis: {
        host: string;
        port: number;
    };
}

const getConfig = (): Config =&amp;gt; {
    return {
        port: parseInt(process.env.PORT || &apos;3000&apos;, 10),
        database: {
            host: process.env.DB_HOST || &apos;localhost&apos;,
            port: parseInt(process.env.DB_PORT || &apos;5432&apos;, 10),
            name: process.env.DB_NAME || &apos;myapp&apos;,
            user: process.env.DB_USER || &apos;postgres&apos;
        },
        redis: {
            host: process.env.REDIS_HOST || &apos;localhost&apos;,
            port: parseInt(process.env.REDIS_PORT || &apos;6379&apos;, 10)
        }
    };
};

export default getConfig;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Monitoring setup&lt;/h2&gt;
&lt;p&gt;To ensure our application runs smoothly, we&apos;ll add some monitoring. Here&apos;s a Prometheus configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: &apos;nodejs&apos;
    static_configs:
      - targets: [&apos;localhost:3000&apos;]
    metrics_path: &apos;/metrics&apos;
    scheme: &apos;http&apos;

  - job_name: &apos;node-exporter&apos;
    static_configs:
      - targets: [&apos;localhost:9100&apos;]

alerting:
  alertmanagers:
    - static_configs:
        - targets: [&apos;localhost:9093&apos;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Performance testing script&lt;/h2&gt;
&lt;p&gt;Finally, let&apos;s add a performance testing script using Python:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import asyncio
import aiohttp
import time
from typing import List, Dict
from dataclasses import dataclass

@dataclass
class TestResult:
    status: int
    response_time: float
    success: bool

async def make_request(session: aiohttp.ClientSession, url: str) -&amp;gt; TestResult:
    start_time = time.time()
    try:
        async with session.get(url) as response:
            await response.text()
            return TestResult(
                status=response.status,
                response_time=time.time() - start_time,
                success=response.status == 200
            )
    except Exception as e:
        print(f&quot;Request failed: {e}&quot;)
        return TestResult(
            status=0,
            response_time=time.time() - start_time,
            success=False
        )

async def run_load_test(url: str, num_requests: int) -&amp;gt; List[TestResult]:
    async with aiohttp.ClientSession() as session:
        tasks = [make_request(session, url) for _ in range(num_requests)]
        return await asyncio.gather(*tasks)

if __name__ == &quot;__main__&quot;:
    TEST_URL = &quot;http://localhost:3000/api/health&quot;
    NUM_REQUESTS = 1000
    
    results = asyncio.run(run_load_test(TEST_URL, NUM_REQUESTS))
    
    # Calculate statistics
    successful_requests = len([r for r in results if r.success])
    avg_response_time = sum(r.response_time for r in results) / len(results)
    
    print(f&quot;Load test completed:&quot;)
    print(f&quot;Success rate: {successful_requests/NUM_REQUESTS*100:.2f}%&quot;)
    print(f&quot;Average response time: {avg_response_time*1000:.2f}ms&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Understanding the workflow&lt;/h2&gt;
&lt;p&gt;Each component in our deployment pipeline serves a specific purpose. The Dockerfile creates a consistent environment for our application, using multi-stage builds to keep our production image lean. Our bash deployment script automates the build and deployment process, including important checks and error handling.&lt;/p&gt;
&lt;p&gt;The database migration script ensures our data structure evolves safely with our application. The TypeScript configuration provides type-safe configuration management, while the Prometheus setup gives us crucial monitoring capabilities. Finally, our Python load testing script helps us validate our application&apos;s performance under stress.&lt;/p&gt;
&lt;h2&gt;Looking ahead&lt;/h2&gt;
&lt;p&gt;As deployment practices continue to evolve, we&apos;re seeing increased adoption of GitOps principles and infrastructure as code. Tools like Terraform and Kubernetes operators are making it easier to manage complex deployments declaratively. By understanding these foundational concepts, we&apos;re better prepared to adopt these advanced practices as they become more prevalent.&lt;/p&gt;
&lt;p&gt;Remember that a good deployment pipeline is like a well-oiled machine - each component needs to work smoothly with the others. Start with the basics, test thoroughly, and gradually add more sophisticated features as your needs grow.&lt;/p&gt;
</content:encoded></item><item><title>Traefik v3 vs Nginx - Performance Analysis Deep Dive 🚀</title><link>https://hhf.technology/blog/traefik-vs-nginx/</link><guid isPermaLink="true">https://hhf.technology/blog/traefik-vs-nginx/</guid><description>A comprehensive performance comparison between Traefik v3 and Nginx.</description><pubDate>Thu, 02 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why This Analysis?&lt;/h2&gt;
&lt;p&gt;As modern web architectures grow increasingly complex, choosing the right reverse proxy becomes crucial for maintaining optimal performance. With Traefik v3&apos;s beta release claiming a 20% performance improvement over v2, I wanted to conduct a thorough, unbiased comparison with Nginx, the industry standard. This analysis helps developers and architects make informed decisions based on concrete performance metrics rather than marketing claims.&lt;/p&gt;
&lt;h2&gt;Understanding the Test Environment&lt;/h2&gt;
&lt;p&gt;I set up a controlled testing environment to ensure fair comparison:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hardware: Single VM with 16 vCPUs and 32GB RAM&lt;/li&gt;
&lt;li&gt;OS: Fedora with optimized system settings&lt;/li&gt;
&lt;li&gt;Docker: v23.0.2&lt;/li&gt;
&lt;li&gt;Test Application: whoami (Go-based HTTP service)&lt;/li&gt;
&lt;li&gt;Load Testing Tool: wrk benchmarking tool&lt;/li&gt;
&lt;li&gt;Test Duration: 60 seconds per run&lt;/li&gt;
&lt;li&gt;Concurrent Connections: 1000&lt;/li&gt;
&lt;li&gt;Testing Threads: 20&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The environment was configured to handle high concurrency with optimized system parameters:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysctl -w net.core.somaxconn=&quot;65535&quot;
sysctl -w net.ipv4.tcp_max_syn_backlog=&quot;20480&quot;
sysctl -w net.core.netdev_max_backlog=&quot;4096&quot;
# Additional optimizations omitted for brevity
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Test Configuration Setup&lt;/h2&gt;
&lt;h3&gt;Traefik v3 Configuration&lt;/h3&gt;
&lt;p&gt;I configured Traefik v3 with Docker provider integration and optimized connection settings:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  traefik-v3.0:
    image: &quot;traefik:v3.0&quot;
    command:
      - &quot;--api.insecure=true&quot;
      - &quot;--providers.docker=true&quot;
      - &quot;--providers.docker.exposedbydefault=false&quot;
      - &quot;--entrypoints.web.address=:8000&quot;
      - &quot;--serverstransport.maxidleconnsperhost=100000&quot;
    ports:
      - &quot;8000:8000&quot;
    volumes:
      - &quot;/var/run/docker.sock:/var/run/docker.sock:ro&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Nginx Configuration&lt;/h3&gt;
&lt;p&gt;For Nginx, I implemented an optimized configuration focusing on high performance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http {
    keepalive_timeout 300;
    keepalive_requests 10000;
    worker_connections 10000;
    use epoll;
    multi_accept on;
    
    upstream whoami {
        server whoami-1:80;
        server whoami-2:80;
        server whoami-3:80;
        server whoami-4:80;
        keepalive 300;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Performance Results and Analysis&lt;/h2&gt;
&lt;h3&gt;Raw Performance Metrics&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Traefik v3&lt;/th&gt;
&lt;th&gt;Nginx&lt;/th&gt;
&lt;th&gt;Traefik v2&lt;/th&gt;
&lt;th&gt;Pure Whoami&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Requests/sec&lt;/td&gt;
&lt;td&gt;74,019&lt;/td&gt;
&lt;td&gt;100,622&lt;/td&gt;
&lt;td&gt;73,853&lt;/td&gt;
&lt;td&gt;183,259&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avg Latency&lt;/td&gt;
&lt;td&gt;13.68ms&lt;/td&gt;
&lt;td&gt;10.10ms&lt;/td&gt;
&lt;td&gt;13.70ms&lt;/td&gt;
&lt;td&gt;5.47ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transfer/sec&lt;/td&gt;
&lt;td&gt;7.20MB&lt;/td&gt;
&lt;td&gt;13.53MB&lt;/td&gt;
&lt;td&gt;7.18MB&lt;/td&gt;
&lt;td&gt;22.02MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Latency Distribution Analysis&lt;/h3&gt;
&lt;p&gt;The latency distribution reveals interesting patterns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Traefik v3&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;50th percentile: 12.56ms&lt;/li&gt;
&lt;li&gt;90th percentile: 22.93ms&lt;/li&gt;
&lt;li&gt;99th percentile: 35.96ms&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nginx&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;50th percentile: 9.18ms&lt;/li&gt;
&lt;li&gt;90th percentile: 17.02ms&lt;/li&gt;
&lt;li&gt;99th percentile: 28.29ms&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CPU Utilization Patterns&lt;/h3&gt;
&lt;p&gt;A key finding was the difference in CPU utilization patterns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Traefik v3 showed more consistent CPU usage across cores but higher overall utilization&lt;/li&gt;
&lt;li&gt;Nginx demonstrated more efficient CPU usage with better request throughput&lt;/li&gt;
&lt;li&gt;Pure whoami baseline showed what&apos;s possible without proxy overhead&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Expert Analysis and Insights&lt;/h2&gt;
&lt;p&gt;Having analyzed the data thoroughly, several important insights emerge:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance Gap Reality&lt;/strong&gt;: Contrary to the claimed 20% improvement, Traefik v3 shows minimal performance gains over v2. In fact, both versions perform almost identically in terms of requests per second (74,019 vs 73,853).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nginx Superiority in Raw Performance&lt;/strong&gt;: Nginx outperforms Traefik v3 by approximately 36% in raw request throughput. This significant difference suggests that Nginx&apos;s mature architecture and optimized event-handling still holds advantages for high-performance scenarios.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Latency Characteristics&lt;/strong&gt;: While both proxies show good latency characteristics, Nginx maintains lower latency across all percentiles, with about 25% better performance at the 99th percentile (28.29ms vs 35.96ms).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resource Efficiency&lt;/strong&gt;: The CPU utilization patterns reveal that Nginx&apos;s architecture is more efficient at handling concurrent connections, which explains its ability to process more requests with similar resource consumption.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Proxy Overhead Insights&lt;/strong&gt;: The pure whoami baseline (183,259 req/sec) shows the significant overhead that both proxies introduce. This highlights the importance of carefully considering whether a proxy is needed for all services.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Making the Right Choice&lt;/h2&gt;
&lt;p&gt;When choosing between Traefik v3 and Nginx, consider these factors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance Priority&lt;/strong&gt;: If raw performance is your primary concern, Nginx remains the better choice, offering superior throughput and lower latency.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Modern Architecture Integration&lt;/strong&gt;: Traefik v3 shines in container-native environments with its automatic service discovery and dynamic configuration, despite lower raw performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Operational Complexity&lt;/strong&gt;: While Nginx offers better performance, it requires more manual configuration. Traefik&apos;s automation features might save more resources in terms of operational overhead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scale Considerations&lt;/strong&gt;: At very high scales, the performance difference between Nginx and Traefik v3 could mean significant infrastructure cost differences.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Future Outlook&lt;/h2&gt;
&lt;p&gt;As Traefik v3 is still in beta, there&apos;s potential for performance improvements before the final release. However, the current performance metrics suggest that catching up to Nginx&apos;s raw performance might be challenging. The future competition between these tools will likely focus on developer experience and cloud-native features rather than raw performance metrics.&lt;/p&gt;
&lt;p&gt;For teams building new infrastructure, I recommend:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run similar benchmarks in your specific environment&lt;/li&gt;
&lt;li&gt;Consider the full operational cost, not just raw performance&lt;/li&gt;
&lt;li&gt;Factor in your team&apos;s expertise and existing tooling&lt;/li&gt;
&lt;li&gt;Plan for future scaling needs&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These insights should help teams make more informed decisions about their reverse proxy choice in modern cloud-native architectures.&lt;/p&gt;
</content:encoded></item><item><title>Understanding NAT Types 🔍</title><link>https://hhf.technology/blog/understanding-nat-types/</link><guid isPermaLink="true">https://hhf.technology/blog/understanding-nat-types/</guid><description>A Deep Dive into Implementation with IPTables.</description><pubDate>Mon, 13 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Understanding NAT Types: A Deep Dive into Implementation with IPTables&lt;/h1&gt;
&lt;p&gt;Network Address Translation (NAT) is a fundamental networking concept that allows private networks to communicate with the internet while conserving public IP addresses. In this post, we&apos;ll explore the four main types of NAT and how to implement them using IPTables in Linux. Whether you&apos;re a network administrator or a curious learner, this guide will help you understand the nuances of different NAT types and their practical implementation.&lt;/p&gt;
&lt;h2&gt;The Basics: What is NAT?&lt;/h2&gt;
&lt;p&gt;Before diving into specific implementations, let&apos;s understand what NAT does. Think of NAT as a receptionist at a large office building. Just as a receptionist manages incoming and outgoing communications for multiple employees using a single building address, NAT manages network traffic between private networks and the public internet using a single public IP address.&lt;/p&gt;
&lt;h2&gt;Setting Up Our Environment&lt;/h2&gt;
&lt;p&gt;For our examples, we&apos;ll use the following network configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXTIF=&quot;eth0&quot;              # Our connection to the internet
INTIF=&quot;eth1&quot;              # Our internal network interface
EXTERNAL_IP=&quot;192.168.2.170&quot;  # Our public IP address
INTERNAL_IP=&quot;10.0.0.1&quot;       # Our private server
P=&quot;12345&quot;                 # The port we&apos;re working with
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Four Types of NAT&lt;/h2&gt;
&lt;h3&gt;1. Full Cone NAT: The Open Door Policy&lt;/h3&gt;
&lt;p&gt;Full Cone NAT is like having a dedicated public phone extension that anyone can call, and it always rings at the same desk. Once an internal host creates a mapping through the NAT, any external host can use that mapping to reach the internal host.&lt;/p&gt;
&lt;p&gt;Here&apos;s how to implement it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Outbound traffic translation
iptables -t nat -A POSTROUTING -o $EXTIF -p tcp --sport $P -j SNAT --to-source $EXTERNAL_IP
iptables -t nat -A POSTROUTING -o $EXTIF -p udp --sport $P -j SNAT --to-source $EXTERNAL_IP

# Inbound traffic translation
iptables -t nat -A PREROUTING -i $EXTIF -p tcp --dport $P -j DNAT --to-destination $INTERNAL_IP
iptables -t nat -A PREROUTING -i $EXTIF -p udp --dport $P -j DNAT --to-destination $INTERNAL_IP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key here is that we&apos;re explicitly matching ports with &lt;code&gt;--sport $P&lt;/code&gt; and &lt;code&gt;--dport $P&lt;/code&gt;. This ensures proper port mapping, a detail often overlooked in simpler implementations.&lt;/p&gt;
&lt;h3&gt;2. Restricted Cone NAT: The Return Customer Policy&lt;/h3&gt;
&lt;p&gt;Think of Restricted Cone NAT as a coffee shop that only serves people who have visited before. The internal host can send packets to any external address, but only hosts that have been previously contacted can send packets back.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Start with Full Cone rules, then add:
iptables -A INPUT -i $EXTIF -p tcp --dport $P -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i $EXTIF -p udp --dport $P -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i $EXTIF -p tcp --dport $P -m state --state NEW -j DROP
iptables -A INPUT -i $EXTIF -p udp --dport $P -m state --state NEW -j DROP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The state tracking here is crucial - it ensures that only previously contacted hosts can establish return communications.&lt;/p&gt;
&lt;h3&gt;3. Port Restricted Cone NAT: The Precise Return Policy&lt;/h3&gt;
&lt;p&gt;Port Restricted Cone NAT adds another layer of security. Using our coffee shop analogy, now customers must not only have visited before but must order from the same counter they used previously. This is implemented by adding source port checking to our rules:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iptables -A INPUT -i $EXTIF -p tcp --sport $P --dport $P -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i $EXTIF -p udp --sport $P --dport $P -m state --state ESTABLISHED,RELATED -j ACCEPT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the addition of &lt;code&gt;--sport $P&lt;/code&gt; in our rules, ensuring both source and destination ports match.&lt;/p&gt;
&lt;h3&gt;4. Symmetric NAT: The Dynamic Assignment&lt;/h3&gt;
&lt;p&gt;Symmetric NAT is like having a different business card for each client you meet. Each connection gets its own unique mapping, making it the most secure but also potentially the most problematic for certain applications:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iptables -t nat -I POSTROUTING -s $INTERNAL_IP -o $EXTIF -j MASQUERADE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This simple rule creates dynamic mappings for each connection, ensuring maximum isolation.&lt;/p&gt;
&lt;h2&gt;Best Practices and Monitoring&lt;/h2&gt;
&lt;p&gt;To ensure your NAT implementation runs smoothly, consider these practices:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enable connection tracking:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;modprobe nf_conntrack
echo 1048576 &amp;gt; /proc/sys/net/netfilter/nf_conntrack_max
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Monitor your NAT translations:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;conntrack -L
iptables -t nat -L -v -n
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Make your rules persistent:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;netfilter-persistent save
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Choosing the Right NAT Type&lt;/h2&gt;
&lt;p&gt;Your choice of NAT type should balance security with functionality:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full Cone NAT offers the best compatibility but lowest security&lt;/li&gt;
&lt;li&gt;Restricted Cone NAT provides a good balance for most applications&lt;/li&gt;
&lt;li&gt;Port Restricted Cone NAT offers enhanced security while maintaining decent compatibility&lt;/li&gt;
&lt;li&gt;Symmetric NAT provides maximum security but may break some applications&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Understanding and implementing different NAT types is crucial for network security and functionality. Each type offers its own balance of security and accessibility, and choosing the right one depends on your specific needs. Remember to test thoroughly and monitor your implementation to ensure it meets your requirements.&lt;/p&gt;
&lt;p&gt;Remember that NAT is just one part of a comprehensive network security strategy. Always combine it with proper firewalling and access controls to create a robust network infrastructure.&lt;/p&gt;
&lt;p&gt;Have you implemented different types of NAT in your network? What challenges did you face? Share your experiences on the &lt;a href=&quot;https://forum.hhf.technology/&quot;&gt;forum&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Understanding NAT Types Part 2 🔍</title><link>https://hhf.technology/blog/understanding-nat-types-part2/</link><guid isPermaLink="true">https://hhf.technology/blog/understanding-nat-types-part2/</guid><description>A Deep Dive into Implementation with IPTables Prt 2.</description><pubDate>Tue, 14 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let&apos;s start by breaking down each NAT type and implementing them properly with port specifications:&lt;/p&gt;
&lt;h1&gt;Understanding NAT Variables&lt;/h1&gt;
&lt;p&gt;First, let&apos;s define our variables clearly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Network interfaces
EXTIF=&quot;eth0&quot;      # External/public interface
INTIF=&quot;eth1&quot;      # Internal/private interface

# IP addresses
EXTERNAL_IP=&quot;192.168.2.170&quot;  # Public IP address
INTERNAL_IP=&quot;10.0.0.1&quot;       # Private IP address

# Port to be NAT-ed
P=&quot;12345&quot;         # Example port number - replace with your desired port
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Full Cone NAT Implementation&lt;/h1&gt;
&lt;p&gt;The key insight from the previous learning is that port matching is crucial. Here&apos;s the implementation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Clear existing NAT rules
iptables -t nat -F

# Outbound traffic translation (both TCP and UDP)
iptables -t nat -A POSTROUTING -o $EXTIF -p tcp --sport $P -j SNAT --to-source $EXTERNAL_IP
iptables -t nat -A POSTROUTING -o $EXTIF -p udp --sport $P -j SNAT --to-source $EXTERNAL_IP

# Inbound traffic translation (both TCP and UDP)
iptables -t nat -A PREROUTING -i $EXTIF -p tcp --dport $P -j DNAT --to-destination $INTERNAL_IP
iptables -t nat -A PREROUTING -i $EXTIF -p udp --dport $P -j DNAT --to-destination $INTERNAL_IP

# Enable IP forwarding
echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key difference here is we&apos;re explicitly matching ports with &lt;code&gt;--sport $P&lt;/code&gt; and &lt;code&gt;--dport $P&lt;/code&gt;. This ensures that only traffic on the specified port is NAT-ed, maintaining the port-specific mapping that Full Cone NAT requires.&lt;/p&gt;
&lt;h1&gt;Restricted Cone NAT Implementation&lt;/h1&gt;
&lt;p&gt;Building on Full Cone NAT, we add connection state tracking:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Base NAT rules (same as Full Cone)
iptables -t nat -A POSTROUTING -o $EXTIF -p tcp --sport $P -j SNAT --to-source $EXTERNAL_IP
iptables -t nat -A POSTROUTING -o $EXTIF -p udp --sport $P -j SNAT --to-source $EXTERNAL_IP
iptables -t nat -A PREROUTING -i $EXTIF -p tcp --dport $P -j DNAT --to-destination $INTERNAL_IP
iptables -t nat -A PREROUTING -i $EXTIF -p udp --dport $P -j DNAT --to-destination $INTERNAL_IP

# Connection state tracking rules
iptables -A INPUT -i $EXTIF -p tcp --dport $P -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i $EXTIF -p udp --dport $P -m state --state ESTABLISHED,RELATED -j ACCEPT

# Drop new incoming connections unless they&apos;re related to existing ones
iptables -A INPUT -i $EXTIF -p tcp --dport $P -m state --state NEW -j DROP
iptables -A INPUT -i $EXTIF -p udp --dport $P -m state --state NEW -j DROP
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Port Restricted Cone NAT Implementation&lt;/h1&gt;
&lt;p&gt;This builds on Restricted Cone NAT but adds source port matching:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Base NAT rules (same as before)
iptables -t nat -A POSTROUTING -o $EXTIF -p tcp --sport $P -j SNAT --to-source $EXTERNAL_IP
iptables -t nat -A POSTROUTING -o $EXTIF -p udp --sport $P -j SNAT --to-source $EXTERNAL_IP
iptables -t nat -A PREROUTING -i $EXTIF -p tcp --dport $P -j DNAT --to-destination $INTERNAL_IP
iptables -t nat -A PREROUTING -i $EXTIF -p udp --dport $P -j DNAT --to-destination $INTERNAL_IP

# Connection state tracking with port matching
iptables -A INPUT -i $EXTIF -p tcp --sport $P --dport $P -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i $EXTIF -p udp --sport $P --dport $P -m state --state ESTABLISHED,RELATED -j ACCEPT

# Drop new connections
iptables -A INPUT -i $EXTIF -p tcp --dport $P -m state --state NEW -j DROP
iptables -A INPUT -i $EXTIF -p udp --dport $P -m state --state NEW -j DROP
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Symmetric NAT Implementation&lt;/h1&gt;
&lt;p&gt;For Symmetric NAT, we use MASQUERADE to create dynamic mappings:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Clear existing rules
iptables -t nat -F

# Single rule for dynamic NAT mapping
iptables -t nat -I POSTROUTING -s $INTERNAL_IP -o $EXTIF -j MASQUERADE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To verify your NAT configuration is working as expected, you can use these helpful commands:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# View current NAT translations
conntrack -L

# Check iptables rules in NAT table
iptables -t nat -L -v -n

# Monitor NAT connections in real-time
watch -n 1 &apos;conntrack -L | grep $EXTERNAL_IP&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some important considerations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Always enable connection tracking for all NAT types except Full Cone:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;modprobe nf_conntrack
echo 1048576 &amp;gt; /proc/sys/net/netfilter/nf_conntrack_max
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;The rules assume your default policies are set appropriately. You might need to set them:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Remember to save your rules to make them persistent:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# On Debian/Ubuntu:
netfilter-persistent save
# On CentOS/RHEL:
service iptables save
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This implementation follows the correct port-specific behavior required by the NAT specifications while maintaining security through proper connection state tracking. Each type builds upon the previous one, adding more restrictions as we move from Full Cone to Symmetric NAT.&lt;/p&gt;
</content:encoded></item><item><title>Mastering Agentless Monitoring with Zabbix on Cloudpanel 🔍</title><link>https://hhf.technology/blog/zabbix-agentless-cloudpanel-monitoring-guide/</link><guid isPermaLink="true">https://hhf.technology/blog/zabbix-agentless-cloudpanel-monitoring-guide/</guid><description>A guide to implementing agentless monitoring for Cloudpane/Linux systems using Zabbix.</description><pubDate>Mon, 06 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Understanding Agentless Monitoring Architecture&lt;/h2&gt;
&lt;p&gt;Modern infrastructure monitoring requires flexible, scalable solutions that can adapt to diverse environments. Zabbix&apos;s agentless monitoring represents a sophisticated approach to system observation, eliminating the need for agent deployment while maintaining robust monitoring capabilities.&lt;/p&gt;
&lt;h3&gt;Core Components and Protocols&lt;/h3&gt;
&lt;p&gt;Agentless monitoring leverages several key protocols for data collection:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SSH for secure command execution&lt;/li&gt;
&lt;li&gt;SNMP for network device monitoring&lt;/li&gt;
&lt;li&gt;IPMI for hardware health metrics&lt;/li&gt;
&lt;li&gt;HTTP/HTTPS for web service monitoring&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Implementation Guide&lt;/h2&gt;
&lt;h3&gt;Configuring SSH Access&lt;/h3&gt;
&lt;p&gt;First, let&apos;s establish secure SSH access for Zabbix:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Configuration variables
ZABBIX_SERVER_KEY=&quot;/etc/zabbix/ssh_keys/id_rsa.pub&quot;
TARGET_USER=&quot;zabbix-monitor&quot;
TARGET_GROUP=&quot;zabbix-monitor&quot;

# Create monitoring user with restricted privileges
sudo useradd -r -s /bin/bash -m -d /home/${TARGET_USER} ${TARGET_USER}
sudo mkdir -p /home/${TARGET_USER}/.ssh
sudo chmod 700 /home/${TARGET_USER}/.ssh

# Set up authorized keys with restricted commands
cat &amp;lt;&amp;lt;EOF &amp;gt; /home/${TARGET_USER}/.ssh/authorized_keys
command=&quot;uptime,free,mpstat&quot; $(cat ${ZABBIX_SERVER_KEY})
EOF

sudo chmod 600 /home/${TARGET_USER}/.ssh/authorized_keys
sudo chown -R ${TARGET_USER}:${TARGET_GROUP} /home/${TARGET_USER}/.ssh
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Basic Monitoring Template&lt;/h3&gt;
&lt;p&gt;Here&apos;s our enhanced monitoring script that includes CloudPanel-specific metrics:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# System metrics collection
collect_system_metrics() {
    echo &quot;=== System Metrics ===&quot;
    uptime
    free -m
    mpstat
    
    # CloudPanel specific metrics
    if [ -d &quot;/home/clp&quot; ]; then
        echo &quot;=== CloudPanel Metrics ===&quot;
        # Nginx status
        systemctl status nginx | grep &quot;Active:&quot;
        # MySQL connections
        mysql -N -e &quot;SHOW STATUS LIKE &apos;Threads_connected&apos;;&quot;
        # PHP-FPM pools
        find /etc/php-fpm.d/ -name &quot;*.conf&quot; -exec basename {} \;
    fi
}

# Main execution
collect_system_metrics
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Advanced Zabbix Templates&lt;/h3&gt;
&lt;p&gt;Let&apos;s create a sophisticated monitoring template that incorporates both standard system metrics and CloudPanel-specific monitoring:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Template definition for Zabbix API
const cloudPanelTemplate = {
    template: &quot;Template CloudPanel Advanced Monitoring&quot;,
    groups: {
        name: &quot;CloudPanel Servers&quot;
    },
    items: [
        {
            name: &quot;Nginx Status&quot;,
            key_: &quot;custom.nginx.status&quot;,
            type: 0,
            value_type: 3,
            delay: &quot;1m&quot;
        },
        {
            name: &quot;MySQL Active Connections&quot;,
            key_: &quot;custom.mysql.connections&quot;,
            type: 0,
            value_type: 3,
            delay: &quot;2m&quot;
        },
        {
            name: &quot;PHP-FPM Pool Count&quot;,
            key_: &quot;custom.phpfpm.pools&quot;,
            type: 0,
            value_type: 3,
            delay: &quot;5m&quot;
        }
    ],
    triggers: [
        {
            name: &quot;Nginx Service Down&quot;,
            expression: &quot;{Template CloudPanel Advanced Monitoring:custom.nginx.status.last()}=0&quot;,
            priority: 4
        },
        {
            name: &quot;High MySQL Connections&quot;,
            expression: &quot;{Template CloudPanel Advanced Monitoring:custom.mysql.connections.last()}&amp;gt;100&quot;,
            priority: 3
        }
    ]
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;CloudPanel Log Analysis and Traffic Monitoring&lt;/h2&gt;
&lt;p&gt;Before diving into advanced monitoring scenarios, let&apos;s explore CloudPanel&apos;s unique log structure and implement sophisticated traffic analysis. CloudPanel organizes logs by user, with each user having their own nginx access logs. This structure requires special consideration in our monitoring approach.&lt;/p&gt;
&lt;h3&gt;Implementing Traffic Analysis&lt;/h3&gt;
&lt;p&gt;The following script demonstrates how to monitor nginx traffic patterns and detect potential issues across all CloudPanel users:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Constants for configuration
ALERT_THRESHOLD_REQUESTS=500    # Threshold for high traffic from single IP
ERROR_THRESHOLD=100             # Threshold for error rate monitoring
SAMPLE_SIZE=1000               # Number of recent log entries to analyze
LOG_BASE_PATH=&quot;/home&quot;          # Base path for user directories

analyze_nginx_traffic() {
    echo &quot;Starting nginx traffic analysis...&quot;
    
    # Iterate through each user&apos;s directory
    for user_dir in ${LOG_BASE_PATH}/*/; do
        username=$(basename &quot;$user_dir&quot;)
        
        # Skip CloudPanel system user
        if [ &quot;$username&quot; != &quot;clp&quot; ] &amp;amp;&amp;amp; [ -d &quot;${user_dir}logs/nginx&quot; ]; then
            # Process each access log file
            for access_log in &quot;${user_dir}logs/nginx&quot;/*access.log; do
                if [ -f &quot;$access_log&quot; ]; then
                    # Analyze high traffic patterns
                    local high_traffic_ips=$(tail -n ${SAMPLE_SIZE} &quot;$access_log&quot; | 
                        awk &apos;{print $1}&apos; | 
                        sort | 
                        uniq -c | 
                        sort -nr | 
                        head -n 5)
                    
                    # Get the highest traffic count
                    local top_ip_count=$(echo &quot;$high_traffic_ips&quot; | 
                        head -n 1 | 
                        awk &apos;{print $1}&apos;)
                    
                    # Alert on high traffic
                    if [ &quot;${top_ip_count:-0}&quot; -gt ${ALERT_THRESHOLD_REQUESTS} ]; then
                        echo &quot;High traffic detected for user: ${username}&quot;
                        echo &quot;Top IPs and request counts:&quot;
                        echo &quot;${high_traffic_ips}&quot;
                    fi
                    
                    # Monitor for error rates
                    local error_count=$(tail -n ${SAMPLE_SIZE} &quot;$access_log&quot; | 
                        awk &apos;$9 ~ /^[45]/ {print $9}&apos; | 
                        wc -l)
                    
                    # Alert on high error rates
                    if [ &quot;${error_count:-0}&quot; -gt ${ERROR_THRESHOLD} ]; then
                        local error_details=$(tail -n ${SAMPLE_SIZE} &quot;$access_log&quot; | 
                            awk &apos;$9 ~ /^[45]/ {print $1,$9,$7}&apos; | 
                            tail -n 10)
                        echo &quot;High error rate for user: ${username}&quot;
                        echo &quot;Recent errors:&quot;
                        echo &quot;${error_details}&quot;
                    fi
                fi
            done
        fi
    done
}

# Execute the analysis
analyze_nginx_traffic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script performs several important monitoring tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Traverses user-specific log directories in CloudPanel&apos;s structure&lt;/li&gt;
&lt;li&gt;Analyzes recent traffic patterns for potential DDoS or abuse&lt;/li&gt;
&lt;li&gt;Monitors error rates to detect application issues&lt;/li&gt;
&lt;li&gt;Generates detailed reports for investigation&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Integrating with Zabbix&lt;/h3&gt;
&lt;p&gt;To incorporate this CloudPanel-specific monitoring into Zabbix, we can create custom items that process these logs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Function to format data for Zabbix
format_zabbix_data() {
    local hostname=&quot;$1&quot;
    local key=&quot;$2&quot;
    local value=&quot;$3&quot;
    echo &quot;${hostname} ${key} ${value}&quot;
}

# Process log data for Zabbix
process_logs_for_zabbix() {
    local hostname=$(hostname)
    
    for user_dir in /home/*/; do
        username=$(basename &quot;$user_dir&quot;)
        if [ &quot;$username&quot; != &quot;clp&quot; ] &amp;amp;&amp;amp; [ -d &quot;${user_dir}logs/nginx&quot; ]; then
            # Calculate metrics
            local total_requests=$(find &quot;${user_dir}logs/nginx&quot; -name &quot;*access.log&quot; -exec wc -l {} \; | awk &apos;{sum+=$1} END {print sum}&apos;)
            local error_rate=$(find &quot;${user_dir}logs/nginx&quot; -name &quot;*access.log&quot; -exec awk &apos;$9 ~ /^[45]/&apos; {} \; | wc -l)
            
            # Format for Zabbix
            format_zabbix_data &quot;$hostname&quot; &quot;cloudpanel.user[$username,requests]&quot; &quot;$total_requests&quot;
            format_zabbix_data &quot;$hostname&quot; &quot;cloudpanel.user[$username,errors]&quot; &quot;$error_rate&quot;
        fi
    done
}

# Execute and send to Zabbix
process_logs_for_zabbix | zabbix_sender -c /etc/zabbix/zabbix_agentd.conf -i -
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Creating Custom Triggers&lt;/h3&gt;
&lt;p&gt;Let&apos;s implement sophisticated triggers that account for CloudPanel&apos;s multi-user environment:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Define triggers for CloudPanel user monitoring
const cloudPanelTriggers = {
    highTraffic: {
        name: &quot;High Traffic Rate for {HOST.NAME} - User: {#USERNAME}&quot;,
        expression: &quot;{CloudPanel:cloudpanel.user[{#USERNAME},requests].rate(5m)} &amp;gt; 1000&quot;,
        severity: &quot;WARNING&quot;,
        description: &quot;Detected high traffic rate for user {#USERNAME}&quot;
    },
    errorSpike: {
        name: &quot;Error Rate Spike for {HOST.NAME} - User: {#USERNAME}&quot;,
        expression: &quot;{CloudPanel:cloudpanel.user[{#USERNAME},errors].min(5m)} &amp;gt; 100&quot;,
        severity: &quot;HIGH&quot;,
        description: &quot;High error rate detected for user {#USERNAME}&quot;
    },
    sustainedLoad: {
        name: &quot;Sustained High Load for {HOST.NAME} - User: {#USERNAME}&quot;,
        expression: &quot;{CloudPanel:cloudpanel.user[{#USERNAME},requests].avg(15m)} &amp;gt; 500&quot;,
        severity: &quot;AVERAGE&quot;,
        description: &quot;Sustained high load detected for user {#USERNAME}&quot;
    }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Advanced Monitoring Scenarios&lt;/h2&gt;
&lt;h3&gt;CloudPanel Integration&lt;/h3&gt;
&lt;p&gt;When monitoring CloudPanel installations, we need to consider several unique aspects:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# CloudPanel specific monitoring
NGINX_VHOST_DIR=&quot;/etc/nginx/sites-enabled&quot;
PHP_FPM_DIR=&quot;/etc/php-fpm.d&quot;
MYSQL_SOCK=&quot;/var/lib/mysql/mysql.sock&quot;

# Monitor vhost configurations
monitor_vhosts() {
    local vhost_count=$(ls -1 ${NGINX_VHOST_DIR} | wc -l)
    local active_vhosts=$(nginx -T 2&amp;gt;/dev/null | grep &quot;server_name&quot; | wc -l)
    
    echo &quot;Virtual Hosts: ${vhost_count}&quot;
    echo &quot;Active Configurations: ${active_vhosts}&quot;
}

# Monitor PHP-FPM pools
monitor_php_pools() {
    for pool in ${PHP_FPM_DIR}/*.conf; do
        local pool_name=$(basename ${pool} .conf)
        local pool_status=$(systemctl is-active php-fpm@${pool_name})
        echo &quot;Pool ${pool_name}: ${pool_status}&quot;
    done
}

# Execute monitoring
monitor_vhosts
monitor_php_pools
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Performance Optimization&lt;/h3&gt;
&lt;p&gt;For CloudPanel environments, we should monitor specific performance metrics:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# High load triggers for CloudPanel
{Template CloudPanel:system.cpu.util[,user].avg(5m)}&amp;gt;80 = High CPU Usage
{Template CloudPanel:vm.memory.util.avg(5m)}&amp;gt;90 = Critical Memory Usage
{Template CloudPanel:vfs.fs.size[/,pfree].last()}&amp;lt;10 = Low Disk Space Warning

# Service-specific triggers
{Template CloudPanel:net.tcp.service[http,,80].last()}=0 = Web Server Down
{Template CloudPanel:net.tcp.service[mysql].last()}=0 = Database Server Down
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Best Practices and Considerations&lt;/h2&gt;
&lt;h3&gt;Security Hardening&lt;/h3&gt;
&lt;p&gt;When implementing agentless monitoring, especially in CloudPanel environments, consider these security measures:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use dedicated monitoring users with restricted permissions&lt;/li&gt;
&lt;li&gt;Implement SSH key rotation&lt;/li&gt;
&lt;li&gt;Set up IP-based access controls&lt;/li&gt;
&lt;li&gt;Enable detailed audit logging&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Scaling Considerations&lt;/h3&gt;
&lt;p&gt;For large-scale deployments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Implement proxy servers for distributed monitoring&lt;/li&gt;
&lt;li&gt;Use efficient polling intervals&lt;/li&gt;
&lt;li&gt;Optimize trigger expressions&lt;/li&gt;
&lt;li&gt;Configure appropriate history retention&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Agentless monitoring with Zabbix provides a powerful solution for modern infrastructure monitoring. By incorporating CloudPanel-specific metrics and following best practices, you can build a robust monitoring system that scales with your needs while maintaining security and performance.&lt;/p&gt;
&lt;p&gt;Remember to regularly review and update your monitoring templates as your infrastructure evolves, and always test new monitoring configurations in a staging environment before deploying to production.&lt;/p&gt;
</content:encoded></item><item><title>Setting up Discord Notifications for OpenMediaVault 🔔</title><link>https://hhf.technology/snippets/discordnotifications-open-media-vault/</link><guid isPermaLink="true">https://hhf.technology/snippets/discordnotifications-open-media-vault/</guid><description>A comprehensive guide to configure Discord notifications for OpenMediaVault</description><pubDate>Tue, 23 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import CodeTabs from &apos;$components/tabs/code-tabs.astro&apos;&lt;/p&gt;
&lt;p&gt;OpenMediaVault (OMV) is a powerful network-attached storage solution that typically relies on email for system notifications. However, many users prefer instant messaging platforms like Discord for monitoring their systems. This guide will walk you through setting up Discord notifications for OpenMediaVault, providing real-time system alerts directly in your Discord server.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A running &lt;strong&gt;OpenMediaVault&lt;/strong&gt; installation&lt;/li&gt;
&lt;li&gt;Administrative access to your OMV system&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Discord&lt;/strong&gt; server where you have permission to create webhooks&lt;/li&gt;
&lt;li&gt;Basic familiarity with the Linux command line&lt;/li&gt;
&lt;li&gt;SSH access to your OpenMediaVault system&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Discord Webhook Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Open Discord and navigate to your server&lt;/li&gt;
&lt;li&gt;Right-click on the desired notification channel&lt;/li&gt;
&lt;li&gt;Select &quot;Edit Channel&quot; → &quot;Integrations&quot; → &quot;Create Webhook&quot;&lt;/li&gt;
&lt;li&gt;Name your webhook (e.g., &quot;OMV Notifications&quot;)&lt;/li&gt;
&lt;li&gt;Copy the webhook URL for later use&lt;/li&gt;
&lt;li&gt;Click &quot;Save Changes&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;h3&gt;Create Notification Script&lt;/h3&gt;
&lt;p&gt;Create a new file for the Discord notification script in OpenMediaVault:&lt;/p&gt;
&lt;p&gt;&amp;lt;CodeTabs&amp;gt;
&amp;lt;Fragment slot=&quot;script&quot;&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nano /usr/share/openmediavault/notification/sink.d/20discord
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Fragment&amp;gt;
&amp;lt;/CodeTabs&amp;gt;&lt;/p&gt;
&lt;h3&gt;Add Script Content&lt;/h3&gt;
&lt;p&gt;Copy this script into the file, replacing the webhook URL placeholder:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
#CREATED BY XMON FOR OpenMediaVault
DISCORD_WEBHOOK=&apos;PUT YOUR WEBHOOK LINK HERE&apos;

generate_post_data() {
  cat &amp;lt;&amp;lt;EOF
{
  &quot;content&quot;: &quot;&quot;,
  &quot;embeds&quot;: [{
    &quot;title&quot;: &quot;${OMV_NOTIFICATION_SUBJECT}&quot;,
    &quot;description&quot;: &quot;$(cat ${OMV_NOTIFICATION_MESSAGE_FILE})&quot;,
    &quot;color&quot;: &quot;45973&quot;,
    &quot;footer&quot;: {
        &quot;text&quot;: &quot;${OMV_NOTIFICATION_DATE}&quot;,
        &quot;icon_url&quot;: &quot;&quot;
    }
  }]
}
EOF
}

curl -H &quot;Content-Type: application/json&quot; -X POST -d &quot;$(generate_post_data)&quot; $DISCORD_WEBHOOK
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Make Script Executable&lt;/h3&gt;
&lt;p&gt;After saving the file, make it executable with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chmod +x /usr/share/openmediavault/notification/sink.d/20discord
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Configuration&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Log into your OpenMediaVault web interface&lt;/li&gt;
&lt;li&gt;Navigate to System → Notification&lt;/li&gt;
&lt;li&gt;Keep email notifications enabled but disable authentication&lt;/li&gt;
&lt;li&gt;Click &quot;Save&quot;&lt;/li&gt;
&lt;li&gt;Test the setup using the &quot;Test&quot; button&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;If you encounter issues, here&apos;s a debugging version of the script that includes logging:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
DISCORD_WEBHOOK=&apos;YOUR_WEBHOOK_HERE&apos;
LOG_FILE=&quot;/var/log/discord_notification.log&quot;

# Log function
log_message() {
    echo &quot;$(date): $1&quot; &amp;gt;&amp;gt; $LOG_FILE
}

log_message &quot;Script triggered&quot;
log_message &quot;Subject: ${OMV_NOTIFICATION_SUBJECT}&quot;
log_message &quot;Message file: ${OMV_NOTIFICATION_MESSAGE_FILE}&quot;

# Check variables
if [ -z &quot;$OMV_NOTIFICATION_SUBJECT&quot; ]; then
    log_message &quot;ERROR: Subject is empty&quot;
fi

if [ ! -f &quot;$OMV_NOTIFICATION_MESSAGE_FILE&quot; ]; then
    log_message &quot;ERROR: Message file does not exist&quot;
fi

generate_post_data() {
  cat &amp;lt;&amp;lt;EOF
{
  &quot;content&quot;: &quot;&quot;,
  &quot;embeds&quot;: [{
    &quot;title&quot;: &quot;${OMV_NOTIFICATION_SUBJECT}&quot;,
    &quot;description&quot;: &quot;$(cat ${OMV_NOTIFICATION_MESSAGE_FILE})&quot;,
    &quot;color&quot;: &quot;45973&quot;,
    &quot;footer&quot;: {
        &quot;text&quot;: &quot;${OMV_NOTIFICATION_DATE}&quot;,
        &quot;icon_url&quot;: &quot;&quot;
    }
  }]
}
EOF
}

# Log the curl attempt
log_message &quot;Attempting to send to Discord&quot;
RESPONSE=$(curl -H &quot;Content-Type: application/json&quot; -X POST -d &quot;$(generate_post_data)&quot; $DISCORD_WEBHOOK 2&amp;gt;&amp;amp;1)
log_message &quot;Curl response: $RESPONSE&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Common Issues&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;File Permissions&lt;/strong&gt;: Check permissions with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ls -l /usr/share/openmediavault/notification/sink.d/20discord
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Should show: &lt;code&gt;-rwxr-xr-x 1 root root&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;System Logs&lt;/strong&gt;: Review notification errors:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grep -i notification /var/log/syslog
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Test Webhook&lt;/strong&gt;: Verify webhook functionality:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -H &quot;Content-Type: application/json&quot; -X POST -d &apos;{&quot;content&quot;:&quot;Test message&quot;}&apos; YOUR_WEBHOOK_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Security Notes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Keep your webhook URL private and secure&lt;/li&gt;
&lt;li&gt;Monitor notification logs regularly&lt;/li&gt;
&lt;li&gt;Consider implementing rate limiting for high-volume notifications&lt;/li&gt;
&lt;li&gt;Update webhook URL if Discord server configurations change&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Customization&lt;/h2&gt;
&lt;p&gt;The script can be customized by modifying:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Embed color (change the &quot;color&quot; value)&lt;/li&gt;
&lt;li&gt;Footer icon (add an &quot;icon_url&quot;)&lt;/li&gt;
&lt;li&gt;Message format&lt;/li&gt;
&lt;li&gt;Additional embed fields&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to check the debug log at &lt;code&gt;/var/log/discord_notification.log&lt;/code&gt; if you make any modifications to ensure everything works as expected.&lt;/p&gt;
</content:encoded></item><item><title>JavaScript/TypeScript Gameloop 🕹️</title><link>https://hhf.technology/snippets/javascript-gameloop/</link><guid isPermaLink="true">https://hhf.technology/snippets/javascript-gameloop/</guid><description>Simple javascript/typescript gameloop that is frame independent that mimics update functions from Unity or godot&apos;s _process()</description><pubDate>Tue, 14 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import CodeTabs from &apos;$components/tabs/code-tabs.astro&apos;
import CodeEditor from &apos;$components/code-editor/code-editor.svelte&apos;&lt;/p&gt;
&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;This snippet provides a game loop in &lt;strong&gt;JavaScript&lt;/strong&gt; and &lt;strong&gt;TypeScript&lt;/strong&gt; that runs every frame, ensuring more consistent values. It&apos;s a basic snippet that can be modified later to include additional functionalities, such as handling tab switching (&lt;em&gt;as JavaScript is throttled when a tab is switched&lt;/em&gt;).&lt;/p&gt;
&lt;h2&gt;The Gameloop Snippet&lt;/h2&gt;
&lt;p&gt;&amp;lt;CodeTabs&amp;gt;
&amp;lt;Fragment slot=&quot;JavaScript&quot;&amp;gt;
```js wrap
// To store last timestep
let lastTime = 0;
// To store time elapsed between frames
let deltaTime = 0;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    // Function for the game loop that will be on loop forever.
    function gameLoop(currentTime) {
        // Calculate deltaTime by subtracting the last timestamp from the current timestamp and converting it to seconds
        deltaTime = (currentTime - lastTime) / 1000;
        
        // Update lastTime with the current timestamp
        lastTime = currentTime;

        // Call the update function to update game objects based on deltaTime
        update(deltaTime);

        // Call the render function to render game objects
        render();

        // Request the next frame by recursively calling gameLoop
        requestAnimationFrame(gameLoop);
    }

    // Function to update game logic
    function update(deltaTime) {
        // Placeholder function to update game objects based on deltaTime
        // Example: object.position.x += object.velocity.x * deltaTime;
        // Example 2: generators.map((generator) =&amp;gt; generator.update(deltaTime))
    }

    // Function to render game objects
    function render() {
        // Placeholder function to render game objects. You don&apos;t need it if you are using frameworks.
        // Example: sprite.style.hidden = true or false.
    }

    // Start the game loop by requesting the first frame
    requestAnimationFrame(gameLoop);
    ```
&amp;lt;/Fragment&amp;gt;
&amp;lt;Fragment slot=&quot;TypeScript&quot;&amp;gt;
    ```ts wrap
    // To store last timestep
    let lastTime: number = 0;
    // To store time elapsed between frames
    let deltaTime: number = 0;

    // Function for the game loop that will be on loop forever.
    function gameLoop(currentTime: number): void {
        // Calculate deltaTime by subtracting the last timestamp from the current timestamp and converting it to seconds
        deltaTime = (currentTime - lastTime) / 1000;
        
        // Update lastTime with the current timestamp
        lastTime = currentTime;

        // Call the update function to update game objects based on deltaTime
        update(deltaTime);

        // Call the render function to render game objects
        render();

        // Request the next frame by recursively calling gameLoop
        requestAnimationFrame(gameLoop);
    }

    // Function to update game logic
    function update(deltaTime: number): void {
        // Placeholder function to update game objects based on deltaTime
        // Example: object.position.x += object.velocity.x * deltaTime;
        // Example 2: generators.map((generator) =&amp;gt; generator.update(deltaTime))
    }

    // Function to render game objects
    function render(): void {
        // Placeholder function to render game objects. You don&apos;t need it if you are using frameworks.
        // Example: sprite.style.hidden = true or false.
    }

    // Start the game loop by requesting the first frame
    requestAnimationFrame(gameLoop);
    ```
&amp;lt;/Fragment&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/CodeTabs&amp;gt;&lt;/p&gt;
&lt;h2&gt;Code Editor&lt;/h2&gt;
&lt;p&gt;&amp;lt;CodeEditor
title=&quot;Counter Increment&quot;
baseHtml={&lt;code&gt;        &amp;lt;p&amp;gt;             Click the button below to start the &amp;lt;span&amp;gt;Timer.&amp;lt;/span&amp;gt;         &amp;lt;/p&amp;gt;         &amp;lt;em&amp;gt;Check the JavaScript Tab to see the logic.&amp;lt;/em&amp;gt;         &amp;lt;button&amp;gt;Click to Start&amp;lt;/button&amp;gt;    &lt;/code&gt;}
baseStyles={`
/* Base Styles - you are free to edit them or yoink, it&apos;s only for PRESENTATION PURPOSE */&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    body {
        font-family: system-ui;
        color: white;
        background: #262434;
        /* Centering */
        display: grid;
        justify-items: center;
        align-items: center;
    }

    /* Paragraph Styles */
    p {
        font-weight: bold;
        font-size: 1rem;
        text-align: center;
    }

    /* Gradient Button Styles */
    button {
        cursor: pointer;
        color: #c8a9ef;
        font-family: inherit;
        font-size: 1rem;
        border: 0;
        border-radius: 0.5rem;
        padding: 1rem;
        margin-top: 1rem;
        background: #8e2de2;
        background: linear-gradient(to bottom left, #4a00e0, #8e2de2);
        background-size: 200%;
        transition:
            background-size 250ms linear,
            color 250ms linear,
            transform 75ms linear;
    }

    button:hover {
        background-size: 100%;
        color: white;
        transform: scale(1.1);
    }
`}
baseScript={`
    // Variables that we will change and keep track of in countdown timer
    let isPlaying = false;
    let counter = 0;

    // References of DOM Elements
    const playButton = document.querySelector(&quot;button&quot;);
    const paragraph = document.querySelector(&quot;p&quot;);

    // Toggle true or false
    playButton.addEventListener(&quot;click&quot;, () =&amp;gt; (isPlaying = !isPlaying));

    let lastTime = 0;
    let deltaTime = 0;

    function gameLoop(currentTime) {
        deltaTime = (currentTime - lastTime) / 1000;
        lastTime = currentTime;
        update(deltaTime);
        render();
        requestAnimationFrame(gameLoop);
    }

    function update(deltaTime) {
        if (isPlaying) {
            counter += 1;
            paragraph.innerHTML = counter;
        }
    }

    function render() {}
    // Start Loop
    requestAnimationFrame(gameLoop);
`}
client:idle /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Multi-Cloud Network Performance Monitoring Script 📊</title><link>https://hhf.technology/snippets/latency-script/</link><guid isPermaLink="true">https://hhf.technology/snippets/latency-script/</guid><description>A bash script to monitor network latency and bandwidth between your local machine and cloud instances</description><pubDate>Thu, 23 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import CodeTabs from &apos;$components/tabs/code-tabs.astro&apos;&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Linux/Unix environment with bash shell&lt;/li&gt;
&lt;li&gt;SSH access to your cloud instances&lt;/li&gt;
&lt;li&gt;iperf3 installed locally&lt;/li&gt;
&lt;li&gt;Cloud instance with:
&lt;ul&gt;
&lt;li&gt;Open ports for SSH (22), iperf3 (5201), and ICMP (ping)&lt;/li&gt;
&lt;li&gt;Public IP address&lt;/li&gt;
&lt;li&gt;SSH key-based authentication configured&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;First, ensure you have iperf3 installed on your local machine:&lt;/p&gt;
&lt;p&gt;&amp;lt;CodeTabs&amp;gt;
&amp;lt;Fragment slot=&quot;debian&quot;&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y iperf3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Fragment&amp;gt;
&amp;lt;Fragment slot=&quot;rhel&quot;&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo yum install -y iperf3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Fragment&amp;gt;
&amp;lt;Fragment slot=&quot;mac&quot;&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install iperf3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Fragment&amp;gt;
&amp;lt;/CodeTabs&amp;gt;&lt;/p&gt;
&lt;h2&gt;Script Implementation&lt;/h2&gt;
&lt;p&gt;Create a new file named &lt;code&gt;cloud-network-monitor.sh&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Cloud provider configurations
# Uncomment and configure your desired cloud provider

# AWS Configuration
#CLOUD_HOST=&quot;ubuntu@ec2-xx-xx-xx-xx.compute-1.amazonaws.com&quot;
#KEY_PATH=&quot;/root/.ssh/aws_key&quot;

# Oracle Cloud Configuration
#CLOUD_HOST=&quot;ubuntu@xxx.xxx.xxx.xxx&quot;  # Oracle instances use the public IP
#KEY_PATH=&quot;/root/.ssh/oracle_key&quot;

# DigitalOcean Configuration
#CLOUD_HOST=&quot;root@xxx.xxx.xxx.xxx&quot;    # DigitalOcean droplets typically use root user
#KEY_PATH=&quot;/root/.ssh/digitalocean_key&quot;

# Common Configuration
HOME_VM=&quot;root@10.24.7.117&quot;
INTERVAL=60
LOG_FILE=&quot;network_metrics.log&quot;

# Function to validate configuration
validate_config() {
    if [ -z &quot;$CLOUD_HOST&quot; ] || [ -z &quot;$KEY_PATH&quot; ]; then
        echo &quot;Error: Please configure CLOUD_HOST and KEY_PATH variables&quot;
        exit 1
    fi
    
    if [ ! -f &quot;$KEY_PATH&quot; ]; then
        echo &quot;Error: SSH key not found at $KEY_PATH&quot;
        exit 1
    fi
}

# Function to check network metrics
check_network() {
    local cloud_ip=$(echo $CLOUD_HOST | cut -d@ -f2)
    echo &quot;=== Network Test $(date) ===&quot; | tee -a $LOG_FILE
    echo &quot;Testing connection to: $CLOUD_HOST&quot; | tee -a $LOG_FILE
    
    # Test ping latency (5 packets)
    echo &quot;Testing latency...&quot; | tee -a $LOG_FILE
    ping -c 5 $cloud_ip | tee -a $LOG_FILE
    
    # Test bandwidth using iperf3
    echo &quot;Testing bandwidth...&quot; | tee -a $LOG_FILE
    
    # Start iperf3 server on cloud VM with error handling
    if ! ssh -i $KEY_PATH -o StrictHostKeyChecking=accept-new $CLOUD_HOST &quot;which iperf3 || sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y iperf3&quot;; then
        echo &quot;Failed to ensure iperf3 is installed on cloud server&quot; | tee -a $LOG_FILE
        return 1
    fi
    
    if ! ssh -i $KEY_PATH $CLOUD_HOST &quot;iperf3 -s -D&quot;; then
        echo &quot;Failed to start iperf3 server on cloud instance&quot; | tee -a $LOG_FILE
        return 1
    fi
    
    # Wait for server to start
    sleep 2
    
    # Run bandwidth test locally
    iperf3 -c $cloud_ip -t 10 | tee -a $LOG_FILE
    
    # Stop iperf3 server on cloud VM
    ssh -i $KEY_PATH $CLOUD_HOST &quot;pkill iperf3&quot;
    
    echo &quot;----------------------------------------&quot; | tee -a $LOG_FILE
}

# Validate configuration before starting
validate_config

# Main loop
while true; do
    check_network || echo &quot;Network check failed, will retry in $INTERVAL seconds&quot;
    sleep $INTERVAL
done
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Cloud Provider Setup&lt;/h2&gt;
&lt;h3&gt;AWS Configuration&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Configure your security group to allow:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Type: All ICMP - IPv4
Source: Your home IP

Type: Custom TCP
Port: 5201
Source: Your home IP

Type: SSH
Port: 22
Source: Your home IP
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure your SSH key is in OpenSSH format (if using .ppk):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;puttygen /path/to/key.ppk -O private-openssh -o /root/.ssh/aws_key
chmod 600 /root/.ssh/aws_key
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Oracle Cloud Configuration&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Add the following security rules to your VCN:&lt;pre&gt;&lt;code&gt;TCP port 22 (SSH)
TCP port 5201 (iperf3)
ICMP Type 3 (ping)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;DigitalOcean Configuration&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Create firewall rules in the DigitalOcean console:&lt;pre&gt;&lt;code&gt;TCP port 22 (SSH)
TCP port 5201 (iperf3)
ICMP (ping)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set proper permissions for the script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chmod +x cloud-network-monitor.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update the configuration section with your cloud instance details&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./cloud-network-monitor.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The script will continuously monitor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Network latency using ping&lt;/li&gt;
&lt;li&gt;Bandwidth using iperf3&lt;/li&gt;
&lt;li&gt;Results are logged to network_metrics.log&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;If you encounter SSH key issues:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Fix key permissions
chmod 600 /path/to/your/key

# Test SSH connection
ssh -i /path/to/your/key -v your_cloud_host
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For iperf3 connection issues:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Test iperf3 manually
iperf3 -c your_cloud_ip -p 5201
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Pangolin Stack Debugging Commands 📊</title><link>https://hhf.technology/snippets/pangolin-commands/</link><guid isPermaLink="true">https://hhf.technology/snippets/pangolin-commands/</guid><description>Commands</description><pubDate>Tue, 28 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Pangolin Stack Debugging Commands&lt;/h1&gt;
&lt;h2&gt;Container Management &amp;amp; Health&lt;/h2&gt;
&lt;h3&gt;Basic Container Commands&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# View all container stats (CPU, memory, network I/O)
docker stats

# View specific container stats
docker stats pangolin
docker stats gerbil
docker stats traefik

# Check container logs
docker compose logs -f
docker compose logs pangolin -f
docker compose logs gerbil -f
docker compose logs traefik -f

# Restart specific services
docker compose restart pangolin
docker compose restart gerbil
docker compose restart traefik

# Check container health status
docker inspect --format=&apos;{{.State.Health.Status}}&apos; pangolin
docker inspect --format=&apos;{{.State.Health.Status}}&apos; gerbil
docker inspect --format=&apos;{{.State.Health.Status}}&apos; traefik
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Container Inspection&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Get detailed container information
docker inspect pangolin
docker inspect gerbil
docker inspect traefik

# Check container environment variables
docker exec pangolin env
docker exec gerbil env
docker exec traefik env

# View running processes in containers
docker top pangolin
docker top gerbil
docker top traefik
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Network Debugging&lt;/h2&gt;
&lt;h3&gt;Network Inspection&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# List all networks
docker network ls

# Inspect network details
docker network inspect pangolin_default

# Get container IP addresses
docker inspect -f &apos;{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}&apos; pangolin
docker inspect -f &apos;{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}&apos; gerbil
docker inspect -f &apos;{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}&apos; traefik

# Check network connectivity between containers
docker exec pangolin ping gerbil
docker exec gerbil ping traefik
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Port Mapping&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# List all port mappings
docker port pangolin
docker port gerbil
docker port traefik

# Check listening ports
docker exec pangolin netstat -tulpn
docker exec gerbil netstat -tulpn
docker exec traefik netstat -tulpn
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Volume Management&lt;/h2&gt;
&lt;h3&gt;Volume Inspection&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# List all volumes
docker volume ls

# Inspect volume details
docker volume inspect pangolin_config
docker volume inspect traefik_config

# Check volume contents
docker exec pangolin ls -la /app/config
docker exec traefik ls -la /etc/traefik
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Config File Access&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# View configuration files
docker exec pangolin cat /app/config/config.yml
docker exec traefik cat /etc/traefik/traefik_config.yml
docker exec traefik cat /etc/traefik/dynamic_config.yml

# Check file permissions
docker exec pangolin ls -l /app/config
docker exec traefik ls -l /etc/traefik
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Service-Specific Commands&lt;/h2&gt;
&lt;h3&gt;Pangolin&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Check Pangolin API health
curl -I http://localhost:3001/api/v1/health

# View Pangolin logs
docker exec pangolin tail -f /app/config/logs/pangolin.log

# Check database status
docker exec pangolin ls -l /app/config/db
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Gerbil&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Check WireGuard interface status
docker exec gerbil wg show
docker exec gerbil ip addr show

# View Gerbil peers
docker exec gerbil wg show all

# Check Gerbil logs
docker exec gerbil tail -f /var/log/gerbil.log
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Traefik&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Check Traefik dashboard (if enabled)
curl -I http://localhost:8080

# View Traefik configurations
docker exec traefik cat /etc/traefik/traefik.yml

# Check SSL certificates
docker exec traefik ls -l /letsencrypt

# View access logs
docker exec traefik tail -f /var/log/access.log
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Security &amp;amp; Certificate Management&lt;/h2&gt;
&lt;h3&gt;SSL/TLS&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Check Let&apos;s Encrypt certificates
docker exec traefik cat /letsencrypt/acme.json

# View certificate expiration
docker exec traefik openssl x509 -in /letsencrypt/acme.json -text -noout

# Test SSL configuration
curl -vI https://your-domain.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Authentication&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Check Badger plugin status
docker exec traefik curl http://localhost:8080/api/http/middlewares

# Test authentication endpoints
curl -I https://your-domain.com/api/v1/auth/status
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;CrowdSec Security Monitoring&lt;/h2&gt;
&lt;h3&gt;Basic CrowdSec Operations&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Monitor CrowdSec container resources
docker stats crowdsec

# View CrowdSec metrics
curl http://localhost:6060/metrics | grep appsec
docker exec -it crowdsec cscli metrics

# Check CrowdSec logs
docker exec -it crowdsec tail -f /var/log/crowdsec.log
docker exec -it crowdsec ls -l /var/log/traefik/
docker exec -it crowdsec cscli explain /var/log/traefik/traefik.log
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Decision Management&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# List current decisions
docker exec -it crowdsec cscli decisions list

# Add captcha challenge for an IP
docker exec crowdsec cscli decisions add --ip 10.10.10.45 --type captcha -d 1h

# Ban an IP address
docker exec crowdsec cscli decisions add -i 10.10.10.45 -t ban -d 1h
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Bouncer Management&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# List all bouncers
docker exec crowdsec cscli bouncers list

# Add Traefik bouncer
docker exec crowdsec cscli bouncers add traefik-bouncer

# Remove Traefik bouncer
docker exec crowdsec cscli bouncers delete traefik-bouncer
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Configuration and Integration&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# View CrowdSec acquisition configuration
docker exec crowdsec cat /etc/crowdsec/acquis.yaml

# Restart CrowdSec and Traefik
docker compose restart traefik crowdsec

# Check CrowdSec network configuration
docker network inspect root_default | grep -A 5 pangolin
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Performance Monitoring&lt;/h2&gt;
&lt;h3&gt;Resource Usage&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Check container resource limits
docker inspect --format=&apos;{{.HostConfig.Resources}}&apos; pangolin
docker inspect --format=&apos;{{.HostConfig.Resources}}&apos; gerbil
docker inspect --format=&apos;{{.HostConfig.Resources}}&apos; traefik

# Monitor real-time metrics
docker stats --format &quot;table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Network Performance&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Check network throughput
docker exec gerbil iftop -i wg0

# Monitor network connections
docker exec traefik netstat -ant | grep ESTABLISHED
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Troubleshooting Tips&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Always check logs first when encountering issues:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker compose logs --tail=100 -f
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Verify network connectivity between services:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker network inspect pangolin_default
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Check configuration file syntax:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker exec pangolin yaml lint /app/config/config.yml
docker exec traefik traefik validate /etc/traefik/traefik_config.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Monitor system resources:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker stats --no-stream
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Verify service health endpoints:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;curl -I http://localhost:3001/api/v1/health
curl -I http://localhost:3003/health # Gerbil
curl -I http://localhost:8080/ping # Traefik
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Pangolin Database Commands 📊</title><link>https://hhf.technology/snippets/pangolin-database-commands/</link><guid isPermaLink="true">https://hhf.technology/snippets/pangolin-database-commands/</guid><description>Commands</description><pubDate>Wed, 29 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Single-line SQLite commands that you can directly use in your terminal. Each command is designed for a specific administrative task:&lt;/h1&gt;
&lt;h2&gt;Install sqlite3 to excuate commands&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;apt install sqlite3
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Back up your SQLite database. This is an important practice for data safety. The command will create a backup file with the current date and time in its name.&lt;/h3&gt;
&lt;p&gt;Here&apos;s the command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sqlite3 /path/to/db.sqlite &quot;.backup &apos;/path/to/backups/db_$(date +%Y%m%d_%H%M%S).sqlite&apos;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to also compress the backup to save space, you can extend the command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sqlite3 /path/to/db.sqlite &quot;.backup &apos;/path/to/backups/db_$(date +%Y%m%d_%H%M%S).sqlite&apos;&quot; &amp;amp;&amp;amp; gzip &quot;/path/to/backups/db_$(date +%Y%m%d_%H%M%S).sqlite&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a compressed &lt;code&gt;.gz&lt;/code&gt; file of your backup.&lt;/p&gt;
&lt;h3&gt;For User Management:&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#### List all users and their roles
sqlite3 /path/to/db.sqlite &quot;SELECT u.email, o.name as organization, r.name as role FROM user u LEFT JOIN userOrgs uo ON u.id = uo.userId LEFT JOIN orgs o ON uo.orgId = o.orgId LEFT JOIN roles r ON uo.roleId = r.roleId;&quot;


#### Enable two-factor auth for a user
sqlite3 /path/to/db.sqlite &quot;UPDATE user SET twoFactorEnabled = 1 WHERE email = &apos;user@email.com&apos;;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Site Management:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### View all sites and their status
sqlite3 /path/to/db.sqlite &quot;SELECT name, online, subnet FROM sites;&quot;

#### Check site bandwidth usage
sqlite3 /path/to/db.sqlite &quot;SELECT name, bytesIn/1024/1024 as MB_in, bytesOut/1024/1024 as MB_out FROM sites;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Resource Management:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### List all resources and their domains
sqlite3 /path/to/db.sqlite &quot;SELECT name, fullDomain, ssl FROM resources;&quot;

#### Check resource access settings
sqlite3 /path/to/db.sqlite &quot;SELECT name, blockAccess, sso, emailWhitelistEnabled FROM resources;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Role and Permission Management:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### List all roles and their actions
sqlite3 /path/to/db.sqlite &quot;SELECT r.name, a.actionId FROM roles r JOIN roleActions ra ON r.roleId = ra.roleId JOIN actions a ON ra.actionId = a.actionId;&quot;

#### Show all admin users
sqlite3 /path/to/db.sqlite &quot;SELECT u.email FROM user u JOIN userOrgs uo ON u.id = uo.userId WHERE uo.isOwner = 1;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Security Auditing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### List users with 2FA status
sqlite3 /path/to/db.sqlite &quot;SELECT email, twoFactorEnabled, emailVerified FROM user;&quot;

#### Show active sessions
sqlite3 /path/to/db.sqlite &quot;SELECT s.id, u.email, s.expiresAt FROM session s JOIN user u ON s.userId = u.id;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Organization Management:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### List all organizations and their domains
sqlite3 /path/to/db.sqlite &quot;SELECT orgId, name, domain FROM orgs;&quot;

#### Show organization members
sqlite3 /path/to/db.sqlite &quot;SELECT o.name, u.email FROM orgs o JOIN userOrgs uo ON o.orgId = uo.orgId JOIN user u ON uo.userId = u.id;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each of these commands can be directly copied and pasted into your terminal. Remember to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Replace &lt;code&gt;/path/to/db.sqlite&lt;/code&gt; with your actual database path&lt;/li&gt;
&lt;li&gt;Replace placeholder values like &apos;user@email.com&apos; with actual values&lt;/li&gt;
&lt;li&gt;Add quotes around values when dealing with strings&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>WinSCP with sudo privileges on an Ubuntu server AWS 📊</title><link>https://hhf.technology/snippets/run-sudo-su-in-winscp-aws/</link><guid isPermaLink="true">https://hhf.technology/snippets/run-sudo-su-in-winscp-aws/</guid><description>To run WinSCP with sudo privileges on an Ubuntu server AWS</description><pubDate>Tue, 28 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To run WinSCP with sudo privileges on an Ubuntu server, you can follow these detailed steps. This configuration allows you to access files and directories that require elevated permissions.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Ensure you have &lt;strong&gt;WinSCP&lt;/strong&gt; installed on your local machine.&lt;/li&gt;
&lt;li&gt;You need to have access to an &lt;strong&gt;Ubuntu server&lt;/strong&gt; (in this case, Ubuntu 24.04).&lt;/li&gt;
&lt;li&gt;Your user account on the server must have the necessary permissions to use &lt;code&gt;sudo&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step-by-Step Guide&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open WinSCP&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Launch the WinSCP application on your local machine.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Access Site Manager&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Session&lt;/strong&gt; in the menu bar and select &lt;strong&gt;Sites&lt;/strong&gt; followed by &lt;strong&gt;Site Manager&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Edit Your Site Profile&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the Site Manager window, select your existing site profile or create a new one.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Edit&lt;/strong&gt; button.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open Advanced Settings&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the Edit Site dialog, click on the &lt;strong&gt;Advanced...&lt;/strong&gt; button located at the bottom.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure SFTP Settings&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the Advanced Site Settings window, navigate to &lt;strong&gt;Environment&lt;/strong&gt; and then select &lt;strong&gt;SFTP&lt;/strong&gt; from the left panel.&lt;/li&gt;
&lt;li&gt;You will see a field labeled &lt;strong&gt;SFTP Server&lt;/strong&gt;. Here, you need to enter the command that allows you to run the SFTP server with sudo privileges.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Insert SFTP Server Command&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enter the following command in the &lt;strong&gt;SFTP Server&lt;/strong&gt; field:&lt;pre&gt;&lt;code&gt;sudo su -c /usr/lib/sftp-server
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Note: The path &lt;code&gt;/usr/lib/sftp-server&lt;/code&gt; may vary based on your system configuration. You can verify the correct path by checking your SSH configuration file (&lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;) for the line starting with &lt;code&gt;Subsystem sftp&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Save Your Changes&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;OK&lt;/strong&gt; to save your changes in the Advanced settings.&lt;/li&gt;
&lt;li&gt;Then click &lt;strong&gt;Save&lt;/strong&gt; in the Edit Site dialog.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Connect to Your Server&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Now, return to the main WinSCP interface and click on &lt;strong&gt;Login&lt;/strong&gt; to connect to your server using your configured profile.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Verify Permissions&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Once connected, you should have access to directories that require root permissions, allowing you to upload or modify files as needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Additional Considerations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Make sure that your user has &lt;code&gt;NOPASSWD&lt;/code&gt; access in the &lt;code&gt;/etc/sudoers&lt;/code&gt; file for seamless operation without being prompted for a password when using sudo commands. This can be set with an entry like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;username ALL=(ALL) NOPASSWD: ALL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;username&lt;/code&gt; with your actual username.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you encounter issues connecting or transferring files, ensure that your SSH configuration allows for passwordless authentication if required, and check for any restrictions in your firewall settings or SSH daemon configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By following these steps, you should be able to successfully configure WinSCP to operate with sudo privileges on your Ubuntu server, enhancing your file transfer capabilities while maintaining security protocols.&lt;/p&gt;
</content:encoded></item><item><title>Installing Starship 🚀</title><link>https://hhf.technology/snippets/starship-installation/</link><guid isPermaLink="true">https://hhf.technology/snippets/starship-installation/</guid><description>Installation guide for Starship (Cross-Shell Prompt)</description><pubDate>Sat, 23 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import CodeTabs from &apos;$components/tabs/code-tabs.astro&apos;&lt;/p&gt;
&lt;h2&gt;Prerequisities&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Terminal&lt;/strong&gt; of your choice&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nerdfonts.com/font-downloads&quot;&gt;&lt;strong&gt;Nerd Font&lt;/strong&gt;&lt;/a&gt; - Any font with the Nerd Font patch to display icons in the terminal&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Git Bash&lt;/strong&gt; - I am using git bash primarily, you can use any other.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;Install Starship using any package manager available on your machine. Detailed installation guides for various platforms are available on the &lt;a href=&quot;https://starship.rs/&quot;&gt;&lt;strong&gt;official website&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Download using Package Manager&lt;/h3&gt;
&lt;p&gt;&amp;lt;CodeTabs&amp;gt;
&amp;lt;Fragment slot=&quot;windows&quot;&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;winget install -e --id Microsoft.WindowsTerminal 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Fragment&amp;gt;
&amp;lt;Fragment slot=&quot;linux&quot;&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -sS https://starship.rs/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Fragment&amp;gt;
&amp;lt;Fragment slot=&quot;mac&quot;&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -sS https://starship.rs/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Fragment&amp;gt;
&amp;lt;/CodeTabs&amp;gt;&lt;/p&gt;
&lt;h3&gt;Setup&lt;/h3&gt;
&lt;p&gt;Once installed, integrate Starship into your shell startup process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your &lt;code&gt;~/.bashrc&lt;/code&gt; file (or equivalent for your shell).&lt;/li&gt;
&lt;li&gt;Add the following line to the end of the file:&lt;pre&gt;&lt;code&gt;# ~/.bashrc
eval &quot;$(starship init bash)&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Save the file and either restart your terminal or source the &lt;code&gt;~/.bashrc&lt;/code&gt; for the changes to take effect.&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item></channel></rss>