feat: complete nginx migration from caddy
- Replace Caddy reverse proxy with Nginx (nginx:alpine) - Add nginx.conf with HTTP/HTTPS, gzip, and proxy settings - Add nginx-custom-domains.conf template for custom domains - Update docker-compose.yml to use Nginx service - Add ProxyFix middleware to Flask app for proper header handling - Create nginx_config_reader.py utility to read Nginx configuration - Update admin blueprint to display Nginx status in https_config page - Add Nginx configuration display to https_config.html template - Generate self-signed SSL certificates for localhost - Add utility scripts: generate_nginx_certs.sh - Add documentation: NGINX_SETUP_QUICK.md, PROXY_FIX_SETUP.md - All containers now running, HTTPS working, HTTP redirects to HTTPS - Session cookies marked as Secure - Security headers properly configured
This commit is contained in:
120
app/utils/nginx_config_reader.py
Normal file
120
app/utils/nginx_config_reader.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""Nginx configuration reader utility."""
|
||||
import os
|
||||
import re
|
||||
from typing import Dict, List, Optional, Any
|
||||
|
||||
|
||||
class NginxConfigReader:
|
||||
"""Read and parse Nginx configuration files."""
|
||||
|
||||
def __init__(self, config_path: str = '/etc/nginx/nginx.conf'):
|
||||
"""Initialize Nginx config reader."""
|
||||
self.config_path = config_path
|
||||
self.config_content = None
|
||||
self.is_available = os.path.exists(config_path)
|
||||
|
||||
if self.is_available:
|
||||
try:
|
||||
with open(config_path, 'r') as f:
|
||||
self.config_content = f.read()
|
||||
except Exception as e:
|
||||
self.is_available = False
|
||||
self.error = str(e)
|
||||
|
||||
def get_status(self) -> Dict[str, Any]:
|
||||
"""Get Nginx configuration status."""
|
||||
if not self.is_available:
|
||||
return {
|
||||
'available': False,
|
||||
'error': 'Nginx configuration not found',
|
||||
'path': self.config_path
|
||||
}
|
||||
|
||||
return {
|
||||
'available': True,
|
||||
'path': self.config_path,
|
||||
'file_exists': os.path.exists(self.config_path),
|
||||
'ssl_enabled': self._check_ssl_enabled(),
|
||||
'http_ports': self._extract_http_ports(),
|
||||
'https_ports': self._extract_https_ports(),
|
||||
'upstream_servers': self._extract_upstream_servers(),
|
||||
'server_names': self._extract_server_names(),
|
||||
'ssl_protocols': self._extract_ssl_protocols(),
|
||||
'client_max_body_size': self._extract_client_max_body_size(),
|
||||
'gzip_enabled': self._check_gzip_enabled(),
|
||||
}
|
||||
|
||||
def _check_ssl_enabled(self) -> bool:
|
||||
"""Check if SSL is enabled."""
|
||||
if not self.config_content:
|
||||
return False
|
||||
return 'ssl_certificate' in self.config_content
|
||||
|
||||
def _extract_http_ports(self) -> List[int]:
|
||||
"""Extract HTTP listening ports."""
|
||||
if not self.config_content:
|
||||
return []
|
||||
pattern = r'listen\s+(\d+)'
|
||||
matches = re.findall(pattern, self.config_content)
|
||||
return sorted(list(set(int(p) for p in matches if int(p) < 1000)))
|
||||
|
||||
def _extract_https_ports(self) -> List[int]:
|
||||
"""Extract HTTPS listening ports."""
|
||||
if not self.config_content:
|
||||
return []
|
||||
pattern = r'listen\s+(\d+).*ssl'
|
||||
matches = re.findall(pattern, self.config_content)
|
||||
return sorted(list(set(int(p) for p in matches)))
|
||||
|
||||
def _extract_upstream_servers(self) -> List[str]:
|
||||
"""Extract upstream servers."""
|
||||
if not self.config_content:
|
||||
return []
|
||||
upstream_match = re.search(r'upstream\s+\w+\s*{([^}]+)}', self.config_content)
|
||||
if upstream_match:
|
||||
upstream_content = upstream_match.group(1)
|
||||
servers = re.findall(r'server\s+([^\s;]+)', upstream_content)
|
||||
return servers
|
||||
return []
|
||||
|
||||
def _extract_server_names(self) -> List[str]:
|
||||
"""Extract server names."""
|
||||
if not self.config_content:
|
||||
return []
|
||||
pattern = r'server_name\s+([^;]+);'
|
||||
matches = re.findall(pattern, self.config_content)
|
||||
result = []
|
||||
for match in matches:
|
||||
names = match.strip().split()
|
||||
result.extend(names)
|
||||
return result
|
||||
|
||||
def _extract_ssl_protocols(self) -> List[str]:
|
||||
"""Extract SSL protocols."""
|
||||
if not self.config_content:
|
||||
return []
|
||||
pattern = r'ssl_protocols\s+([^;]+);'
|
||||
match = re.search(pattern, self.config_content)
|
||||
if match:
|
||||
return match.group(1).strip().split()
|
||||
return []
|
||||
|
||||
def _extract_client_max_body_size(self) -> Optional[str]:
|
||||
"""Extract client max body size."""
|
||||
if not self.config_content:
|
||||
return None
|
||||
pattern = r'client_max_body_size\s+([^;]+);'
|
||||
match = re.search(pattern, self.config_content)
|
||||
return match.group(1).strip() if match else None
|
||||
|
||||
def _check_gzip_enabled(self) -> bool:
|
||||
"""Check if gzip is enabled."""
|
||||
if not self.config_content:
|
||||
return False
|
||||
return bool(re.search(r'gzip\s+on\s*;', self.config_content))
|
||||
|
||||
|
||||
def get_nginx_status() -> Dict[str, Any]:
|
||||
"""Get Nginx configuration status."""
|
||||
reader = NginxConfigReader()
|
||||
return reader.get_status()
|
||||
Reference in New Issue
Block a user