• Welcome to LiuJason's Blog!

使用PHP读取MySQL中配置信息并自动批量生成Nginx反向代理配置

Linux笔记 Jason 6 days ago 6 Views 0 Comments QR code of this page

前言

又造了个轮子....用来给SHPC用的,后续开通新的SHPC时不用再调用API操作Caddy了,直接Nginx搞定。
简单描述一下流程:
1. 支付回调确认付款成功,系统自动开通SHPC容器,这时候需要做一个反向代理,将客户的rstudio和jupyterhub暴露给公网访问。
2. 系统将需要反代的信息写入MySQL数据库。
3. 定时任务每5分钟执行一次PHP脚本,脚本读取MySQL中的配置并生成对应Nginx的conf文件。
4. 确认生成成功后Nginx重载配置(Reload)

代码

首先是MySQL部分:

CREATE TABLE `reverse_proxies` (
  `id` int UNSIGNED NOT NULL,
  `hostname` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `listen_port` smallint UNSIGNED NOT NULL DEFAULT '80',
  `protocol` enum('HTTP','HTTPS') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'HTTP',
  `proxy_address` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL,
  `proxy_hostname` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `enable_websocket` tinyint(1) NOT NULL DEFAULT '0',
  `metadata` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

ALTER TABLE `reverse_proxies`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `unique_hostname_port` (`hostname`,`listen_port`);
  
ALTER TABLE `reverse_proxies`
  MODIFY `id` int UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
COMMIT;

然后是PHP部分

<?php
/**
 * Script to generate/update Nginx reverse proxy configuration based on MySQL table entries.
 * 
 * Usage: php update_nginx_config.php
 */

// Database configuration
$dbHost = 'localhost';          // Database host
$dbName = 'reverse_proxies'; // Database name
$dbUser = 'reverse_proxies';      // Database username
$dbPass = 'XXXXXXXXXXX';      // Database password

// Nginx configuration file path
$nginxConfigPath = './0.auto-reverse-proxy.conf';

// Nginx configuration header
$nginxConfigHeader = <<<EOL
# Auto-generated reverse proxy configuration
# Generated on: {date}

EOL;

// Function to escape variables for Nginx
function escape_nginx($string) {
    return addcslashes($string, '\\"');
}

try {
    // Establish a PDO connection
    $dsn = "mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4";
    $options = [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // Enable exceptions
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,       // Fetch associative arrays
        PDO::ATTR_EMULATE_PREPARES   => false,                  // Disable emulation
    ];
    $pdo = new PDO($dsn, $dbUser, $dbPass, $options);

    // Fetch all reverse proxy entries
    $stmt = $pdo->query("SELECT hostname, listen_port, protocol, proxy_address, proxy_hostname, enable_websocket FROM reverse_proxies");
    $reverseProxies = $stmt->fetchAll();

    // Initialize the configuration content
    $configContent = $nginxConfigHeader;
    $configContent = str_replace('{date}', date('Y-m-d H:i:s'), $configContent);

    // Generate Nginx server blocks
    foreach ($reverseProxies as $proxy) {
        // Sanitize and escape variables
        $hostname = escape_nginx($proxy['hostname']);
        $listenPort = (int)$proxy['listen_port'];
        $protocol = strtoupper($proxy['protocol']);
        $proxyAddress = escape_nginx($proxy['proxy_address']);
        $proxyHostname = escape_nginx($proxy['proxy_hostname']);
        $enableWebsocket = (bool)$proxy['enable_websocket'];

        // Initialize listen directives
        $listenDirectives = '';
        $sslConfig = '';
        $websocketConfig = '';

        if ($protocol === 'HTTPS') {
            // For HTTPS, include both HTTP and HTTPS listen directives
            $listenDirectives = "listen 80;\n    listen [::]:80;\n    listen 443 ssl;\n    listen [::]:443 ssl;";
            
            // Paths to SSL certificate and key files
            // Ensure these paths are correct and certificates exist
            $sslCertPath = "/www/server/panel/vhost/cert/cloudraft.cn/fullchain.pem";
            $sslKeyPath = "/www/server/panel/vhost/cert/cloudraft.cn/privkey.pem";

            $sslConfig = <<<EOL

    ssl_certificate     {$sslCertPath};
    ssl_certificate_key {$sslKeyPath};
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

EOL;
        } else { // HTTP
            // For HTTP, only include the HTTP listen directive
            $listenDirectives = "listen {$listenPort};\n    listen [::]:{$listenPort};";
        }
        
        // WebSocket Configuration (if enabled)
        if ($enableWebsocket) {
            $websocketConfig = <<<EOL

        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";

EOL;
        }

        // Construct the server block
        $serverBlock = <<<EOL
server {
    {$listenDirectives}
    server_name {$hostname};
    root /www/wwwroot/router-sh-bgp.cloudraft.cn/reverse-proxy;

{$sslConfig}
    location / {
        proxy_pass {$proxyAddress};
        proxy_set_header Host {$proxyHostname};
        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;
    }
}

EOL;

        // Append the server block to the configuration content
        $configContent .= $serverBlock;
    }

    // Write the configuration to the file
    if (file_put_contents($nginxConfigPath, $configContent) === false) {
        throw new Exception("Failed to write to Nginx configuration file: {$nginxConfigPath}");
    }

    echo "Nginx configuration successfully updated.\n";

    // Optionally, reload Nginx to apply changes
    // Uncomment the following lines if you want the script to reload Nginx automatically
    /*
    $reloadOutput = [];
    $reloadStatus = 0;
    exec('sudo systemctl reload nginx', $reloadOutput, $reloadStatus);
    if ($reloadStatus !== 0) {
        throw new Exception("Failed to reload Nginx. Output: " . implode("\n", $reloadOutput));
    }
    echo "Nginx reloaded successfully.\n";
    */

} catch (PDOException $e) {
    // Handle database connection errors
    error_log("Database error: " . $e->getMessage());
    exit("Database error occurred. Check logs for details.\n");
} catch (Exception $e) {
    // Handle general errors
    error_log("Error: " . $e->getMessage());
    exit("An error occurred. Check logs for details.\n");
}
?>

最后是定时任务:

sudo -u root bash -c 'curl https://router-sh-bgp.cloudraft.cn/reverse-proxy/update.php && /etc/init.d/nginx reload'

This article is under CC BY-NC-SA 4.0 license.
Please quote the original link:https://www.liujason.com/article/1284.html
Like (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址