feat: 新增 15 个服务组件,总计 59 个

系统服务: NTP, DHCP, BIND, NFS, SAMBA, RSYNC, Sersync, vsftpd, Subversion
数据库中间件: Mycat
CI/CD: GitLab, Jenkins
高可用: Keepalived, HAProxy, LVS

新增 4 个分类: 系统服务、数据库中间件、CI/CD、高可用
This commit is contained in:
cnbugs
2026-07-19 16:11:09 +08:00
parent 3d6501efd5
commit d80d33e6f6
19 changed files with 3810 additions and 2 deletions
+16 -1
View File
@@ -37,7 +37,7 @@
--- ---
## 🧩 支持组件(44 个) ## 🧩 支持组件(59 个)
| 分类 | 组件 | 输出格式 | 核心配置项 | | 分类 | 组件 | 输出格式 | 核心配置项 |
|------|------|----------|------------| |------|------|----------|------------|
@@ -85,6 +85,21 @@
| 日志监控 | **Syslog** | `.conf` | UDP/TCP/RELP 协议、远程日志、按主机分目录、速率限制 | | 日志监控 | **Syslog** | `.conf` | UDP/TCP/RELP 协议、远程日志、按主机分目录、速率限制 |
| 自动化运维 | **Ansible** | `.cfg` | SSH 连接、Pipelining、Become 提权、Forks、事实缓存 | | 自动化运维 | **Ansible** | `.cfg` | SSH 连接、Pipelining、Become 提权、Forks、事实缓存 |
| 自动化运维 | **Ansible Playbook** | `.yaml` | 变量、包管理、服务管理、文件复制、模板渲染、Handlers | | 自动化运维 | **Ansible Playbook** | `.yaml` | 变量、包管理、服务管理、文件复制、模板渲染、Handlers |
| 系统服务 | **NTP** | `.conf` | NTP 服务器、认证、轮询间隔、drift 文件 |
| 系统服务 | **DHCP** | `.conf` | 子网、地址范围、租约时间、网关、静态绑定 |
| 系统服务 | **BIND (DNS)** | `.conf` | 监听地址、转发器、递归、DNSSEC、Zone 配置 |
| 系统服务 | **NFS** | `.exports` | 共享路径、客户端地址、权限、root_squash、NFSv4 |
| 系统服务 | **SAMBA** | `.conf` | 工作组、共享目录、权限、用户认证、日志 |
| 系统服务 | **RSYNC** | `.conf` | 模块、路径、认证、主机白名单 |
| 系统服务 | **Sersync** | `.xml` | 监控目录、远程同步目标、过滤规则、定时触发 |
| 系统服务 | **vsftpd** | `.conf` | 被动模式、TLS、用户限制、chroot、日志 |
| 系统服务 | **Subversion** | `.conf` | 匿名访问、认证、SASL、Hook 脚本 |
| 数据库中间件 | **Mycat** | `.xml` | 端口、字符集、连接数、事务隔离、认证 |
| CI/CD | **GitLab** | `.rb` | 外部 URL、SSL、数据库、Redis、Registry、SMTP |
| CI/CD | **Jenkins** | `.yaml` | 端口、执行器、LDAP、Casc、Git 配置 |
| 高可用 | **Keepalived** | `.conf` | VRRP 实例、VIP、优先级、健康检查、通知脚本 |
| 高可用 | **HAProxy** | `.cfg` | 全局配置、前后端、负载均衡算法、SSL、统计页面 |
| 高可用 | **LVS** | `.conf` | 调度算法、VIP、Real Server、DR/NAT/TUN 模式 |
--- ---
Binary file not shown.
+1 -1
View File
@@ -60,7 +60,7 @@
</div> </div>
<div class="sidebar-footer"> <div class="sidebar-footer">
<el-text size="small" type="info">v1.0.0 · 纯前端生成 · 44 个组件</el-text> <el-text size="small" type="info">v1.0.0 · 纯前端生成 · 59 个组件</el-text>
</div> </div>
</div> </div>
</template> </template>
+252
View File
@@ -0,0 +1,252 @@
export const bindSchema = {
id: 'bind',
name: 'BIND (DNS)',
icon: 'Connection',
category: '系统服务',
description: 'BIND DNS 服务器配置',
format: 'conf',
fileName: 'named.conf',
groups: [
{
title: '监听与查询',
fields: [
{
key: 'listenOn',
label: 'IPv4 监听地址',
type: 'text',
default: '127.0.0.1; any',
tip: 'IPv4 监听地址列表',
},
{
key: 'listenOnV6',
label: 'IPv6 监听地址',
type: 'text',
default: '::1; any',
tip: 'IPv6 监听地址列表',
},
{
key: 'allowQuery',
label: '允许查询',
type: 'text',
default: 'localhost; any',
tip: '允许哪些客户端查询',
},
{
key: 'allowRecursion',
label: '允许递归',
type: 'text',
default: 'localhost; localnets',
tip: '允许哪些客户端进行递归查询',
},
{
key: 'recursion',
label: '启用递归',
type: 'switch',
default: true,
},
],
},
{
title: '转发配置',
fields: [
{
key: 'forwarders',
label: '转发服务器',
type: 'text',
default: '8.8.8.8; 8.8.4.4',
tip: '上游 DNS 服务器地址',
},
{
key: 'forwardType',
label: '转发策略',
type: 'select',
options: [
{ label: 'first - 先转发再自行解析', value: 'first' },
{ label: 'only - 仅转发不自行解析', value: 'only' },
],
default: 'first',
},
],
},
{
title: '日志配置',
fields: [
{
key: 'enableLogging',
label: '启用日志',
type: 'switch',
default: true,
},
{
key: 'logCategory',
label: '日志类别',
type: 'text',
default: 'queries',
dependsOn: { key: 'enableLogging', value: true },
tip: 'BIND 日志类别名称',
},
{
key: 'logFile',
label: '日志文件路径',
type: 'text',
default: '/var/log/named/queries.log',
dependsOn: { key: 'enableLogging', value: true },
},
],
},
{
title: 'DNSSEC',
fields: [
{
key: 'enableDnssec',
label: '启用 DNSSEC',
type: 'switch',
default: true,
tip: '启用 DNS 安全扩展',
},
{
key: 'dnssecValidation',
label: 'DNSSEC 验证',
type: 'switch',
default: true,
tip: '对查询结果进行 DNSSEC 验证',
},
],
},
{
title: '区域配置',
fields: [
{
key: 'enableZone',
label: '启用自定义区域',
type: 'switch',
default: false,
tip: '配置本地 DNS 区域',
},
{
key: 'zoneName',
label: '区域名称',
type: 'text',
default: 'example.com',
dependsOn: { key: 'enableZone', value: true },
},
{
key: 'zoneType',
label: '区域类型',
type: 'select',
options: [
{ label: 'master - 主区域', value: 'master' },
{ label: 'slave - 从区域', value: 'slave' },
{ label: 'hint - 根提示', value: 'hint' },
],
default: 'master',
dependsOn: { key: 'enableZone', value: true },
},
{
key: 'zoneFile',
label: '区域文件路径',
type: 'text',
default: '/var/named/example.com.zone',
dependsOn: { key: 'enableZone', value: true },
},
],
},
],
}
export function generateBindConf(config) {
const lines = []
lines.push(`// BIND DNS 配置文件 - 由 ConfTemplate 生成`)
lines.push(`// 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
// Options block
lines.push(`// ======================== 全局选项 ========================`)
lines.push(`options {`)
lines.push(` listen-on port 53 { ${config.listenOn} };`)
lines.push(` listen-on-v6 port 53 { ${config.listenOnV6} };`)
lines.push(` directory "/var/named";`)
lines.push(` dump-file "/var/named/data/cache_dump.db";`)
lines.push(` statistics-file "/var/named/data/named_stats.txt";`)
lines.push(` memstatistics-file "/var/named/data/named_mem_stats.txt";`)
lines.push(` allow-query { ${config.allowQuery} };`)
lines.push(` allow-recursion { ${config.allowRecursion} };`)
lines.push(` recursion ${config.recursion ? 'yes' : 'no'};`)
lines.push(``)
lines.push(` forwarders {`)
const forwarders = config.forwarders.split(';').map((s) => s.trim()).filter(Boolean)
forwarders.forEach((f) => {
lines.push(` ${f};`)
})
lines.push(` };`)
lines.push(` forward ${config.forwardType};`)
lines.push(``)
if (config.enableDnssec) {
lines.push(` dnssec-enable yes;`)
}
if (config.dnssecValidation) {
lines.push(` dnssec-validation yes;`)
}
lines.push(``)
lines.push(` pid-file "/run/named/named.pid";`)
lines.push(` session-keyfile "/run/named/session.key";`)
lines.push(`};`)
lines.push(``)
// Logging
if (config.enableLogging) {
lines.push(`// ======================== 日志配置 ========================`)
lines.push(`logging {`)
lines.push(` channel default_debug {`)
lines.push(` file "data/named.run";`)
lines.push(` severity dynamic;`)
lines.push(` };`)
lines.push(` channel query_log {`)
lines.push(` file "${config.logFile}" versions 3 size 5m;`)
lines.push(` severity dynamic;`)
lines.push(` print-time yes;`)
lines.push(` print-category yes;`)
lines.push(` };`)
lines.push(` category ${config.logCategory} { query_log; };`)
lines.push(`};`)
lines.push(``)
}
// Zone configuration
lines.push(`// ======================== 标准区域 ========================`)
lines.push(`zone "." IN {`)
lines.push(` type hint;`)
lines.push(` file "named.ca";`)
lines.push(`};`)
lines.push(``)
lines.push(`zone "localhost" IN {`)
lines.push(` type master;`)
lines.push(` file "named.localhost";`)
lines.push(` allow-update { none; };`)
lines.push(`};`)
lines.push(``)
lines.push(`zone "0.0.127.in-addr.arpa" IN {`)
lines.push(` type master;`)
lines.push(` file "named.loopback";`)
lines.push(` allow-update { none; };`)
lines.push(`};`)
lines.push(``)
if (config.enableZone) {
lines.push(`// ======================== 自定义区域 ========================`)
lines.push(`zone "${config.zoneName}" IN {`)
lines.push(` type ${config.zoneType};`)
lines.push(` file "${config.zoneFile}";`)
if (config.zoneType === 'master') {
lines.push(` allow-update { none; };`)
}
lines.push(`};`)
lines.push(``)
}
lines.push(`include "/etc/named.rfc1912.zones";`)
lines.push(`include "/etc/named.root.key";`)
return lines.join('\n')
}
+169
View File
@@ -0,0 +1,169 @@
export const dhcpSchema = {
id: 'dhcp',
name: 'DHCP',
icon: 'Connection',
category: '系统服务',
description: 'ISC DHCP 服务器配置',
format: 'conf',
fileName: 'dhcpd.conf',
groups: [
{
title: '全局参数',
fields: [
{
key: 'domainName',
label: '域名',
type: 'text',
default: 'example.com',
tip: '分配给客户端的域名',
},
{
key: 'domainNameServers',
label: 'DNS 服务器',
type: 'text',
default: '8.8.8.8, 8.8.4.4',
tip: '多个用逗号分隔',
},
{
key: 'defaultLeaseTime',
label: '默认租约时间 (秒)',
type: 'number',
min: 60,
max: 86400,
default: 600,
},
{
key: 'maxLeaseTime',
label: '最大租约时间 (秒)',
type: 'number',
min: 60,
max: 604800,
default: 7200,
},
],
},
{
title: '子网配置',
fields: [
{
key: 'subnet',
label: '子网地址',
type: 'text',
default: '192.168.1.0',
tip: 'DHCP 分配的子网',
},
{
key: 'netmask',
label: '子网掩码',
type: 'text',
default: '255.255.255.0',
},
{
key: 'rangeStart',
label: '地址池起始',
type: 'text',
default: '192.168.1.100',
tip: '动态分配范围起始 IP',
},
{
key: 'rangeEnd',
label: '地址池结束',
type: 'text',
default: '192.168.1.200',
tip: '动态分配范围结束 IP',
},
{
key: 'gateway',
label: '默认网关',
type: 'text',
default: '192.168.1.1',
},
{
key: 'broadcastAddress',
label: '广播地址',
type: 'text',
default: '192.168.1.255',
},
],
},
{
title: '静态主机绑定',
fields: [
{
key: 'enableStaticHost',
label: '启用静态主机',
type: 'switch',
default: false,
tip: '为特定 MAC 地址分配固定 IP',
},
{
key: 'staticHostName',
label: '主机名',
type: 'text',
default: 'myhost',
dependsOn: { key: 'enableStaticHost', value: true },
},
{
key: 'staticHostMac',
label: 'MAC 地址',
type: 'text',
default: '00:11:22:33:44:55',
dependsOn: { key: 'enableStaticHost', value: true },
tip: '客户端 MAC 地址',
},
{
key: 'staticHostIp',
label: '固定 IP 地址',
type: 'text',
default: '192.168.1.50',
dependsOn: { key: 'enableStaticHost', value: true },
},
],
},
],
}
export function generateDhcpConf(config) {
const lines = []
lines.push(`# DHCP 服务器配置文件 - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
// Global parameters
lines.push(`# ======================== 全局参数 ========================`)
lines.push(`option domain-name "${config.domainName}";`)
const dnsServers = config.domainNameServers.split(',').map((s) => s.trim()).join(', ')
lines.push(`option domain-name-servers ${dnsServers};`)
lines.push(``)
lines.push(`default-lease-time ${config.defaultLeaseTime};`)
lines.push(`max-lease-time ${config.maxLeaseTime};`)
lines.push(``)
lines.push(`# 如果本机不是 DHCP 服务器的 authoritative,取消注释下行`)
lines.push(`# authoritative;`)
lines.push(``)
// Subnet configuration
lines.push(`# ======================== 子网配置 ========================`)
lines.push(`subnet ${config.subnet} netmask ${config.netmask} {`)
lines.push(` range ${config.rangeStart} ${config.rangeEnd};`)
lines.push(` option routers ${config.gateway};`)
lines.push(` option broadcast-address ${config.broadcastAddress};`)
lines.push(` option domain-name-servers ${dnsServers};`)
lines.push(` option domain-name "${config.domainName}";`)
lines.push(` default-lease-time ${config.defaultLeaseTime};`)
lines.push(` max-lease-time ${config.maxLeaseTime};`)
lines.push(`}`)
lines.push(``)
// Static host
if (config.enableStaticHost) {
lines.push(`# ======================== 静态主机绑定 ========================`)
lines.push(`host ${config.staticHostName} {`)
lines.push(` hardware ethernet ${config.staticHostMac};`)
lines.push(` fixed-address ${config.staticHostIp};`)
lines.push(`}`)
lines.push(``)
}
return lines.join('\n')
}
+325
View File
@@ -0,0 +1,325 @@
export const gitlabSchema = {
id: 'gitlab',
name: 'GitLab',
icon: 'Files',
category: 'CI/CD',
description: 'DevOps 生命周期平台,提供代码托管、CI/CD、制品管理等',
format: 'rb',
fileName: 'gitlab.rb',
groups: [
{
title: '基础配置',
fields: [
{
key: 'externalUrl',
label: '外部访问 URL',
type: 'text',
placeholder: 'http://gitlab.example.com',
default: 'http://gitlab.example.com',
required: true,
tip: 'GitLab 实例的外部访问地址',
},
],
},
{
title: 'Nginx 配置',
fields: [
{
key: 'nginxListenPort',
label: 'Nginx 监听端口',
type: 'number',
min: 1,
max: 65535,
default: 80,
},
{
key: 'nginxEnableSsl',
label: '启用 SSL',
type: 'switch',
default: false,
tip: '为 Nginx 启用 HTTPS',
},
{
key: 'sslCertificate',
label: 'SSL 证书路径',
type: 'text',
default: '/etc/gitlab/ssl/gitlab.crt',
dependsOn: { key: 'nginxEnableSsl', value: true },
required: true,
},
{
key: 'sslCertificateKey',
label: 'SSL 私钥路径',
type: 'text',
default: '/etc/gitlab/ssl/gitlab.key',
dependsOn: { key: 'nginxEnableSsl', value: true },
required: true,
},
],
},
{
title: '数据库配置',
fields: [
{
key: 'gitlabRbDbAdapter',
label: '数据库类型',
type: 'select',
options: [
{ label: 'PostgreSQL', value: 'postgresql' },
{ label: 'MySQL', value: 'mysql' },
],
default: 'postgresql',
},
{
key: 'gitlabRbDbHost',
label: '数据库主机',
type: 'text',
default: '127.0.0.1',
},
{
key: 'gitlabRbDbPort',
label: '数据库端口',
type: 'number',
min: 1,
max: 65535,
default: 5432,
},
{
key: 'gitlabRbDbName',
label: '数据库名称',
type: 'text',
default: 'gitlabhq_production',
},
{
key: 'gitlabRbDbUser',
label: '数据库用户',
type: 'text',
default: 'gitlab',
},
{
key: 'gitlabRbDbPassword',
label: '数据库密码',
type: 'text',
default: 'changeme',
tip: '生产环境请使用强密码',
},
],
},
{
title: 'Redis 配置',
fields: [
{
key: 'redisHost',
label: 'Redis 主机',
type: 'text',
default: '127.0.0.1',
},
{
key: 'redisPort',
label: 'Redis 端口',
type: 'number',
min: 1,
max: 65535,
default: 6379,
},
],
},
{
title: 'Container Registry',
fields: [
{
key: 'registryEnable',
label: '启用 Container Registry',
type: 'switch',
default: false,
tip: 'Docker 镜像仓库',
},
{
key: 'registryExternalUrl',
label: 'Registry 外部 URL',
type: 'text',
placeholder: 'http://registry.example.com',
default: 'http://registry.example.com',
dependsOn: { key: 'registryEnable', value: true },
},
],
},
{
title: 'GitLab Pages',
fields: [
{
key: 'pagesEnable',
label: '启用 GitLab Pages',
type: 'switch',
default: false,
tip: '静态网站托管服务',
},
{
key: 'pagesExternalUrl',
label: 'Pages 外部 URL',
type: 'text',
placeholder: 'http://pages.example.com',
default: 'http://pages.example.com',
dependsOn: { key: 'pagesEnable', value: true },
},
],
},
{
title: 'SMTP 邮件配置',
fields: [
{
key: 'smtpEnable',
label: '启用 SMTP',
type: 'switch',
default: false,
tip: '用于发送邮件通知',
},
{
key: 'smtpAddress',
label: 'SMTP 服务器',
type: 'text',
default: 'smtp.example.com',
dependsOn: { key: 'smtpEnable', value: true },
},
{
key: 'smtpPort',
label: 'SMTP 端口',
type: 'number',
min: 1,
max: 65535,
default: 587,
dependsOn: { key: 'smtpEnable', value: true },
},
{
key: 'smtpUser',
label: 'SMTP 用户名',
type: 'text',
default: 'gitlab@example.com',
dependsOn: { key: 'smtpEnable', value: true },
},
{
key: 'smtpPassword',
label: 'SMTP 密码',
type: 'text',
default: 'changeme',
dependsOn: { key: 'smtpEnable', value: true },
},
{
key: 'smtpTls',
label: '启用 TLS',
type: 'switch',
default: true,
dependsOn: { key: 'smtpEnable', value: true },
},
],
},
{
title: '备份与监控',
fields: [
{
key: 'backupKeepTime',
label: '备份保留时间 (秒)',
type: 'number',
min: 0,
default: 604800,
tip: '604800 秒 = 7 天',
},
{
key: 'prometheusEnable',
label: '启用 Prometheus 监控',
type: 'switch',
default: true,
},
],
},
],
}
export function generateGitlabRb(config) {
const lines = []
lines.push(`# GitLab 配置文件 - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
lines.push(`## 外部访问 URL`)
lines.push(`external_url '${config.externalUrl}'`)
lines.push(``)
// Nginx
lines.push(`## Nginx 配置`)
lines.push(`nginx['listen_port'] = ${config.nginxListenPort}`)
if (config.nginxEnableSsl) {
lines.push(`nginx['ssl_certificate'] = '${config.sslCertificate}'`)
lines.push(`nginx['ssl_certificate_key'] = '${config.sslCertificateKey}'`)
} else {
lines.push(`nginx['enable_ssl'] = false`)
}
lines.push(``)
// Database
lines.push(`## 数据库配置`)
if (config.gitlabRbDbAdapter === 'postgresql') {
lines.push(`postgresql['enable'] = true`)
lines.push(`gitlab_rails['db_adapter'] = 'postgresql'`)
lines.push(`gitlab_rails['db_host'] = '${config.gitlabRbDbHost}'`)
lines.push(`gitlab_rails['db_port'] = ${config.gitlabRbDbPort}`)
} else {
lines.push(`postgresql['enable'] = false`)
lines.push(`gitlab_rails['db_adapter'] = 'mysql2'`)
lines.push(`gitlab_rails['db_host'] = '${config.gitlabRbDbHost}'`)
lines.push(`gitlab_rails['db_port'] = ${config.gitlabRbDbPort}`)
}
lines.push(`gitlab_rails['db_database'] = '${config.gitlabRbDbName}'`)
lines.push(`gitlab_rails['db_username'] = '${config.gitlabRbDbUser}'`)
lines.push(`gitlab_rails['db_password'] = '${config.gitlabRbDbPassword}'`)
lines.push(``)
// Redis
lines.push(`## Redis 配置`)
lines.push(`redis['enable'] = true`)
lines.push(`gitlab_rails['redis_host'] = '${config.redisHost}'`)
lines.push(`gitlab_rails['redis_port'] = ${config.redisPort}`)
lines.push(``)
// Registry
if (config.registryEnable) {
lines.push(`## Container Registry`)
lines.push(`registry['enable'] = true`)
lines.push(`registry_external_url '${config.registryExternalUrl}'`)
lines.push(``)
}
// Pages
if (config.pagesEnable) {
lines.push(`## GitLab Pages`)
lines.push(`pages_external_url '${config.pagesExternalUrl}'`)
lines.push(`gitlab_pages['enable'] = true`)
lines.push(``)
}
// SMTP
if (config.smtpEnable) {
lines.push(`## SMTP 邮件配置`)
lines.push(`gitlab_rails['smtp_enable'] = true`)
lines.push(`gitlab_rails['smtp_address'] = '${config.smtpAddress}'`)
lines.push(`gitlab_rails['smtp_port'] = ${config.smtpPort}`)
lines.push(`gitlab_rails['smtp_user_name'] = '${config.smtpUser}'`)
lines.push(`gitlab_rails['smtp_password'] = '${config.smtpPassword}'`)
lines.push(`gitlab_rails['smtp_tls'] = ${config.smtpTls}`)
lines.push(``)
}
// Backup
lines.push(`## 备份配置`)
lines.push(`gitlab_rails['backup_keep_time'] = ${config.backupKeepTime}`)
lines.push(``)
// Prometheus
if (config.prometheusEnable) {
lines.push(`## Prometheus 监控`)
lines.push(`prometheus['enable'] = true`)
} else {
lines.push(`prometheus['enable'] = false`)
}
return lines.join('\n')
}
+318
View File
@@ -0,0 +1,318 @@
export const haproxySchema = {
id: 'haproxy',
name: 'HAProxy',
icon: 'Connection',
category: '高可用',
description: '高性能 TCP/HTTP 负载均衡器和代理服务器',
format: 'cfg',
fileName: 'haproxy.cfg',
groups: [
{
title: 'Global 全局配置',
fields: [
{
key: 'globalMaxconn',
label: '最大连接数',
type: 'number',
min: 100,
max: 1000000,
default: 1000,
},
{
key: 'globalLog',
label: '日志输出',
type: 'text',
default: '127.0.0.1 local0',
},
{
key: 'globalChroot',
label: '启用 chroot',
type: 'switch',
default: false,
tip: '安全加固,限制进程访问范围',
},
{
key: 'chrootDir',
label: 'chroot 目录',
type: 'text',
default: '/var/lib/haproxy',
dependsOn: { key: 'globalChroot', value: true },
},
{
key: 'globalUser',
label: '运行用户',
type: 'text',
default: 'haproxy',
},
{
key: 'globalGroup',
label: '运行用户组',
type: 'text',
default: 'haproxy',
},
{
key: 'globalStatsEnable',
label: '启用 Stats Socket',
type: 'switch',
default: true,
},
{
key: 'statsSocket',
label: 'Stats Socket 路径',
type: 'text',
default: '/var/run/haproxy.sock',
dependsOn: { key: 'globalStatsEnable', value: true },
},
],
},
{
title: 'Defaults 默认配置',
fields: [
{
key: 'defaultsMode',
label: '代理模式',
type: 'select',
options: [
{ label: 'HTTP 模式', value: 'http' },
{ label: 'TCP 模式', value: 'tcp' },
],
default: 'http',
},
{
key: 'defaultsLog',
label: '日志模式',
type: 'text',
default: 'global',
},
{
key: 'defaultsOptionHttplog',
label: '启用 HTTP 日志',
type: 'switch',
default: true,
},
{
key: 'defaultsOptionDontlognull',
label: '忽略空连接日志',
type: 'switch',
default: true,
},
{
key: 'defaultsTimeoutConnect',
label: '连接超时 (ms)',
type: 'number',
min: 100,
max: 60000,
default: 5000,
},
{
key: 'defaultsTimeoutClient',
label: '客户端超时 (ms)',
type: 'number',
min: 1000,
max: 300000,
default: 50000,
},
{
key: 'defaultsTimeoutServer',
label: '服务端超时 (ms)',
type: 'number',
min: 1000,
max: 300000,
default: 50000,
},
{
key: 'defaultsRetries',
label: '重试次数',
type: 'number',
min: 0,
max: 10,
default: 3,
},
],
},
{
title: 'Frontend 前端配置',
fields: [
{
key: 'frontendName',
label: '前端名称',
type: 'text',
default: 'myapp_front',
},
{
key: 'frontendBind',
label: '绑定地址',
type: 'text',
default: '*:80',
tip: '格式: 地址:端口',
},
{
key: 'frontendBackend',
label: '关联后端',
type: 'text',
default: 'myapp_back',
},
{
key: 'enableSsl',
label: '启用 SSL',
type: 'switch',
default: false,
},
{
key: 'sslBind',
label: 'SSL 绑定配置',
type: 'text',
default: '*:443 ssl crt /etc/haproxy/cert.pem',
dependsOn: { key: 'enableSsl', value: true },
},
],
},
{
title: 'Backend 后端配置',
fields: [
{
key: 'backendName',
label: '后端名称',
type: 'text',
default: 'myapp_back',
},
{
key: 'balanceType',
label: '负载均衡算法',
type: 'select',
options: [
{ label: 'roundrobin - 轮询 (推荐)', value: 'roundrobin' },
{ label: 'leastconn - 最少连接', value: 'leastconn' },
{ label: 'source - 源地址哈希', value: 'source' },
{ label: 'uri - URI 哈希', value: 'uri' },
],
default: 'roundrobin',
},
{
key: 'backendServer1',
label: '后端服务器 1',
type: 'text',
default: 'web1 192.168.1.10:8080 check',
tip: '格式: 名称 IP:端口 check',
},
{
key: 'backendServer2',
label: '后端服务器 2',
type: 'text',
default: 'web2 192.168.1.11:8080 check',
},
],
},
{
title: 'Stats 统计页面',
fields: [
{
key: 'enableStats',
label: '启用统计页面',
type: 'switch',
default: true,
},
{
key: 'statsUri',
label: '统计页面 URI',
type: 'text',
default: '/haproxy?stats',
dependsOn: { key: 'enableStats', value: true },
},
{
key: 'statsAuthEnable',
label: '统计页面认证',
type: 'switch',
default: true,
dependsOn: { key: 'enableStats', value: true },
},
{
key: 'statsUser',
label: '统计页面用户名',
type: 'text',
default: 'admin',
dependsOn: { key: 'statsAuthEnable', value: true },
},
{
key: 'statsPassword',
label: '统计页面密码',
type: 'text',
default: 'admin',
dependsOn: { key: 'statsAuthEnable', value: true },
},
],
},
],
}
export function generateHaproxyCfg(config) {
const lines = []
lines.push(`# HAProxy 配置文件 - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
// Global
lines.push(`global`)
lines.push(` log ${config.globalLog} local0`)
lines.push(` maxconn ${config.globalMaxconn}`)
lines.push(` user ${config.globalUser}`)
lines.push(` group ${config.globalGroup}`)
lines.push(` daemon`)
if (config.globalChroot) {
lines.push(` chroot ${config.chrootDir}`)
}
if (config.globalStatsEnable) {
lines.push(` stats socket ${config.statsSocket} mode 660 level admin`)
}
lines.push(``)
// Defaults
lines.push(`defaults`)
lines.push(` mode ${config.defaultsMode}`)
lines.push(` log ${config.defaultsLog}`)
if (config.defaultsOptionHttplog) {
lines.push(` option httplog`)
}
if (config.defaultsOptionDontlognull) {
lines.push(` option dontlognull`)
}
lines.push(` timeout connect ${config.defaultsTimeoutConnect}`)
lines.push(` timeout client ${config.defaultsTimeoutClient}`)
lines.push(` timeout server ${config.defaultsTimeoutServer}`)
lines.push(` retries ${config.defaultsRetries}`)
lines.push(``)
// Frontend
lines.push(`frontend ${config.frontendName}`)
lines.push(` bind ${config.frontendBind}`)
if (config.enableSsl) {
lines.push(` bind ${config.sslBind}`)
}
lines.push(` default_backend ${config.frontendBackend}`)
lines.push(``)
// Backend
lines.push(`backend ${config.backendName}`)
lines.push(` balance ${config.balanceType}`)
if (config.backendServer1) {
lines.push(` server ${config.backendServer1}`)
}
if (config.backendServer2) {
lines.push(` server ${config.backendServer2}`)
}
lines.push(``)
// Stats
if (config.enableStats) {
lines.push(`listen stats`)
lines.push(` bind *:8404`)
lines.push(` stats enable`)
lines.push(` stats uri ${config.statsUri}`)
if (config.statsAuthEnable) {
lines.push(` stats auth ${config.statsUser}:${config.statsPassword}`)
}
lines.push(` stats refresh 10s`)
}
return lines.join('\n')
}
+82
View File
@@ -74,6 +74,29 @@ import { syslogSchema, generateSyslogConf } from './syslog'
import { ansibleSchema, generateAnsibleCfg } from './ansible' import { ansibleSchema, generateAnsibleCfg } from './ansible'
import { ansiblePlaybookSchema, generateAnsiblePlaybookYaml } from './ansible-playbook' import { ansiblePlaybookSchema, generateAnsiblePlaybookYaml } from './ansible-playbook'
// ============ CI/CD ============
import { gitlabSchema, generateGitlabRb } from './gitlab'
import { jenkinsSchema, generateJenkinsYaml } from './jenkins'
// ============ 高可用 ============
import { keepalivedSchema, generateKeepalivedConf } from './keepalived'
import { haproxySchema, generateHaproxyCfg } from './haproxy'
import { lvsSchema, generateLvsConf } from './lvs'
// ============ 系统服务 ============
import { ntpSchema, generateNtpConf } from './ntp'
import { dhcpSchema, generateDhcpConf } from './dhcp'
import { bindSchema, generateBindConf } from './bind'
import { nfsSchema, generateNfsExports } from './nfs'
import { sambaSchema, generateSambaConf } from './samba'
import { rsyncSchema, generateRsyncConf } from './rsync'
import { sersyncSchema, generateSersyncXml } from './sersync'
import { vsftpdSchema, generateVsftpdConf } from './vsftpd'
import { subversionSchema, generateSubversionConf } from './subversion'
// ============ 数据库中间件 ============
import { mycatSchema, generateMycatServerXml } from './mycat'
// ============================================================ // ============================================================
// Schema Registry // Schema Registry
// ============================================================ // ============================================================
@@ -139,6 +162,25 @@ export const schemas = {
// 自动化运维 // 自动化运维
ansible: ansibleSchema, ansible: ansibleSchema,
'ansible-playbook': ansiblePlaybookSchema, 'ansible-playbook': ansiblePlaybookSchema,
// CI/CD
gitlab: gitlabSchema,
jenkins: jenkinsSchema,
// 高可用
keepalived: keepalivedSchema,
haproxy: haproxySchema,
lvs: lvsSchema,
// 系统服务
ntp: ntpSchema,
dhcp: dhcpSchema,
bind: bindSchema,
nfs: nfsSchema,
samba: sambaSchema,
rsync: rsyncSchema,
sersync: sersyncSchema,
vsftpd: vsftpdSchema,
subversion: subversionSchema,
// 数据库中间件
mycat: mycatSchema,
} }
// ============================================================ // ============================================================
@@ -190,6 +232,25 @@ export const generators = {
syslog: generateSyslogConf, syslog: generateSyslogConf,
ansible: generateAnsibleCfg, ansible: generateAnsibleCfg,
'ansible-playbook': generateAnsiblePlaybookYaml, 'ansible-playbook': generateAnsiblePlaybookYaml,
// CI/CD
gitlab: generateGitlabRb,
jenkins: generateJenkinsYaml,
// 高可用
keepalived: generateKeepalivedConf,
haproxy: generateHaproxyCfg,
lvs: generateLvsConf,
// 系统服务
ntp: generateNtpConf,
dhcp: generateDhcpConf,
bind: generateBindConf,
nfs: generateNfsExports,
samba: generateSambaConf,
rsync: generateRsyncConf,
sersync: generateSersyncXml,
vsftpd: generateVsftpdConf,
subversion: generateSubversionConf,
// 数据库中间件
mycat: generateMycatServerXml,
} }
// ============================================================ // ============================================================
@@ -277,6 +338,26 @@ export const categories = [
icon: 'Files', icon: 'Files',
items: ['ansible', 'ansible-playbook'], items: ['ansible', 'ansible-playbook'],
}, },
{
name: 'CI/CD',
icon: 'Files',
items: ['gitlab', 'jenkins'],
},
{
name: '高可用',
icon: 'Connection',
items: ['keepalived', 'haproxy', 'lvs'],
},
{
name: '系统服务',
icon: 'Setting',
items: ['ntp', 'dhcp', 'bind', 'nfs', 'samba', 'rsync', 'sersync', 'vsftpd', 'subversion'],
},
{
name: '数据库中间件',
icon: 'Coin',
items: ['mycat'],
},
] ]
// ============================================================ // ============================================================
@@ -299,6 +380,7 @@ export function getLanguage(format) {
cnf: 'ini', cnf: 'ini',
cfg: 'ini', cfg: 'ini',
ora: 'ini', ora: 'ini',
rb: 'ruby',
yml: 'yaml', yml: 'yaml',
yaml: 'yaml', yaml: 'yaml',
json: 'json', json: 'json',
+267
View File
@@ -0,0 +1,267 @@
export const jenkinsSchema = {
id: 'jenkins',
name: 'Jenkins',
icon: 'Setting',
category: 'CI/CD',
description: '开源自动化服务器,支持持续集成与持续交付',
format: 'yml',
fileName: 'jenkins.yaml',
groups: [
{
title: '基础配置',
fields: [
{
key: 'httpPort',
label: 'HTTP 端口',
type: 'number',
min: 1,
max: 65535,
default: 8080,
},
{
key: 'ajpPort',
label: 'AJP 端口',
type: 'number',
default: -1,
tip: '-1 表示禁用 AJP',
},
{
key: 'jenkinsHome',
label: 'JENKINS_HOME 目录',
type: 'text',
default: '/var/lib/jenkins',
},
{
key: 'numExecutors',
label: '执行器数量',
type: 'number',
min: 0,
max: 100,
default: 2,
tip: '同时执行的任务数',
},
{
key: 'mode',
label: '节点模式',
type: 'select',
options: [
{ label: 'normal - 正常模式', value: 'normal' },
{ label: 'exclusive - 仅构建指定任务', value: 'exclusive' },
],
default: 'normal',
},
],
},
{
title: '安全配置',
fields: [
{
key: 'securityRealm',
label: '安全域',
type: 'text',
default: 'default',
tip: '用户认证方式',
},
{
key: 'enableLdap',
label: '启用 LDAP 认证',
type: 'switch',
default: false,
},
{
key: 'ldapServer',
label: 'LDAP 服务器',
type: 'text',
default: 'ldap://ldap.example.com',
dependsOn: { key: 'enableLdap', value: true },
},
{
key: 'ldapRootDn',
label: 'LDAP Root DN',
type: 'text',
default: 'dc=example,dc=com',
dependsOn: { key: 'enableLdap', value: true },
},
{
key: 'authorizationStrategy',
label: '授权策略',
type: 'select',
options: [
{ label: '登录用户可以做任何事', value: 'loggedInUsersCanDoAnything' },
{ label: '项目矩阵授权', value: 'projectMatrix' },
],
default: 'loggedInUsersCanDoAnything',
},
{
key: 'adminUser',
label: '管理员用户名',
type: 'text',
default: 'admin',
},
{
key: 'adminPassword',
label: '管理员密码',
type: 'text',
default: 'admin',
tip: '生产环境请修改默认密码',
},
],
},
{
title: 'JCasC (Configuration as Code)',
fields: [
{
key: 'enableCasc',
label: '启用 JCasC',
type: 'switch',
default: true,
tip: 'Configuration as Code 插件',
},
{
key: 'jenkinsUrl',
label: 'Jenkins URL',
type: 'text',
default: 'http://localhost:8080/',
tip: 'Jenkins 系统 URL',
},
],
},
{
title: 'Agent 配置',
fields: [
{
key: 'enableAgent',
label: '启用 Agent 节点',
type: 'switch',
default: false,
tip: '允许远程 Agent 连接',
},
{
key: 'agentPort',
label: 'Agent 端口',
type: 'number',
min: 1,
max: 65535,
default: 50000,
dependsOn: { key: 'enableAgent', value: true },
},
],
},
{
title: 'Git 与 Gitea 集成',
fields: [
{
key: 'enableGitea',
label: '启用 Gitea 集成',
type: 'switch',
default: false,
},
{
key: 'giteaUrl',
label: 'Gitea 服务器 URL',
type: 'text',
default: 'http://gitea.example.com',
dependsOn: { key: 'enableGitea', value: true },
},
{
key: 'enableGit',
label: '启用 Git',
type: 'switch',
default: true,
},
{
key: 'gitPath',
label: 'Git 可执行文件路径',
type: 'text',
default: '/usr/bin/git',
dependsOn: { key: 'enableGit', value: true },
},
],
},
],
}
export function generateJenkinsYaml(config) {
const lines = []
lines.push(`# Jenkins Configuration as Code - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
lines.push(`jenkins:`)
// System
lines.push(` systemMessage: "Jenkins configured via ConfTemplate"`)
lines.push(` numExecutors: ${config.numExecutors}`)
lines.push(` mode: ${config.mode}`)
lines.push(` jenkinsHome: "${config.jenkinsHome}"`)
lines.push(``)
// Security Realm
if (config.enableLdap) {
lines.push(` securityRealm:`)
lines.push(` ldap:`)
lines.push(` configurations:`)
lines.push(` - server: "${config.ldapServer}"`)
lines.push(` rootDN: "${config.ldapRootDn}"`)
} else {
lines.push(` securityRealm:`)
lines.push(` local:`)
lines.push(` allowsSignup: false`)
lines.push(` users:`)
lines.push(` - id: "${config.adminUser}"`)
lines.push(` password: "${config.adminPassword}"`)
}
lines.push(``)
// Authorization
if (config.authorizationStrategy === 'loggedInUsersCanDoAnything') {
lines.push(` authorizationStrategy:`)
lines.push(` loggedInUsersCanDoAnything:`)
lines.push(` allowAnonymousRead: false`)
} else {
lines.push(` authorizationStrategy:`)
lines.push(` projectMatrix:`)
lines.push(` entries:`)
lines.push(` - user:"${config.adminUser}":`)
lines.push(` permissions:`)
lines.push(` - "Overall/Administer"`)
}
lines.push(``)
// Agent
if (config.enableAgent) {
lines.push(` agent:`)
lines.push(` port: ${config.agentPort}`)
}
// JCasC
if (config.enableCasc) {
lines.push(` configuration-as-code:`)
lines.push(` enabled: true`)
}
lines.push(``)
// URL
lines.push(`unclassified:`)
lines.push(` jenkinsLocationConfiguration:`)
lines.push(` jenkinsUrl: "${config.jenkinsUrl}"`)
lines.push(``)
// Git
if (config.enableGit) {
lines.push(` git:`)
lines.push(` installations:`)
lines.push(` - name: "Default"`)
lines.push(` home: "${config.gitPath}"`)
lines.push(``)
}
// Gitea
if (config.enableGitea) {
lines.push(` giteaServers:`)
lines.push(` servers:`)
lines.push(` - displayName: "Gitea"`)
lines.push(` serverUrl: "${config.giteaUrl}"`)
}
return lines.join('\n')
}
+296
View File
@@ -0,0 +1,296 @@
export const keepalivedSchema = {
id: 'keepalived',
name: 'Keepalived',
icon: 'Connection',
category: '高可用',
description: '基于 VRRP 协议的高可用解决方案,用于 IP 漂移和故障转移',
format: 'conf',
fileName: 'keepalived.conf',
groups: [
{
title: 'VRRP 实例配置',
fields: [
{
key: 'vrrpInstanceName',
label: 'VRRP 实例名称',
type: 'text',
default: 'VI_1',
},
{
key: 'interface',
label: '网络接口',
type: 'text',
default: 'eth0',
tip: '绑定的网络接口名称',
},
{
key: 'state',
label: '初始状态',
type: 'select',
options: [
{ label: 'MASTER - 主节点', value: 'master' },
{ label: 'BACKUP - 备节点', value: 'backup' },
],
default: 'master',
},
{
key: 'virtualRouterId',
label: '虚拟路由 ID',
type: 'number',
min: 1,
max: 255,
default: 51,
tip: '同一组的节点必须相同',
},
{
key: 'priority',
label: '优先级',
type: 'number',
min: 1,
max: 255,
default: 100,
tip: '数值越大优先级越高',
},
{
key: 'advertInt',
label: '通告间隔 (秒)',
type: 'number',
min: 1,
max: 255,
default: 1,
},
],
},
{
title: '认证配置',
fields: [
{
key: 'authType',
label: '认证类型',
type: 'text',
default: 'PASS',
tip: 'PASS 或 AH',
},
{
key: 'authPass',
label: '认证密码',
type: 'text',
default: '1234',
tip: '同一组的节点必须相同',
},
],
},
{
title: '虚拟 IP 配置',
fields: [
{
key: 'virtualIpAddress',
label: '虚拟 IP 地址',
type: 'text',
default: '192.168.1.100/24 dev eth0',
required: true,
tip: '格式: IP/MASK dev 接口',
},
],
},
{
title: '通知脚本',
fields: [
{
key: 'enableNotify',
label: '启用通知脚本',
type: 'switch',
default: false,
tip: '状态切换时执行的脚本',
},
{
key: 'notifyMaster',
label: '切换为 Master 时执行',
type: 'text',
default: "'/etc/keepalived/notify.sh master'",
dependsOn: { key: 'enableNotify', value: true },
},
{
key: 'notifyBackup',
label: '切换为 Backup 时执行',
type: 'text',
default: "'/etc/keepalived/notify.sh backup'",
dependsOn: { key: 'enableNotify', value: true },
},
{
key: 'notifyFault',
label: '进入 Fault 状态时执行',
type: 'text',
default: "'/etc/keepalived/notify.sh fault'",
dependsOn: { key: 'enableNotify', value: true },
},
],
},
{
title: '单播配置',
fields: [
{
key: 'enableVipUnicast',
label: '启用单播',
type: 'switch',
default: false,
tip: '使用单播代替组播通信',
},
{
key: 'unicastPeerIp',
label: '单播对端 IP',
type: 'text',
default: '192.168.1.2',
dependsOn: { key: 'enableVipUnicast', value: true },
},
],
},
{
title: '健康检查',
fields: [
{
key: 'enableHealthCheck',
label: '启用健康检查',
type: 'switch',
default: true,
},
{
key: 'healthCheckType',
label: '检查类型',
type: 'select',
options: [
{ label: 'TCP 端口检查', value: 'tcp' },
{ label: 'HTTP GET 检查', value: 'http_get' },
{ label: 'SSL GET 检查', value: 'ssl_get' },
{ label: 'SMTP 检查', value: 'smtp' },
{ label: 'MISC 自定义检查', value: 'misc_check' },
],
default: 'tcp',
dependsOn: { key: 'enableHealthCheck', value: true },
},
{
key: 'healthCheckUrl',
label: '检查 URL 路径',
type: 'text',
default: '/health',
dependsOn: { key: 'healthCheckType', valueIn: ['http_get', 'ssl_get'] },
},
{
key: 'healthCheckPort',
label: '检查端口',
type: 'number',
min: 1,
max: 65535,
default: 80,
dependsOn: { key: 'enableHealthCheck', value: true },
},
{
key: 'healthCheckTimeout',
label: '超时时间 (秒)',
type: 'number',
min: 1,
max: 30,
default: 3,
dependsOn: { key: 'enableHealthCheck', value: true },
},
{
key: 'healthCheckRetry',
label: '重试次数',
type: 'number',
min: 1,
max: 10,
default: 3,
dependsOn: { key: 'enableHealthCheck', value: true },
},
{
key: 'healthCheckDelayBeforeRetry',
label: '重试间隔 (秒)',
type: 'number',
min: 1,
max: 30,
default: 3,
dependsOn: { key: 'enableHealthCheck', value: true },
},
],
},
],
}
export function generateKeepalivedConf(config) {
const lines = []
lines.push(`# Keepalived 配置文件 - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
// VRRP Script (health check)
if (config.enableHealthCheck) {
lines.push(`vrrp_script chk_service {`)
if (config.healthCheckType === 'tcp') {
lines.push(` script "</dev/tcp/127.0.0.1/${config.healthCheckPort}"`)
} else if (config.healthCheckType === 'http_get') {
lines.push(` script "curl -s http://127.0.0.1:${config.healthCheckPort}${config.healthCheckUrl}"`)
} else if (config.healthCheckType === 'ssl_get') {
lines.push(` script "curl -sk https://127.0.0.1:${config.healthCheckPort}${config.healthCheckUrl}"`)
} else if (config.healthCheckType === 'smtp') {
lines.push(` script "nc -w ${config.healthCheckTimeout} 127.0.0.1 25 < /dev/null"`)
} else {
lines.push(` script "/etc/keepalived/check_script.sh"`)
}
lines.push(` interval ${config.healthCheckTimeout}`)
lines.push(` weight -20`)
lines.push(` fall ${config.healthCheckRetry}`)
lines.push(` rise ${config.healthCheckRetry}`)
lines.push(`}`)
lines.push(``)
}
// VRRP Instance
lines.push(`vrrp_instance ${config.vrrpInstanceName} {`)
lines.push(` state ${config.state.toUpperCase()}`)
lines.push(` interface ${config.interface}`)
lines.push(` virtual_router_id ${config.virtualRouterId}`)
lines.push(` priority ${config.priority}`)
lines.push(` advert_int ${config.advertInt}`)
lines.push(``)
// Auth
lines.push(` authentication {`)
lines.push(` auth_type ${config.authType}`)
lines.push(` auth_pass ${config.authPass}`)
lines.push(` }`)
lines.push(``)
// Virtual IP
lines.push(` virtual_ipaddress {`)
lines.push(` ${config.virtualIpAddress}`)
lines.push(` }`)
lines.push(``)
// Unicast
if (config.enableVipUnicast) {
lines.push(` unicast_src_ip ${config.virtualIpAddress.split('/')[0].trim()}`)
lines.push(` unicast_peer {`)
lines.push(` ${config.unicastPeerIp}`)
lines.push(` }`)
lines.push(``)
}
// Notify
if (config.enableNotify) {
lines.push(` notify_master ${config.notifyMaster}`)
lines.push(` notify_backup ${config.notifyBackup}`)
lines.push(` notify_fault ${config.notifyFault}`)
lines.push(``)
}
// Health check track
if (config.enableHealthCheck) {
lines.push(` track_script {`)
lines.push(` chk_service`)
lines.push(` }`)
}
lines.push(`}`)
return lines.join('\n')
}
+287
View File
@@ -0,0 +1,287 @@
export const lvsSchema = {
id: 'lvs',
name: 'LVS',
icon: 'Connection',
category: '高可用',
description: 'Linux Virtual Server,基于 IP 层的四层负载均衡',
format: 'conf',
fileName: 'lvs-dr.conf',
groups: [
{
title: '虚拟服务配置',
fields: [
{
key: 'vip',
label: '虚拟 IP (VIP)',
type: 'text',
default: '192.168.1.100',
required: true,
tip: '对外提供服务的虚拟 IP',
},
{
key: 'vipPort',
label: '虚拟服务端口',
type: 'number',
min: 1,
max: 65535,
default: 80,
},
{
key: 'protocol',
label: '协议',
type: 'select',
options: [
{ label: 'TCP', value: 'tcp' },
{ label: 'UDP', value: 'udp' },
{ label: 'FTP', value: 'ftp' },
],
default: 'tcp',
},
{
key: 'scheduler',
label: '调度算法',
type: 'select',
options: [
{ label: 'wrr - 加权轮询', value: 'wrr' },
{ label: 'wlc - 加权最少连接 (推荐)', value: 'wlc' },
{ label: 'lc - 最少连接', value: 'lc' },
{ label: 'sh - 源地址哈希', value: 'sh' },
{ label: 'dh - 目标地址哈希', value: 'dh' },
{ label: 'rr - 轮询', value: 'rr' },
],
default: 'wrr',
},
{
key: 'drMode',
label: '转发模式',
type: 'select',
options: [
{ label: 'DR - 直接路由 (推荐)', value: 'dr' },
{ label: 'NAT - 网络地址转换', value: 'nat' },
{ label: 'TUN - IP 隧道', value: 'tun' },
],
default: 'dr',
},
],
},
{
title: 'Real Server 1',
fields: [
{
key: 'realServer1',
label: '真实服务器 1 IP',
type: 'text',
default: '192.168.1.10',
},
{
key: 'realServer1Port',
label: '端口',
type: 'number',
min: 1,
max: 65535,
default: 80,
},
{
key: 'realServer1Weight',
label: '权重',
type: 'number',
min: 0,
max: 256,
default: 1,
},
],
},
{
title: 'Real Server 2',
fields: [
{
key: 'realServer2',
label: '真实服务器 2 IP',
type: 'text',
default: '192.168.1.11',
},
{
key: 'realServer2Port',
label: '端口',
type: 'number',
min: 1,
max: 65535,
default: 80,
},
{
key: 'realServer2Weight',
label: '权重',
type: 'number',
min: 0,
max: 256,
default: 1,
},
],
},
{
title: 'Real Server 3 (可选)',
fields: [
{
key: 'enableRealServer3',
label: '启用第三台服务器',
type: 'switch',
default: false,
},
{
key: 'realServer3',
label: '真实服务器 3 IP',
type: 'text',
default: '192.168.1.12',
dependsOn: { key: 'enableRealServer3', value: true },
},
{
key: 'realServer3Port',
label: '端口',
type: 'number',
min: 1,
max: 65535,
default: 80,
dependsOn: { key: 'enableRealServer3', value: true },
},
{
key: 'realServer3Weight',
label: '权重',
type: 'number',
min: 0,
max: 256,
default: 1,
dependsOn: { key: 'enableRealServer3', value: true },
},
],
},
{
title: '健康检查',
fields: [
{
key: 'enableHealthCheck',
label: '启用健康检查',
type: 'switch',
default: true,
},
{
key: 'healthCheckType',
label: '检查类型',
type: 'select',
options: [
{ label: 'TCP 端口检查', value: 'tcp' },
{ label: 'HTTP GET 检查', value: 'http' },
],
default: 'tcp',
dependsOn: { key: 'enableHealthCheck', value: true },
},
{
key: 'healthCheckUrl',
label: '检查 URL 路径',
type: 'text',
default: '/health',
dependsOn: { key: 'healthCheckType', value: 'http' },
},
{
key: 'healthCheckPort',
label: '检查端口',
type: 'number',
min: 1,
max: 65535,
default: 80,
dependsOn: { key: 'healthCheckType', value: 'http' },
},
],
},
],
}
export function generateLvsConf(config) {
const lines = []
lines.push(`#!/bin/bash`)
lines.push(`# LVS 配置脚本 (ipvsadm 命令) - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(`# 转发模式: ${config.drMode.toUpperCase()}`)
lines.push(``)
lines.push(`# 清除现有规则`)
lines.push(`ipvsadm -C`)
lines.push(``)
// Add VIP
const modeFlag = config.drMode === 'nat' ? '-m' : config.drMode === 'tun' ? '-i' : '-g'
lines.push(`# 添加虚拟服务`)
lines.push(`# VIP: ${config.vip}:${config.vipPort}`)
lines.push(`# 协议: ${config.protocol.toUpperCase()}`)
lines.push(`# 调度算法: ${config.scheduler}`)
lines.push(`ipvsadm -A -t ${config.vip}:${config.vipPort} -s ${config.scheduler}`)
lines.push(``)
// Add real servers
lines.push(`# 添加真实服务器`)
lines.push(`# Real Server 1: ${config.realServer1}:${config.realServer1Port} (weight=${config.realServer1Weight})`)
lines.push(`ipvsadm -a -t ${config.vip}:${config.vipPort} -r ${config.realServer1}:${config.realServer1Port} -w ${config.realServer1Weight} ${modeFlag}`)
lines.push(``)
lines.push(`# Real Server 2: ${config.realServer2}:${config.realServer2Port} (weight=${config.realServer2Weight})`)
lines.push(`ipvsadm -a -t ${config.vip}:${config.vipPort} -r ${config.realServer2}:${config.realServer2Port} -w ${config.realServer2Weight} ${modeFlag}`)
lines.push(``)
if (config.enableRealServer3) {
lines.push(`# Real Server 3: ${config.realServer3}:${config.realServer3Port} (weight=${config.realServer3Weight})`)
lines.push(`ipvsadm -a -t ${config.vip}:${config.vipPort} -r ${config.realServer3}:${config.realServer3Port} -w ${config.realServer3Weight} ${modeFlag}`)
lines.push(``)
}
lines.push(`# 查看当前规则`)
lines.push(`ipvsadm -Ln`)
lines.push(``)
// Health check script
if (config.enableHealthCheck) {
lines.push(`# ============================================================`)
lines.push(`# 健康检查脚本 (保存为 /etc/lvs/check_real_server.sh)`)
lines.push(`# ============================================================`)
lines.push(`cat > /etc/lvs/check_real_server.sh << 'HEALTHCHECK_EOF'`)
lines.push(`#!/bin/bash`)
lines.push(`# LVS 健康检查脚本`)
lines.push(`VIP="${config.vip}"`)
lines.push(`VPORT="${config.vipPort}"`)
lines.push(``)
const servers = [
{ ip: config.realServer1, port: config.realServer1Port, weight: config.realServer1Weight },
{ ip: config.realServer2, port: config.realServer2Port, weight: config.realServer2Weight },
]
if (config.enableRealServer3) {
servers.push({ ip: config.realServer3, port: config.realServer3Port, weight: config.realServer3Weight })
}
for (let i = 0; i < servers.length; i++) {
const rs = servers[i]
lines.push(`# Check Real Server ${i + 1}: ${rs.ip}`)
if (config.healthCheckType === 'tcp') {
lines.push(`if nc -z -w 3 ${rs.ip} ${rs.port} > /dev/null 2>&1; then`)
} else {
lines.push(`if curl -s -o /dev/null -w "%{http_code}" http://${rs.ip}:${config.healthCheckPort}${config.healthCheckUrl} | grep -q "200"; then`)
}
lines.push(` # Server ${rs.ip} is UP`)
lines.push(` ipvsadm -a -t $VIP:$VPORT -r ${rs.ip}:${rs.port} -w ${rs.weight} ${modeFlag} 2>/dev/null`)
lines.push(`else`)
lines.push(` # Server ${rs.ip} is DOWN, removing from pool`)
lines.push(` ipvsadm -d -t $VIP:$VPORT -r ${rs.ip}:${rs.port} 2>/dev/null`)
lines.push(`fi`)
lines.push(``)
}
lines.push(`HEALTHCHECK_EOF`)
lines.push(`chmod +x /etc/lvs/check_real_server.sh`)
lines.push(``)
lines.push(`# 添加 crontab 定时检查 (每 10 秒)`)
lines.push(`# */1 * * * * /etc/lvs/check_real_server.sh`)
lines.push(`# */1 * * * * sleep 10 && /etc/lvs/check_real_server.sh`)
lines.push(`# */1 * * * * sleep 20 && /etc/lvs/check_real_server.sh`)
lines.push(`# */1 * * * * sleep 30 && /etc/lvs/check_real_server.sh`)
lines.push(`# */1 * * * * sleep 40 && /etc/lvs/check_real_server.sh`)
lines.push(`# */1 * * * * sleep 50 && /etc/lvs/check_real_server.sh`)
}
return lines.join('\n')
}
+226
View File
@@ -0,0 +1,226 @@
export const mycatSchema = {
id: 'mycat',
name: 'Mycat',
icon: 'Coin',
category: '数据库中间件',
description: '开源数据库中间件,支持 MySQL 协议',
format: 'xml',
fileName: 'server.xml',
groups: [
{
title: '网络配置',
fields: [
{
key: 'port',
label: '服务端口',
type: 'number',
min: 1,
max: 65535,
default: 8066,
tip: 'MyCat 数据服务端口',
},
{
key: 'managerPort',
label: '管理端口',
type: 'number',
min: 1,
max: 65535,
default: 9066,
tip: 'MyCat 管理服务端口',
},
{
key: 'processors',
label: '处理线程数',
type: 'number',
min: 1,
max: 64,
default: 8,
tip: '建议设为 CPU 核心数',
},
{
key: 'maxConnections',
label: '最大连接数',
type: 'number',
min: 1,
max: 10000,
default: 1000,
},
{
key: 'idleTimeout',
label: '空闲超时 (毫秒)',
type: 'number',
min: 0,
max: 3600000,
step: 1000,
default: 1800000,
tip: '连接空闲超时时间,默认 30 分钟',
},
],
},
{
title: '数据库配置',
fields: [
{
key: 'defaultSchema',
label: '默认 Schema',
type: 'text',
default: 'mydb',
tip: '客户端连接后默认使用的逻辑库',
},
{
key: 'charset',
label: '字符集',
type: 'select',
options: [
{ label: 'utf8mb4 (推荐)', value: 'utf8mb4' },
{ label: 'utf8', value: 'utf8' },
],
default: 'utf8mb4',
},
{
key: 'txIsolation',
label: '事务隔离级别',
type: 'select',
options: [
{ label: '1 - READ_UNCOMMITTED', value: '1' },
{ label: '2 - READ_COMMITTED (推荐)', value: '2' },
{ label: '3 - REPEATABLE_READ', value: '3' },
{ label: '4 - SERIALIZABLE', value: '4' },
],
default: '2',
tip: '1=READ_UNCOMMITTED 2=READ_COMMITTED 3=REPEATABLE_READ 4=SERIALIZABLE',
},
{
key: 'sqlExecuteLimit',
label: 'SQL 执行限制',
type: 'number',
min: 0,
max: 10000,
default: 100,
tip: '单次查询最大执行行数,0 表示不限制',
},
],
},
{
title: '性能与优化',
fields: [
{
key: 'enableGather',
label: '统计 SQL 执行',
type: 'switch',
default: true,
tip: '统计 SQL 执行次数和时间',
},
{
key: 'useCompression',
label: '启用压缩',
type: 'switch',
default: false,
tip: 'MySQL 协议压缩,减少网络传输',
},
],
},
{
title: '用户认证',
fields: [
{
key: 'authUser',
label: '用户名',
type: 'text',
default: 'root',
tip: '连接 MyCat 的用户名',
},
{
key: 'authPassword',
label: '密码',
type: 'text',
default: '123456',
tip: '连接 MyCat 的密码',
},
{
key: 'readOnly',
label: '只读用户',
type: 'switch',
default: false,
tip: '该用户是否只有读权限',
},
],
},
],
}
export function generateMycatServerXml(config) {
const lines = []
lines.push(`<?xml version="1.0" encoding="UTF-8"?>`)
lines.push(`<!-- MyCat server.xml 配置文件 - 由 ConfTemplate 生成 -->`)
lines.push(`<!-- 生成时间: ${new Date().toLocaleString('zh-CN')} -->`)
lines.push(`<!DOCTYPE mycat:server SYSTEM "server.dtd">`)
lines.push(`<mycat:server xmlns:mycat="http://io.mycat/">`)
lines.push(``)
// 系统配置
lines.push(` <system>`)
lines.push(` <property name="serverPort">${config.port}</property>`)
lines.push(` <property name="managerPort">${config.managerPort}</property>`)
lines.push(` <property name="processors">${config.processors}</property>`)
lines.push(` <property name="maxConnections">${config.maxConnections}</property>`)
lines.push(` <property name="idleTimeout">${config.idleTimeout}</property>`)
lines.push(` <property name="defaultSchema">${config.defaultSchema}</property>`)
lines.push(` <property name="characterEncoding">${config.charset}</property>`)
lines.push(` <property name="txIsolation">${config.txIsolation}</property>`)
lines.push(` <property name="sqlExecuteTimeout">${config.sqlExecuteLimit}</property>`)
if (config.enableGather) {
lines.push(` <property name="useSqlStat">1</property>`)
}
if (config.useCompression) {
lines.push(` <property name="handleDistributedTransactions">0</property>`)
lines.push(` <property name="useGlobleTableCheck">0</property>`)
lines.push(` <!-- 压缩配置 -->`)
lines.push(` <property name="packetHeaderSize">4</property>`)
lines.push(` <property name="maxPacketSize">16777216</property>`)
}
lines.push(` </system>`)
lines.push(``)
// 用户配置
lines.push(` <!-- 用户配置 -->`)
lines.push(` <user name="${config.authUser}">`)
lines.push(` <property name="password">${config.authPassword}</property>`)
lines.push(` <property name="schemas">${config.defaultSchema}</property>`)
if (config.readOnly) {
lines.push(` <property name="readOnly">true</property>`)
}
lines.push(` </user>`)
lines.push(``)
// 集群配置注释
lines.push(` <!--`)
lines.push(` 集群配置示例 (在其他节点配置):`)
lines.push(` <cluster>`)
lines.push(` <node name="node1" ip="192.168.1.101" port="3306"/>`)
lines.push(` <node name="node2" ip="192.168.1.102" port="3306"/>`)
lines.push(` </cluster>`)
lines.push(` -->`)
lines.push(``)
// 连接池注释
lines.push(` <!-- 连接池配置示例 (在 schema.xml 中配置): -->`)
lines.push(` <!--`)
lines.push(` <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"`)
lines.push(` writeType="0" dbType="mysql" dbDriver="native">`)
lines.push(` <heartbeat>select user()</heartbeat>`)
lines.push(` <writeHost host="hostM1" url="192.168.1.101:3306"`)
lines.push(` user="root" password="123456"/>`)
lines.push(` </dataHost>`)
lines.push(` -->`)
lines.push(`</mycat:server>`)
return lines.join('\n')
}
+185
View File
@@ -0,0 +1,185 @@
export const nfsSchema = {
id: 'nfs',
name: 'NFS',
icon: 'Files',
category: '系统服务',
description: 'NFS 网络文件系统 exports 配置',
format: 'conf',
fileName: 'exports',
groups: [
{
title: '主共享配置',
fields: [
{
key: 'sharePath',
label: '共享路径',
type: 'text',
default: '/data/share',
tip: '要共享的本地目录路径',
},
{
key: 'clientAddress',
label: '客户端地址',
type: 'text',
default: '192.168.1.0/24',
tip: '允许访问的客户端网段或主机',
},
{
key: 'permissions',
label: '权限',
type: 'select',
options: [
{ label: 'rw - 读写', value: 'rw' },
{ label: 'ro - 只读', value: 'ro' },
],
default: 'rw',
},
{
key: 'rootSquash',
label: 'Root Squash',
type: 'switch',
default: true,
tip: '将 root 用户映射为匿名用户',
},
{
key: 'allSquash',
label: 'All Squash',
type: 'switch',
default: false,
tip: '将所有用户映射为匿名用户',
},
{
key: 'sync',
label: '同步写入',
type: 'switch',
default: true,
tip: '同步写入磁盘,更安全但稍慢',
},
{
key: 'anonuid',
label: '匿名用户 UID',
type: 'number',
min: 0,
max: 65535,
default: 65534,
tip: '匿名用户的 UID',
},
{
key: 'anongid',
label: '匿名用户 GID',
type: 'number',
min: 0,
max: 65535,
default: 65534,
tip: '匿名用户的 GID',
},
],
},
{
title: '附加共享',
fields: [
{
key: 'additionalShares',
label: '启用附加共享',
type: 'switch',
default: false,
tip: '配置第二个 NFS 共享目录',
},
{
key: 'sharePath2',
label: '共享路径 2',
type: 'text',
default: '/data/backup',
dependsOn: { key: 'additionalShares', value: true },
},
{
key: 'clientAddress2',
label: '客户端地址 2',
type: 'text',
default: '10.0.0.0/24',
dependsOn: { key: 'additionalShares', value: true },
},
{
key: 'permissions2',
label: '权限 2',
type: 'select',
options: [
{ label: 'rw - 读写', value: 'rw' },
{ label: 'ro - 只读', value: 'ro' },
],
default: 'ro',
dependsOn: { key: 'additionalShares', value: true },
},
],
},
{
title: 'NFS 版本',
fields: [
{
key: 'enableNfsV4',
label: '启用 NFSv4',
type: 'switch',
default: true,
tip: '使用 NFS 第四版协议',
},
],
},
],
}
export function generateNfsExports(config) {
const lines = []
lines.push(`# NFS exports 配置文件 - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(`# 格式: <目录> <客户端>(<选项>)`)
lines.push(``)
// Build options string for primary share
const buildOptions = (cfg, prefix = '') => {
const perms = cfg[`permissions${prefix}`] || 'rw'
const rootSquash = cfg.rootSquash !== undefined ? cfg.rootSquash : true
const allSquash = cfg.allSquash !== undefined ? cfg.allSquash : false
const sync = cfg.sync !== undefined ? cfg.sync : true
const opts = []
opts.push(perms)
opts.push(sync ? 'sync' : 'async')
opts.push(rootSquash ? 'root_squash' : 'no_root_squash')
if (allSquash) {
opts.push('all_squash')
}
opts.push(`anonuid=${cfg.anonuid || 65534}`)
opts.push(`anongid=${cfg.anongid || 65534}`)
return opts.join(',')
}
// Primary share
lines.push(`# ======================== 主共享 ========================`)
lines.push(`${config.sharePath} ${config.clientAddress}(${buildOptions(config)})`)
lines.push(``)
// Additional share
if (config.additionalShares) {
lines.push(`# ======================== 附加共享 ========================`)
const opts2 = []
opts2.push(config.permissions2 || 'ro')
opts2.push('sync')
opts2.push('root_squash')
opts2.push(`anonuid=${config.anonuid || 65534}`)
opts2.push(`anongid=${config.anongid || 65534}`)
lines.push(`${config.sharePath2} ${config.clientAddress2}(${opts2.join(',')})`)
lines.push(``)
}
// NFSv4 note
if (config.enableNfsV4) {
lines.push(`# ======================== NFSv4 配置提示 ========================`)
lines.push(`# NFSv4 需要在 /etc/exports 中使用 fsid=0 或 fsid=N 来定义导出根`)
lines.push(`# 确保 rpcbind 和 nfs-server 服务已启动:`)
lines.push(`# systemctl enable --now rpcbind nfs-server`)
lines.push(`# 修改后执行: exportfs -ra`)
}
return lines.join('\n')
}
+181
View File
@@ -0,0 +1,181 @@
export const ntpSchema = {
id: 'ntp',
name: 'NTP',
icon: 'Timer',
category: '系统服务',
description: 'NTP 网络时间协议服务配置',
format: 'conf',
fileName: 'ntp.conf',
groups: [
{
title: '时间服务器',
fields: [
{
key: 'server',
label: 'NTP 服务器',
type: 'text',
default: 'pool.ntp.org',
tip: '主 NTP 服务器地址',
},
{
key: 'server2',
label: '备用 NTP 服务器',
type: 'text',
default: 'cn.ntp.org.cn',
tip: '备用 NTP 服务器地址',
},
],
},
{
title: '访问控制',
fields: [
{
key: 'restrict',
label: 'IPv4 访问限制',
type: 'text',
default: '-4 default kod notrap nomodify nopeer noquery limited',
tip: 'IPv4 默认访问控制规则',
},
{
key: 'restrict6',
label: 'IPv6 访问限制',
type: 'text',
default: '-6 default kod notrap nomodify nopeer noquery limited',
tip: 'IPv6 默认访问控制规则',
},
],
},
{
title: '文件路径',
fields: [
{
key: 'driftfile',
label: '漂移文件路径',
type: 'text',
default: '/var/lib/ntp/drift',
tip: '频率补偿文件路径',
},
{
key: 'logfile',
label: '日志文件路径',
type: 'text',
default: '/var/log/ntp.log',
tip: 'NTP 日志文件路径',
},
],
},
{
title: '认证配置',
fields: [
{
key: 'enableAuth',
label: '启用认证',
type: 'switch',
default: false,
tip: '启用 NTP 认证机制',
},
{
key: 'keysFile',
label: '密钥文件路径',
type: 'text',
default: '/etc/ntp/keys',
dependsOn: { key: 'enableAuth', value: true },
tip: 'NTP 认证密钥文件',
},
],
},
{
title: '性能调优',
fields: [
{
key: 'tinkerPanic',
label: 'Tinker Panic 阈值',
type: 'number',
min: 0,
max: 1000,
default: 0,
tip: '0=永不 panic,超过此秒数偏移将 panic',
},
{
key: 'burst',
label: '启用 Burst 模式',
type: 'switch',
default: false,
tip: '在网络正常时发送一批请求以提高精度',
},
{
key: 'minpoll',
label: '最小轮询间隔 (2^n 秒)',
type: 'number',
min: 3,
max: 17,
default: 6,
tip: '最小轮询间隔指数,3=8秒',
},
{
key: 'maxpoll',
label: '最大轮询间隔 (2^n 秒)',
type: 'number',
min: 3,
max: 17,
default: 10,
tip: '最大轮询间隔指数,10=1024秒',
},
],
},
],
}
export function generateNtpConf(config) {
const lines = []
lines.push(`# NTP 配置文件 - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
// Time servers
lines.push(`# ======================== 时间服务器 ========================`)
lines.push(`server ${config.server} iburst minpoll ${config.minpoll} maxpoll ${config.maxpoll}`)
lines.push(`server ${config.server2} iburst minpoll ${config.minpoll} maxpoll ${config.maxpoll}`)
lines.push(``)
// Access control
lines.push(`# ======================== 访问控制 ========================`)
lines.push(`restrict ${config.restrict}`)
lines.push(`restrict ${config.restrict6}`)
lines.push(`restrict 127.0.0.1`)
lines.push(`restrict ::1`)
lines.push(``)
// File paths
lines.push(`# ======================== 文件路径 ========================`)
lines.push(`driftfile ${config.driftfile}`)
lines.push(`logfile ${config.logfile}`)
lines.push(``)
// Authentication
if (config.enableAuth) {
lines.push(`# ======================== 认证配置 ========================`)
lines.push(`enable auth`)
lines.push(`keys ${config.keysFile}`)
lines.push(``)
}
// Performance
lines.push(`# ======================== 性能调优 ========================`)
if (config.tinkerPanic > 0) {
lines.push(`tinker panic ${config.tinkerPanic}`)
} else {
lines.push(`tinker panic 0`)
}
if (config.burst) {
lines.push(`burst`)
}
lines.push(``)
// Leap second
lines.push(`# ======================== 其他 ========================`)
lines.push(`# 闰秒文件(如需要)`)
lines.push(`# leapfile /usr/share/zoneinfo/leap-seconds.list`)
return lines.join('\n')
}
+196
View File
@@ -0,0 +1,196 @@
export const rsyncSchema = {
id: 'rsync',
name: 'RSYNC',
icon: 'Files',
category: '系统服务',
description: '快速增量文件传输工具',
format: 'conf',
fileName: 'rsyncd.conf',
groups: [
{
title: '全局配置',
fields: [
{
key: 'uid',
label: '用户 (uid)',
type: 'text',
default: 'root',
tip: '传输文件时使用的用户',
},
{
key: 'gid',
label: '用户组 (gid)',
type: 'text',
default: 'root',
tip: '传输文件时使用的用户组',
},
{
key: 'useChroot',
label: '使用 chroot',
type: 'switch',
default: false,
tip: '是否限制在根目录下,提高安全性',
},
{
key: 'port',
label: '监听端口',
type: 'number',
min: 1,
max: 65535,
default: 873,
},
{
key: 'maxConnections',
label: '最大连接数',
type: 'number',
min: 1,
max: 1000,
default: 10,
},
{
key: 'timeout',
label: '超时时间 (秒)',
type: 'number',
min: 0,
max: 3600,
default: 300,
tip: 'I/O 超时时间',
},
{
key: 'logFile',
label: '日志文件路径',
type: 'text',
default: '/var/log/rsyncd.log',
},
{
key: 'pidFile',
label: 'PID 文件路径',
type: 'text',
default: '/var/run/rsyncd.pid',
},
],
},
{
title: '模块配置',
fields: [
{
key: 'enableModule',
label: '启用共享模块',
type: 'switch',
default: true,
tip: '是否配置共享模块',
},
{
key: 'moduleName',
label: '模块名称',
type: 'text',
default: 'backup',
dependsOn: { key: 'enableModule', value: true },
tip: '客户端访问时使用的模块名',
},
{
key: 'modulePath',
label: '模块路径',
type: 'text',
default: '/data/backup',
dependsOn: { key: 'enableModule', value: true },
tip: '共享目录的绝对路径',
},
{
key: 'moduleComment',
label: '模块注释',
type: 'text',
default: 'Backup Area',
dependsOn: { key: 'enableModule', value: true },
},
{
key: 'readOnly',
label: '只读模式',
type: 'switch',
default: false,
dependsOn: { key: 'enableModule', value: true },
},
{
key: 'list',
label: '允许列出模块',
type: 'switch',
default: true,
dependsOn: { key: 'enableModule', value: true },
tip: '客户端是否可以列出可用模块',
},
],
},
{
title: '认证与安全',
fields: [
{
key: 'authUsers',
label: '授权用户',
type: 'text',
default: 'backup_user',
tip: '多个用户用逗号分隔',
},
{
key: 'secretsFile',
label: '密码文件路径',
type: 'text',
default: '/etc/rsyncd.secrets',
tip: '格式: 用户名:密码,每行一个',
},
{
key: 'hostsAllow',
label: '允许的主机',
type: 'text',
default: '192.168.1.0/24',
tip: 'IP 或网段,多个用逗号或空格分隔',
},
{
key: 'hostsDeny',
label: '拒绝的主机',
type: 'text',
default: '*',
tip: '* 表示拒绝所有未明确允许的主机',
},
],
},
],
}
export function generateRsyncConf(config) {
const lines = []
lines.push(`# rsyncd.conf 配置文件 - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
// 全局配置
lines.push(`# ======================== 全局配置 ========================`)
lines.push(`uid = ${config.uid}`)
lines.push(`gid = ${config.gid}`)
lines.push(`use chroot = ${config.useChroot ? 'true' : 'false'}`)
lines.push(`port = ${config.port}`)
lines.push(`max connections = ${config.maxConnections}`)
lines.push(`timeout = ${config.timeout}`)
lines.push(`log file = ${config.logFile}`)
lines.push(`pid file = ${config.pidFile}`)
lines.push(``)
// 模块配置
if (config.enableModule) {
lines.push(`# ======================== 模块配置 ========================`)
lines.push(`[${config.moduleName}]`)
lines.push(` comment = ${config.moduleComment}`)
lines.push(` path = ${config.modulePath}`)
lines.push(` read only = ${config.readOnly ? 'true' : 'false'}`)
lines.push(` list = ${config.list ? 'true' : 'false'}`)
lines.push(``)
}
// 认证与安全
lines.push(`# ======================== 认证与安全 ========================`)
lines.push(`auth users = ${config.authUsers}`)
lines.push(`secrets file = ${config.secretsFile}`)
lines.push(`hosts allow = ${config.hostsAllow}`)
lines.push(`hosts deny = ${config.hostsDeny}`)
return lines.join('\n')
}
+233
View File
@@ -0,0 +1,233 @@
export const sambaSchema = {
id: 'samba',
name: 'SAMBA',
icon: 'Files',
category: '系统服务',
description: 'Samba 文件共享服务配置',
format: 'conf',
fileName: 'smb.conf',
groups: [
{
title: '全局设置',
fields: [
{
key: 'workgroup',
label: '工作组',
type: 'text',
default: 'WORKGROUP',
tip: 'Windows 工作组名称',
},
{
key: 'serverString',
label: '服务器描述',
type: 'text',
default: 'Samba Server',
tip: '服务器的描述字符串',
},
{
key: 'netbiosName',
label: 'NetBIOS 名称',
type: 'text',
default: 'smbserver',
tip: '网络中显示的计算机名',
},
{
key: 'securityType',
label: '安全模式',
type: 'select',
options: [
{ label: 'user - 用户级认证 (推荐)', value: 'user' },
{ label: 'share - 共享级认证', value: 'share' },
{ label: 'domain - 域认证', value: 'domain' },
],
default: 'user',
},
{
key: 'mapToGuest',
label: '访客映射',
type: 'text',
default: 'Bad User',
tip: '认证失败时映射为 guest 用户',
},
],
},
{
title: '共享目录',
fields: [
{
key: 'enableShare',
label: '启用共享',
type: 'switch',
default: true,
tip: '配置一个共享目录',
},
{
key: 'shareName',
label: '共享名称',
type: 'text',
default: 'share',
dependsOn: { key: 'enableShare', value: true },
tip: '网络访问路径中的共享名',
},
{
key: 'sharePath',
label: '共享路径',
type: 'text',
default: '/data/samba',
dependsOn: { key: 'enableShare', value: true },
},
{
key: 'shareComment',
label: '共享注释',
type: 'text',
default: 'Shared Folder',
dependsOn: { key: 'enableShare', value: true },
},
{
key: 'browseable',
label: '可浏览',
type: 'switch',
default: true,
dependsOn: { key: 'enableShare', value: true },
tip: '是否在网络中可见',
},
{
key: 'writable',
label: '可写',
type: 'switch',
default: true,
dependsOn: { key: 'enableShare', value: true },
},
{
key: 'guestOk',
label: '允许匿名访问',
type: 'switch',
default: false,
dependsOn: { key: 'enableShare', value: true },
},
{
key: 'validUsers',
label: '有效用户',
type: 'text',
default: 'user1 user2',
dependsOn: { key: 'enableShare', value: true },
tip: '允许访问的用户列表,空格分隔',
},
],
},
{
title: '权限掩码',
fields: [
{
key: 'createMask',
label: '文件创建掩码',
type: 'text',
default: '0664',
tip: '新建文件的权限掩码',
},
{
key: 'directoryMask',
label: '目录创建掩码',
type: 'text',
default: '0775',
tip: '新建目录的权限掩码',
},
],
},
{
title: '日志配置',
fields: [
{
key: 'enableLogging',
label: '启用日志',
type: 'switch',
default: true,
},
{
key: 'logFile',
label: '日志文件',
type: 'text',
default: '/var/log/samba/log.%m',
dependsOn: { key: 'enableLogging', value: true },
tip: '%m 会被替换为客户端机器名',
},
{
key: 'maxLogSize',
label: '最大日志大小 (KB)',
type: 'number',
min: 0,
max: 100000,
default: 5000,
dependsOn: { key: 'enableLogging', value: true },
tip: '0 表示不限制',
},
],
},
],
}
export function generateSambaConf(config) {
const lines = []
lines.push(`# Samba 配置文件 - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
// Global section
lines.push(`# ======================== 全局设置 ========================`)
lines.push(`[global]`)
lines.push(` workgroup = ${config.workgroup}`)
lines.push(` server string = ${config.serverString}`)
lines.push(` netbios name = ${config.netbiosName}`)
lines.push(` security = ${config.securityType}`)
lines.push(` map to guest = ${config.mapToGuest}`)
lines.push(``)
// Logging
if (config.enableLogging) {
lines.push(` # 日志配置`)
lines.push(` log file = ${config.logFile}`)
if (config.maxLogSize > 0) {
lines.push(` max log size = ${config.maxLogSize}`)
}
lines.push(``)
}
// Performance tuning
lines.push(` # 性能优化`)
lines.push(` socket options = TCP_NODELAY IPTOS_LOWDELAY`)
lines.push(` load printers = no`)
lines.push(` printing = bsd`)
lines.push(` printcap name = /dev/null`)
lines.push(` disable spoolss = yes`)
lines.push(``)
// Share section
if (config.enableShare) {
lines.push(`# ======================== 共享目录 ========================`)
lines.push(`[${config.shareName}]`)
lines.push(` comment = ${config.shareComment}`)
lines.push(` path = ${config.sharePath}`)
lines.push(` browseable = ${config.browseable ? 'yes' : 'no'}`)
lines.push(` writable = ${config.writable ? 'yes' : 'no'}`)
lines.push(` guest ok = ${config.guestOk ? 'yes' : 'no'}`)
if (!config.guestOk && config.validUsers) {
const users = config.validUsers.split(/\s+/).filter(Boolean).join(', ')
lines.push(` valid users = ${users}`)
}
lines.push(` create mask = ${config.createMask}`)
lines.push(` directory mask = ${config.directoryMask}`)
lines.push(``)
}
// Tips
lines.push(`# ======================== 使用提示 ========================`)
lines.push(`# 1. 添加 Samba 用户: smbpasswd -a <username>`)
lines.push(`# 2. 确保目录存在: mkdir -p ${config.enableShare ? config.sharePath : '/data/samba'}`)
lines.push(`# 3. 设置权限: chmod 775 ${config.enableShare ? config.sharePath : '/data/samba'}`)
lines.push(`# 4. 重启服务: systemctl restart smb nmb`)
lines.push(`# 5. 测试配置: testparm`)
return lines.join('\n')
}
+256
View File
@@ -0,0 +1,256 @@
export const sersyncSchema = {
id: 'sersync',
name: 'Sersync',
icon: 'Refresh',
category: '系统服务',
description: '基于 inotify + rsync 的实时文件同步工具',
format: 'xml',
fileName: 'confxml.xml',
groups: [
{
title: '基础配置',
fields: [
{
key: 'watchPath',
label: '监控目录',
type: 'text',
default: '/data/web',
tip: '需要实时同步的本地目录',
},
{
key: 'localDebug',
label: '本地调试模式',
type: 'switch',
default: false,
tip: '开启后仅记录日志不执行同步',
},
],
},
{
title: 'Rsync 配置',
fields: [
{
key: 'rsyncCommand',
label: 'Rsync 命令路径',
type: 'text',
default: '/usr/bin/rsync',
},
{
key: 'rsyncArgs',
label: 'Rsync 参数',
type: 'text',
default: '-avz --delete',
tip: '常用的 rsync 同步参数',
},
{
key: 'rsyncUser',
label: 'Rsync 用户',
type: 'text',
default: 'root',
},
{
key: 'remoteHosts',
label: '远程主机列表',
type: 'text',
default: '192.168.1.101::backup 192.168.1.102::backup',
tip: '格式: IP::模块名,多个用空格分隔',
},
{
key: 'remotePassword',
label: '密码文件路径',
type: 'text',
default: '/etc/rsyncd.secrets',
},
],
},
{
title: 'SSH 配置',
fields: [
{
key: 'enableSsh',
label: '启用 SSH 传输',
type: 'switch',
default: false,
tip: '使用 SSH 代替 rsync daemon 传输',
},
{
key: 'sshPort',
label: 'SSH 端口',
type: 'number',
min: 1,
max: 65535,
default: 22,
dependsOn: { key: 'enableSsh', value: true },
},
],
},
{
title: '监控配置',
fields: [
{
key: 'enableMonitor',
label: '开启 HTTP 监控',
type: 'switch',
default: true,
tip: '提供 HTTP 接口查看同步状态',
},
{
key: 'monitorPort',
label: '监控端口',
type: 'number',
min: 1,
max: 65535,
default: 8008,
dependsOn: { key: 'enableMonitor', value: true },
},
{
key: 'failLog',
label: '失败日志脚本',
type: 'text',
default: '/tmp/rsync_fail_log.sh',
tip: '同步失败时执行的脚本',
},
],
},
{
title: '定时任务与过滤',
fields: [
{
key: 'enableCron',
label: '启用定时同步',
type: 'switch',
default: true,
tip: '定时执行全量同步作为兜底',
},
{
key: 'cronInterval',
label: '定时同步间隔 (秒)',
type: 'number',
min: 60,
max: 86400,
default: 600,
dependsOn: { key: 'enableCron', value: true },
tip: '每隔多少秒执行一次全量同步',
},
{
key: 'filterRule',
label: '启用过滤规则',
type: 'switch',
default: false,
tip: '过滤不需要同步的文件',
},
{
key: 'filterExpression',
label: '过滤表达式',
type: 'text',
default: '*.tmp *.temp',
dependsOn: { key: 'filterRule', value: true },
tip: '匹配的文件不同步,空格分隔',
},
],
},
],
}
export function generateSersyncXml(config) {
const lines = []
lines.push(`<?xml version="1.0" encoding="UTF-8"?>`)
lines.push(`<!-- Sersync 配置文件 - 由 ConfTemplate 生成 -->`)
lines.push(`<!-- 生成时间: ${new Date().toLocaleString('zh-CN')} -->`)
lines.push(`<head>`)
lines.push(` <host hostip="localhost" port="8008"></host>`)
lines.push(` <filter start="false">`)
if (config.filterRule && config.filterExpression) {
const expressions = config.filterExpression.split(/\s+/).filter(Boolean)
for (const expr of expressions) {
lines.push(` <exclude expression="${expr}"></exclude>`)
}
}
lines.push(` </filter>`)
lines.push(` <inotify start="true">`)
lines.push(` <delete start="true"/>`)
lines.push(` <createFolder start="true"/>`)
lines.push(` <createFile start="false"/>`)
lines.push(` <closeWrite start="true"/>`)
lines.push(` <moveFrom start="true"/>`)
lines.push(` <moveTo start="true"/>`)
lines.push(` <attrib start="false"/>`)
lines.push(` <modify start="false"/>`)
lines.push(` </inotify>`)
lines.push(` <sersync>`)
lines.push(` <localpath watch="${config.watchPath}">`)
// 解析远程主机列表
const hosts = config.remoteHosts.split(/\s+/).filter(Boolean)
for (const host of hosts) {
if (config.enableSsh) {
const parts = host.split('::')
const ip = parts[0]
const remotePath = parts[1] || '/data/backup'
lines.push(` <remote ip="${ip}" name="${remotePath}"/>`)
} else {
const parts = host.split('::')
const ip = parts[0]
const module = parts[1] || 'backup'
lines.push(` <remote ip="${ip}" name="${module}"/>`)
}
}
lines.push(` </localpath>`)
lines.push(` <rsync>`)
lines.push(` <commonParams params="${config.rsyncArgs}"/>`)
if (config.enableSsh) {
lines.push(` <ssh start="true" port="${config.sshPort}"/>`)
}
lines.push(` <userDefinedPort start="false" port="874"/><!-- rsync daemon 端口 -->`)
lines.push(` <auth start="${config.rsyncUser ? 'true' : 'false'}" users="${config.rsyncUser}" passwordfile="${config.remotePassword}"/>`)
lines.push(` <userDefinedPort start="false" port="874"/>`)
lines.push(` <timeout start="true" time="1000"/><!-- timeout in ms -->`)
lines.push(` </rsync>`)
if (config.enableMonitor) {
lines.push(` <failLog path="${config.failLog}" timeToExecute="60"/><!-- 每60秒检查一次失败日志 -->`)
} else {
lines.push(` <failLog path="${config.failLog}" timeToExecute="60"/>`)
}
if (config.enableCron) {
lines.push(` <crontab start="true" schedule="${Math.floor(config.cronInterval / 60)}"><!-- 分钟 -->`)
lines.push(` <crontabfilter start="false">`)
if (config.filterRule && config.filterExpression) {
const expressions = config.filterExpression.split(/\s+/).filter(Boolean)
for (const expr of expressions) {
lines.push(` <exclude expression="${expr}"></exclude>`)
}
}
lines.push(` </crontabfilter>`)
lines.push(` </crontab>`)
} else {
lines.push(` <crontab start="false" schedule="600">`)
lines.push(` <crontabfilter start="false">`)
lines.push(` </crontabfilter>`)
lines.push(` </crontab>`)
}
lines.push(` <plugin start="false" name="command"/>`)
lines.push(` </sersync>`)
lines.push(` <plugin name="command">`)
lines.push(` <param prefix="/bin/sh" suffix="" ignoreError="true"/>`)
lines.push(` <filter start="false">`)
lines.push(` <include expression="(.*)\.php"/>`)
lines.push(` <include expression="(.*)\.sh"/>`)
lines.push(` </filter>`)
lines.push(` </plugin>`)
lines.push(` <plugin name="socket">`)
lines.push(` <localpath watch="/opt/tongbu">`)
lines.push(` <deshost ip="192.168.1.101" port="8009"/>`)
lines.push(` </localpath>`)
lines.push(` </plugin>`)
lines.push(`</head>`)
return lines.join('\n')
}
+224
View File
@@ -0,0 +1,224 @@
export const subversionSchema = {
id: 'subversion',
name: 'Subversion (SVN)',
icon: 'Files',
category: '系统服务',
description: '集中式版本控制系统',
format: 'conf',
fileName: 'svnserve.conf',
groups: [
{
title: '访问控制',
fields: [
{
key: 'anonAccess',
label: '匿名访问权限',
type: 'select',
options: [
{ label: 'none - 禁止匿名访问 (推荐)', value: 'none' },
{ label: 'read - 匿名用户只读', value: 'read' },
{ label: 'write - 匿名用户可写', value: 'write' },
],
default: 'none',
},
{
key: 'authAccess',
label: '认证用户权限',
type: 'select',
options: [
{ label: 'write - 认证用户可写 (推荐)', value: 'write' },
{ label: 'read - 认证用户只读', value: 'read' },
],
default: 'write',
},
{
key: 'passwordDb',
label: '密码数据库文件',
type: 'text',
default: 'passwd',
tip: '相对于 conf 目录的路径',
},
{
key: 'authzDb',
label: '权限数据库文件',
type: 'text',
default: 'authz',
tip: '相对于 conf 目录的路径',
},
{
key: 'realm',
label: '认证域',
type: 'text',
default: 'My Repository',
tip: '认证域名称,用于区分不同的仓库',
},
{
key: 'listenPort',
label: '监听端口',
type: 'number',
min: 1,
max: 65535,
default: 3690,
},
],
},
{
title: 'SASL 认证',
fields: [
{
key: 'enableSasl',
label: '启用 SASL 认证',
type: 'switch',
default: false,
tip: '使用 SASL 框架进行认证,支持更高级的加密',
},
{
key: 'saslRealm',
label: 'SASL 域',
type: 'text',
default: '',
dependsOn: { key: 'enableSasl', value: true },
tip: 'SASL 认证域,留空使用默认',
},
{
key: 'minEncryption',
label: '最小加密强度',
type: 'number',
min: 0,
max: 256,
default: 0,
dependsOn: { key: 'enableSasl', value: true },
tip: '0=不加密, 1=仅完整性, 128=128位, 256=256位',
},
{
key: 'maxEncryption',
label: '最大加密强度',
type: 'number',
min: 0,
max: 256,
default: 256,
dependsOn: { key: 'enableSasl', value: true },
tip: '0=不加密, 1=仅完整性, 128=128位, 256=256位',
},
],
},
{
title: '钩子脚本',
fields: [
{
key: 'enableHooks',
label: '启用钩子脚本',
type: 'switch',
default: false,
tip: '在特定 SVN 事件时执行自定义脚本',
},
{
key: 'hookType',
label: '钩子类型',
type: 'select',
options: [
{ label: 'post-commit - 提交后执行 (推荐)', value: 'post-commit' },
{ label: 'pre-commit - 提交前执行', value: 'pre-commit' },
],
default: 'post-commit',
dependsOn: { key: 'enableHooks', value: true },
},
{
key: 'hookScript',
label: '钩子脚本内容',
type: 'text',
default: '#!/bin/sh\n/usr/bin/svn update /var/www/html',
dependsOn: { key: 'enableHooks', value: true },
tip: '钩子脚本的完整内容',
},
],
},
],
}
export function generateSubversionConf(config) {
const lines = []
lines.push(`# svnserve.conf 配置文件 - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(`#`)
lines.push(`# 将此文件放置在仓库的 conf/ 目录下`)
lines.push(`# 启动命令: svnserve -d -r /path/to/repos --listen-port ${config.listenPort}`)
lines.push(``)
// 通用配置
lines.push(`[general]`)
// 匿名访问
lines.push(`# 匿名访问权限`)
lines.push(`anon-access = ${config.anonAccess}`)
lines.push(``)
// 认证用户访问
lines.push(`# 认证用户访问权限`)
lines.push(`auth-access = ${config.authAccess}`)
lines.push(``)
// 密码数据库
lines.push(`# 密码数据库`)
lines.push(`password-db = ${config.passwordDb}`)
lines.push(``)
// 权限数据库
lines.push(`# 权限数据库`)
lines.push(`authz-db = ${config.authzDb}`)
lines.push(``)
// 认证域
lines.push(`# 认证域`)
lines.push(`realm = ${config.realm}`)
lines.push(``)
// SASL 认证
if (config.enableSasl) {
lines.push(`[sasl]`)
lines.push(`# 启用 SASL 认证`)
lines.push(`use-sasl = true`)
if (config.saslRealm) {
lines.push(`sasl-realm = ${config.saslRealm}`)
}
lines.push(`min-encryption = ${config.minEncryption}`)
lines.push(`max-encryption = ${config.maxEncryption}`)
lines.push(``)
}
// 钩子脚本说明
if (config.enableHooks) {
lines.push(`# ======================== 钩子脚本 ========================`)
lines.push(`# 以下为 ${config.hookType} 钩子脚本`)
lines.push(`# 请将此内容保存为: <仓库路径>/hooks/${config.hookType}`)
lines.push(`# 并确保有执行权限: chmod +x <仓库路径>/hooks/${config.hookType}`)
lines.push(`#`)
lines.push(`# ---- 脚本内容开始 ----`)
lines.push(config.hookScript)
lines.push(`# ---- 脚本内容结束 ----`)
lines.push(`#`)
}
// passwd 文件示例
lines.push(`# ======================== 附录 ========================`)
lines.push(`# passwd 文件示例 (${config.passwordDb}):`)
lines.push(`# [users]`)
lines.push(`# admin = admin123`)
lines.push(`# developer = dev123`)
lines.push(`#`)
lines.push(`# authz 文件示例 (${config.authzDb}):`)
lines.push(`# [groups]`)
lines.push(`# admin = admin`)
lines.push(`# developers = developer`)
lines.push(`#`)
lines.push(`# [/]`)
lines.push(`# @admin = rw`)
lines.push(`# * = ${config.anonAccess === 'none' ? '' : config.anonAccess}`)
lines.push(`#`)
lines.push(`# [/trunk]`)
lines.push(`# @developers = rw`)
return lines.join('\n')
}
+296
View File
@@ -0,0 +1,296 @@
export const vsftpdSchema = {
id: 'vsftpd',
name: 'vsftpd',
icon: 'Upload',
category: '系统服务',
description: '非常安全的 FTP 守护进程',
format: 'conf',
fileName: 'vsftpd.conf',
groups: [
{
title: '基础配置',
fields: [
{
key: 'listenPort',
label: '监听端口',
type: 'number',
min: 1,
max: 65535,
default: 21,
},
{
key: 'anonymousEnable',
label: '允许匿名访问',
type: 'switch',
default: false,
tip: '生产环境建议关闭',
},
{
key: 'localEnable',
label: '允许本地用户登录',
type: 'switch',
default: true,
},
{
key: 'writeEnable',
label: '允许写操作',
type: 'switch',
default: true,
tip: 'FTP 写命令权限 (STOR, DELE 等)',
},
{
key: 'localUmask',
label: '本地用户 umask',
type: 'text',
default: '022',
tip: '新建文件/目录的权限掩码',
},
],
},
{
title: '用户限制',
fields: [
{
key: 'chrootLocalUser',
label: '限制用户在家目录',
type: 'switch',
default: true,
tip: 'chroot 将用户限制在其主目录',
},
{
key: 'allowWriteableChroot',
label: '允许可写 chroot',
type: 'switch',
default: true,
dependsOn: { key: 'chrootLocalUser', value: true },
tip: 'chroot 目录可写时需要开启',
},
{
key: 'maxClients',
label: '最大客户端数',
type: 'number',
min: 1,
max: 10000,
default: 100,
},
{
key: 'maxPerIp',
label: '单 IP 最大连接数',
type: 'number',
min: 1,
max: 100,
default: 5,
},
{
key: 'idleSessionTimeout',
label: '空闲会话超时 (秒)',
type: 'number',
min: 30,
max: 3600,
default: 300,
},
{
key: 'dataConnectionTimeout',
label: '数据连接超时 (秒)',
type: 'number',
min: 30,
max: 3600,
default: 120,
},
],
},
{
title: '被动模式',
fields: [
{
key: 'pasvEnable',
label: '启用被动模式',
type: 'switch',
default: true,
tip: '防火墙/NAT 后的客户端需要被动模式',
},
{
key: 'pasvMinPort',
label: '被动模式最小端口',
type: 'number',
min: 1024,
max: 65535,
default: 30000,
dependsOn: { key: 'pasvEnable', value: true },
},
{
key: 'pasvMaxPort',
label: '被动模式最大端口',
type: 'number',
min: 1024,
max: 65535,
default: 30100,
dependsOn: { key: 'pasvEnable', value: true },
},
],
},
{
title: 'TLS/SSL 安全',
fields: [
{
key: 'enableTls',
label: '启用 TLS/SSL',
type: 'switch',
default: false,
tip: '通过 FTPS 加密传输',
},
{
key: 'rsaCertFile',
label: 'SSL 证书路径',
type: 'text',
default: '/etc/ssl/certs/vsftpd.pem',
dependsOn: { key: 'enableTls', value: true },
},
{
key: 'rsaPrivateKeyFile',
label: 'SSL 私钥路径',
type: 'text',
default: '/etc/ssl/private/vsftpd.key',
dependsOn: { key: 'enableTls', value: true },
},
{
key: 'sslTlsv1',
label: '启用 TLSv1',
type: 'switch',
default: true,
dependsOn: { key: 'enableTls', value: true },
},
],
},
{
title: '用户列表与日志',
fields: [
{
key: 'userlistEnable',
label: '启用用户列表',
type: 'switch',
default: true,
},
{
key: 'userlistDeny',
label: '用户列表为黑名单',
type: 'switch',
default: false,
dependsOn: { key: 'userlistEnable', value: true },
tip: 'false=白名单 (允许列表中用户), true=黑名单 (拒绝列表中用户)',
},
{
key: 'logEnable',
label: '启用日志',
type: 'switch',
default: true,
},
{
key: 'xferlogFile',
label: '传输日志路径',
type: 'text',
default: '/var/log/vsftpd.log',
dependsOn: { key: 'logEnable', value: true },
},
{
key: 'asciiUploadEnable',
label: 'ASCII 上传模式',
type: 'switch',
default: false,
tip: '允许 ASCII 模式上传',
},
{
key: 'asciiDownloadEnable',
label: 'ASCII 下载模式',
type: 'switch',
default: false,
tip: '允许 ASCII 模式下载',
},
{
key: 'ftpdBanner',
label: '欢迎横幅',
type: 'text',
default: 'Welcome to FTP service',
tip: '用户登录时显示的欢迎信息',
},
],
},
],
}
export function generateVsftpdConf(config) {
const lines = []
lines.push(`# vsftpd.conf 配置文件 - 由 ConfTemplate 生成`)
lines.push(`# 生成时间: ${new Date().toLocaleString('zh-CN')}`)
lines.push(``)
// 基础配置
lines.push(`# ======================== 基础配置 ========================`)
lines.push(`listen=YES`)
lines.push(`listen_port=${config.listenPort}`)
lines.push(`anonymous_enable=${config.anonymousEnable ? 'YES' : 'NO'}`)
lines.push(`local_enable=${config.localEnable ? 'YES' : 'NO'}`)
lines.push(`write_enable=${config.writeEnable ? 'YES' : 'NO'}`)
lines.push(`local_umask=${config.localUmask}`)
lines.push(`dirmessage_enable=YES`)
lines.push(`use_localtime=YES`)
lines.push(`xferlog_enable=YES`)
lines.push(`connect_from_port_20=YES`)
lines.push(``)
// 用户限制
lines.push(`# ======================== 用户限制 ========================`)
lines.push(`chroot_local_user=${config.chrootLocalUser ? 'YES' : 'NO'}`)
if (config.chrootLocalUser) {
lines.push(`allow_writeable_chroot=${config.allowWriteableChroot ? 'YES' : 'NO'}`)
}
lines.push(`max_clients=${config.maxClients}`)
lines.push(`max_per_ip=${config.maxPerIp}`)
lines.push(`idle_session_timeout=${config.idleSessionTimeout}`)
lines.push(`data_connection_timeout=${config.dataConnectionTimeout}`)
lines.push(``)
// 被动模式
lines.push(`# ======================== 被动模式 ========================`)
lines.push(`pasv_enable=${config.pasvEnable ? 'YES' : 'NO'}`)
if (config.pasvEnable) {
lines.push(`pasv_min_port=${config.pasvMinPort}`)
lines.push(`pasv_max_port=${config.pasvMaxPort}`)
}
lines.push(``)
// TLS/SSL 安全
lines.push(`# ======================== TLS/SSL 安全 ========================`)
if (config.enableTls) {
lines.push(`ssl_enable=YES`)
lines.push(`rsa_cert_file=${config.rsaCertFile}`)
lines.push(`rsa_private_key_file=${config.rsaPrivateKeyFile}`)
lines.push(`ssl_tlsv1=${config.sslTlsv1 ? 'YES' : 'NO'}`)
lines.push(`ssl_sslv2=NO`)
lines.push(`ssl_sslv3=NO`)
lines.push(`require_ssl_reuse=NO`)
lines.push(`ssl_ciphers=HIGH`)
} else {
lines.push(`ssl_enable=NO`)
}
lines.push(``)
// 用户列表与日志
lines.push(`# ======================== 用户列表与日志 ========================`)
lines.push(`userlist_enable=${config.userlistEnable ? 'YES' : 'NO'}`)
if (config.userlistEnable) {
lines.push(`userlist_deny=${config.userlistDeny ? 'YES' : 'NO'}`)
}
lines.push(`log_enable=${config.logEnable ? 'YES' : 'NO'}`)
if (config.logEnable) {
lines.push(`xferlog_file=${config.xferlogFile}`)
lines.push(`xferlog_std_format=YES`)
}
lines.push(`ascii_upload_enable=${config.asciiUploadEnable ? 'YES' : 'NO'}`)
lines.push(`ascii_download_enable=${config.asciiDownloadEnable ? 'YES' : 'NO'}`)
lines.push(`ftpd_banner=${config.ftpdBanner}`)
lines.push(`pam_service_name=vsftpd`)
lines.push(`tcp_wrappers=YES`)
return lines.join('\n')
}