diff --git a/config/nginx.conf.template b/config/nginx.conf.template index fb0b5ef..36dbe65 100644 --- a/config/nginx.conf.template +++ b/config/nginx.conf.template @@ -35,10 +35,11 @@ http { } location ~ \.php$ { + # Use $request_filename for consistent behavior across global and project configs + include "{{CONF_DIR}}/fastcgi_params"; fastcgi_pass 127.0.0.1:{{PHP_PORT}}; fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - include "{{CONF_DIR}}/fastcgi_params"; + fastcgi_param SCRIPT_FILENAME $request_filename; } } } diff --git a/config/nginx_project.conf.template b/config/nginx_project.conf.template index 9861540..c89de7f 100644 --- a/config/nginx_project.conf.template +++ b/config/nginx_project.conf.template @@ -11,12 +11,12 @@ location ^~ /{{HOST}}/ { fastcgi_pass 127.0.0.1:{{PHP_PORT}}; fastcgi_index index.php; - # Correctly split path to get the relative script path - fastcgi_split_path_info ^/{{HOST}}(.+\.php)(.*)$; - fastcgi_param SCRIPT_FILENAME "{{PATH}}$fastcgi_script_name"; - fastcgi_param DOCUMENT_ROOT "{{PATH}}"; - fastcgi_param PATH_INFO $fastcgi_path_info; - + # Correctly use $request_filename for alias compatibility include "{{CONF_DIR}}/fastcgi_params"; + fastcgi_param SCRIPT_FILENAME $request_filename; + fastcgi_param DOCUMENT_ROOT $document_root; + + # Optional parameters for frameworks + fastcgi_param PATH_INFO $fastcgi_path_info; } } diff --git a/src/main/ipc/index.ts b/src/main/ipc/index.ts index 17e955b..db1dfc3 100644 --- a/src/main/ipc/index.ts +++ b/src/main/ipc/index.ts @@ -28,25 +28,93 @@ function findExecutable(dir: string, name: string): string | null { return null } +async function rebuildNginxConfig(forceProjects: boolean = false): Promise<{ binPath: string; nginxPrefix: string; configPath: string }> { + const settings = configService.getSettings() + const binDir = path.join(configService.getBasePath(), 'bin') + const nginxDir = path.join(binDir, 'nginx') + const nginxVersions = fs.readdirSync(nginxDir).filter(f => fs.statSync(path.join(nginxDir, f)).isDirectory()) + const activeVersion = nginxVersions[0] + if (!activeVersion) throw new Error('Nginx sürümü bulunamadı.') + + const nginxPrefix = path.join(nginxDir, activeVersion) + const binPath = path.join(nginxPrefix, 'nginx.exe') + const confDir = path.join(nginxPrefix, 'conf') + const logDir = path.join(configService.getBasePath(), 'logs') + const rootPath = path.join(app.getAppPath(), 'www') + + // Ensure directories exist + const projectsConfDir = path.join(configService.getBasePath(), 'generated_configs', 'projects') + if (!fs.existsSync(projectsConfDir)) fs.mkdirSync(projectsConfDir, { recursive: true }) + + const tempDirs = ['temp', 'temp/client_body_temp', 'temp/proxy_temp', 'temp/fastcgi_temp', 'temp/uwsgi_temp', 'temp/scgi_temp', 'logs'] + for (const dir of tempDirs) { + const fullDir = path.join(nginxPrefix, dir) + if (!fs.existsSync(fullDir)) fs.mkdirSync(fullDir, { recursive: true }) + } + + // Generate project configs + const projects = await projectService.getProjects() + for (const p of projects) { + const projectConfPath = path.join(projectsConfDir, `${p.host}.conf`) + if (forceProjects || !fs.existsSync(projectConfPath)) { + const phpPort = portMappingService.getPhpPort(p.phpVersion) + const normalizedPath = p.path.replace(/\\/g, '/') + await configService.generateConfig('nginx_project.conf.template', `projects/${p.host}.conf`, { + HOST: p.host, + PATH: normalizedPath, + PHP_PORT: phpPort.toString(), + CONF_DIR: confDir.replace(/\\/g, '/') + }) + } + } + + const projectsInclusion = projects.length > 0 + ? `include "${projectsConfDir.replace(/\\/g, '/')}/*.conf";` + : '' + + const configPath = await configService.generateConfig('nginx.conf.template', 'nginx.conf', { + PORT: settings.nginxPort, + PHP_PORT: settings.phpPort, + ROOT: rootPath, + LOG_DIR: logDir.replace(/\\/g, '/'), + CONF_DIR: confDir.replace(/\\/g, '/'), + PHPMYADMIN_DIR: phpMyAdminService.getPath().replace(/\\/g, '/'), + PROJECTS: projectsInclusion + }) + + return { binPath, nginxPrefix, configPath } +} + +async function restartNginx(): Promise<{ success: boolean; message: string }> { + try { + const { binPath, nginxPrefix, configPath } = await rebuildNginxConfig(false) + + // Force kill Nginx to ensure it picks up new config on Windows + await processManager.forceKillAll('nginx') + + // Start service + const success = await processManager.startService('nginx', binPath, ['-p', nginxPrefix, '-c', configPath], false) + + if (success) { + return { success: true, message: 'Nginx restart successful' } + } else { + const errorLogs = await processManager.getLastErrorLogs('nginx') + return { success: false, message: `Nginx restart failed:\n${errorLogs.join('\n')}` } + } + } catch (error: any) { + return { success: false, message: `Restart hatası: ${error.message}` } + } +} async function reloadNginx(): Promise<{ success: boolean; message: string }> { try { - const binDir = path.join(configService.getBasePath(), 'bin') - const nginxDir = path.join(binDir, 'nginx') - const nginxVersions = fs.readdirSync(nginxDir).filter(f => fs.statSync(path.join(nginxDir, f)).isDirectory()) - const activeVersion = nginxVersions[0] - if (!activeVersion) throw new Error('Nginx sürümü bulunamadı.') - - const nginxPrefix = path.join(nginxDir, activeVersion) - const binPath = path.join(nginxPrefix, 'nginx.exe') - const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf') - + const { binPath, nginxPrefix, configPath } = await rebuildNginxConfig(false) const result = await processManager.runOnce(binPath, ['-p', nginxPrefix, '-c', configPath, '-s', 'reload'], 'nginx') if (result.success) { console.log('Nginx reload successful') return { success: true, message: 'Nginx reloaded' } } else { - console.error('Nginx reload failed:', result.output) - return { success: false, message: result.output || 'Nginx reload failed' } + // Fallback to full restart if reload fails (common on Windows) + return await restartNginx() } } catch (error: any) { return { success: false, message: `Reload hatası: ${error.message}` } @@ -66,67 +134,7 @@ export function registerIpcHandlers(): void { const binDir = path.join(configService.getBasePath(), 'bin') if (serviceName === 'nginx') { - const rootPath = path.join(app.getAppPath(), 'www') - const nginxDir = path.join(binDir, 'nginx') - const binPath = findExecutable(nginxDir, 'nginx.exe') - const logDir = path.join(configService.getBasePath(), 'logs') - - if (!binPath) return { success: false, message: 'Nginx executable bulunamadı. Lütfen indirin.' } - - // Nginx prefix = directory containing nginx.exe - const nginxPrefix = path.dirname(binPath) - const confDir = path.join(nginxPrefix, 'conf') - - // Ensure temp directories exist (Nginx needs these) - const tempDirs = ['temp', 'temp/client_body_temp', 'temp/proxy_temp', 'temp/fastcgi_temp', 'temp/uwsgi_temp', 'temp/scgi_temp', 'logs'] - for (const dir of tempDirs) { - const fullDir = path.join(nginxPrefix, dir) - if (!fs.existsSync(fullDir)) { - fs.mkdirSync(fullDir, { recursive: true }) - } - } - - const projects = await projectService.getProjects() - const projectsConfDir = path.join(configService.getBasePath(), 'generated_configs', 'projects') - if (!fs.existsSync(projectsConfDir)) fs.mkdirSync(projectsConfDir, { recursive: true }) - - // Clean up old project configs - const existingFiles = fs.readdirSync(projectsConfDir) - for (const file of existingFiles) { - fs.unlinkSync(path.join(projectsConfDir, file)) - } - - for (const p of projects) { - const phpPort = portMappingService.getPhpPort(p.phpVersion) - const normalizedPath = p.path.replace(/\\/g, '/') - await configService.generateConfig('nginx_project.conf.template', `projects/${p.host}.conf`, { - HOST: p.host, - PATH: normalizedPath, - PHP_PORT: phpPort.toString(), - CONF_DIR: confDir.replace(/\\/g, '/') - }) - } - - const projectsInclusion = projects.length > 0 - ? `include "${projectsConfDir.replace(/\\/g, '/')}/*.conf";` - : '' - - const configPath = await configService.generateConfig('nginx.conf.template', 'nginx.conf', { - PORT: settings.nginxPort, - PHP_PORT: settings.phpPort, - ROOT: rootPath, - LOG_DIR: logDir.replace(/\\/g, '/'), - CONF_DIR: confDir.replace(/\\/g, '/'), - PHPMYADMIN_DIR: phpMyAdminService.getPath().replace(/\\/g, '/'), - PROJECTS: projectsInclusion - }) - - // Test config first with prefix - const testResult = await processManager.runOnce(binPath, ['-t', '-p', nginxPrefix, '-c', configPath], 'nginx') - if (!testResult.success) { - console.error('Nginx config test failed before reload:', testResult.output) - return { success: false, message: `Nginx config error: ${testResult.output}` } - } + const { binPath, nginxPrefix, configPath } = await rebuildNginxConfig(false) const success = await processManager.startService('nginx', binPath, ['-p', nginxPrefix, '-c', configPath], false) @@ -383,21 +391,28 @@ export function registerIpcHandlers(): void { ipcMain.handle('projects:add', async (_event, project) => { const result = await projectService.addProject(project) - // Trigger Nginx reload - await ipcMain.emit('services:reload', null, 'nginx') + // Trigger Nginx restart to generate initial config and apply + await restartNginx() return result }) ipcMain.handle('projects:remove', async (_event, id) => { const result = projectService.removeProject(id) - // Trigger Nginx reload - await ipcMain.emit('services:reload', null, 'nginx') + // Trigger Nginx restart to remove config from glob inclusion indirectly + // Actually we might want to delete the .conf file too + const projects = await projectService.getProjects() + const projectToRemove = projects.find(p => p.id === id) + if (projectToRemove) { + const configPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${projectToRemove.host}.conf`) + if (fs.existsSync(configPath)) fs.unlinkSync(configPath) + } + await restartNginx() return result }) ipcMain.handle('projects:update', async (_event, project) => { const result = projectService.updateProject(project) - // Trigger Nginx reload - await ipcMain.emit('services:reload', null, 'nginx') + // Trigger Nginx restart + await restartNginx() return result }) @@ -423,8 +438,8 @@ export function registerIpcHandlers(): void { ipcMain.handle('nginx:config:save', async (_event, content) => { const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf') fs.writeFileSync(configPath, content) - // Reload Nginx after save - return await reloadNginx() + // Full restart after manual global save + return await restartNginx() }) ipcMain.handle('nginx:config:test', async () => { @@ -496,8 +511,8 @@ export function registerIpcHandlers(): void { ipcMain.handle('project:nginx:save', async (_event, host, content) => { const configPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${host}.conf`) fs.writeFileSync(configPath, content) - // Reload Nginx after save - return await reloadNginx() + // Full restart after manual project save + return await restartNginx() }) // phpMyAdmin