feat: implement IPC handlers for Nginx and Apache configuration management and service lifecycle control

This commit is contained in:
Ümit Tunç
2026-04-01 20:43:11 +03:00
parent da1640c334
commit 2bc793662e
5 changed files with 89 additions and 17 deletions
+27
View File
@@ -1,9 +1,15 @@
Define SRVROOT "{{SRVROOT}}" Define SRVROOT "{{SRVROOT}}"
ServerRoot "${SRVROOT}"
Listen {{LISTEN_ADDRESS}}:{{PORT}} Listen {{LISTEN_ADDRESS}}:{{PORT}}
# Temel Modüller
LoadModule authz_core_module modules/mod_authz_core.so LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_host_module modules/mod_authz_host.so LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule dir_module modules/mod_dir.so LoadModule dir_module modules/mod_dir.so
LoadModule mime_module modules/mod_mime.so LoadModule mime_module modules/mod_mime.so
LoadModule alias_module modules/mod_alias.so LoadModule alias_module modules/mod_alias.so
@@ -11,6 +17,17 @@ LoadModule log_config_module modules/mod_log_config.so
LoadModule rewrite_module modules/mod_rewrite.so LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule setenvif_module modules/mod_setenvif.so
# Önerilen Ek Modüller
LoadModule headers_module modules/mod_headers.so
LoadModule env_module modules/mod_env.so
LoadModule deflate_module modules/mod_deflate.so
# Windows optimizations
AcceptFilter http none
AcceptFilter https none
# Required for PHP-FPM on Windows to avoid "No input file specified" # Required for PHP-FPM on Windows to avoid "No input file specified"
<IfModule proxy_fcgi_module> <IfModule proxy_fcgi_module>
@@ -20,6 +37,15 @@ LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
ServerAdmin admin@localhost ServerAdmin admin@localhost
ServerName localhost:{{PORT}} ServerName localhost:{{PORT}}
# MIME Types (Kritik)
TypesConfig conf/mime.types
# Ana Güvenlik Kuralı (Tüm disk erişimini kapat)
<Directory />
AllowOverride none
Require all denied
</Directory>
DocumentRoot "{{ROOT}}" DocumentRoot "{{ROOT}}"
<Directory "{{ROOT}}"> <Directory "{{ROOT}}">
Options Indexes FollowSymLinks Options Indexes FollowSymLinks
@@ -58,6 +84,7 @@ Alias /phpmyadmin "{{PHPMYADMIN_DIR}}"
# Global PHP handler # Global PHP handler
<FilesMatch \.php$> <FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:{{PHP_PORT}}/" SetHandler "proxy:fcgi://127.0.0.1:{{PHP_PORT}}/"
CGIPassAuth On
</FilesMatch> </FilesMatch>
# Project configurations # Project configurations
+2
View File
@@ -45,6 +45,8 @@ session.save_path = "{{SESSION_DIR}}"
upload_tmp_dir = "{{TEMP_DIR}}" upload_tmp_dir = "{{TEMP_DIR}}"
sys_temp_dir = "{{TEMP_DIR}}" sys_temp_dir = "{{TEMP_DIR}}"
extension_dir = "{{EXT_DIR}}" extension_dir = "{{EXT_DIR}}"
cgi.force_redirect = 0
cgi.fix_pathinfo = 1
[ExtensionList] [ExtensionList]
{{EXTENSIONS}} {{EXTENSIONS}}
+1 -1
View File
@@ -5,7 +5,7 @@
"phpPort": "9001", "phpPort": "9001",
"mariaDbPort": "3306", "mariaDbPort": "3306",
"mariaDbPorts": {}, "mariaDbPorts": {},
"allowRemoteAccess": true, "allowRemoteAccess": false,
"language": "tr", "language": "tr",
"mysqlPort": "3306", "mysqlPort": "3306",
"mysqlPorts": {} "mysqlPorts": {}
+14 -3
View File
@@ -161,12 +161,13 @@ async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ bi
const configPath = path.join(configService.getBasePath(), 'generated_configs', 'httpd.conf') const configPath = path.join(configService.getBasePath(), 'generated_configs', 'httpd.conf')
// Check if manual edit exists // Check if manual edit exists for global config
let skipGlobal = false
if (fs.existsSync(configPath) && !forceProjects) { if (fs.existsSync(configPath) && !forceProjects) {
const content = fs.readFileSync(configPath, 'utf8') const content = fs.readFileSync(configPath, 'utf8')
if (content.includes('# MANUAL_EDIT')) { if (content.includes('# MANUAL_EDIT')) {
console.log('Skipping Apache config generation (Manual Edit detected)') console.log('Skipping Apache global config generation (Manual Edit detected)')
return { binPath, apacheDir, configPath } skipGlobal = true
} }
} }
@@ -181,6 +182,14 @@ async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ bi
const projectConfPath = path.join(projectsConfDir, `${p.host}.conf`) const projectConfPath = path.join(projectsConfDir, `${p.host}.conf`)
let shouldGenerate = forceProjects || !fs.existsSync(projectConfPath) let shouldGenerate = forceProjects || !fs.existsSync(projectConfPath)
// If file exists, check if it was manually edited (though we don't have a UI for this yet, good for future)
if (!shouldGenerate && fs.existsSync(projectConfPath)) {
const currentContent = fs.readFileSync(projectConfPath, 'utf8')
if (!currentContent.includes('# MANUAL_EDIT')) {
shouldGenerate = true
}
}
if (shouldGenerate) { if (shouldGenerate) {
const phpPort = portMappingService.getPhpPort(p.phpVersion) const phpPort = portMappingService.getPhpPort(p.phpVersion)
let normalizedPath = p.path.replace(/\\/g, '/') let normalizedPath = p.path.replace(/\\/g, '/')
@@ -194,6 +203,7 @@ async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ bi
} }
} }
if (!skipGlobal) {
const projectsInclusion = projects.length > 0 const projectsInclusion = projects.length > 0
? `Include "${projectsConfDir.replace(/\\/g, '/')}/*.conf"` ? `Include "${projectsConfDir.replace(/\\/g, '/')}/*.conf"`
: '' : ''
@@ -208,6 +218,7 @@ async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ bi
PHPMYADMIN_DIR: phpMyAdminService.getPath().replace(/\\/g, '/'), PHPMYADMIN_DIR: phpMyAdminService.getPath().replace(/\\/g, '/'),
PROJECTS: projectsInclusion PROJECTS: projectsInclusion
}) })
}
return { binPath, apacheDir, configPath } return { binPath, apacheDir, configPath }
} }
+32
View File
@@ -259,8 +259,40 @@ export class PhpManagerService {
} }
fs.writeFileSync(iniPath, finalLines.join('\n'), 'utf8') fs.writeFileSync(iniPath, finalLines.join('\n'), 'utf8')
await this.ensureFcgiSettings(version)
return { success: true, message: `Extension ${extName} ${enabled ? 'enabled' : 'disabled'}` } return { success: true, message: `Extension ${extName} ${enabled ? 'enabled' : 'disabled'}` }
} }
async ensureFcgiSettings(version: string): Promise<boolean> {
const phpDir = path.join(this.binDir, `php-${version}`)
const iniPath = path.join(phpDir, 'php.ini')
if (!fs.existsSync(iniPath)) return false
let content = fs.readFileSync(iniPath, 'utf8')
const lines = content.split(/\r?\n/)
let forceRedirectSet = false
let fixPathinfoSet = false
const newLines = lines.map(line => {
const trimmed = line.trim()
if (trimmed.startsWith('cgi.force_redirect') || trimmed.startsWith(';cgi.force_redirect')) {
forceRedirectSet = true
return 'cgi.force_redirect = 0'
}
if (trimmed.startsWith('cgi.fix_pathinfo') || trimmed.startsWith(';cgi.fix_pathinfo')) {
fixPathinfoSet = true
return 'cgi.fix_pathinfo = 1'
}
return line
})
if (!forceRedirectSet) newLines.push('cgi.force_redirect = 0')
if (!fixPathinfoSet) newLines.push('cgi.fix_pathinfo = 1')
fs.writeFileSync(iniPath, newLines.join('\n'), 'utf8')
return true
}
} }
export const phpManagerService = new PhpManagerService() export const phpManagerService = new PhpManagerService()