🎉 Added production setup documentation and scripts, improved firewall configuration, and updated systemd services for production environment. 🖥️🔒📡
This commit is contained in:
1
backend/PRODUCTION_HTTPS_SETUP.md
Normal file
1
backend/PRODUCTION_HTTPS_SETUP.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
@@ -1 +1,412 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
MYP Druckerverwaltung - OPTIMIERTE PRODUKTIONS-VERSION
|
||||||
|
=====================================================
|
||||||
|
|
||||||
|
Standalone Flask App für Raspberry Pi Produktionsbetrieb:
|
||||||
|
- Nur HTTPS Port 443 (kein HTTP Port 5000)
|
||||||
|
- Browser-kompatible SSL-Zertifikate
|
||||||
|
- Optimierte Performance für Kiosk-Modus
|
||||||
|
- Minimale Firewall-Exposition
|
||||||
|
- Keine Proxy-Dependencies
|
||||||
|
|
||||||
|
Version: 5.0.0 Production
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import ssl
|
||||||
|
import logging
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
# Füge App-Verzeichnis zum Python-Pfad hinzu
|
||||||
|
sys.path.insert(0, '/opt/myp')
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
# Import der Haupt-App
|
||||||
|
from app import app, app_logger
|
||||||
|
|
||||||
|
# SSL und Sicherheits-Imports
|
||||||
|
from utils.ssl_config import ensure_ssl_certificates, get_ssl_context
|
||||||
|
|
||||||
|
# =========================== PRODUKTIONS-KONFIGURATION ===========================
|
||||||
|
|
||||||
|
class ProductionConfig:
|
||||||
|
"""Optimierte Produktions-Konfiguration für Raspberry Pi"""
|
||||||
|
|
||||||
|
# HTTPS-Only Konfiguration
|
||||||
|
FORCE_HTTPS = True
|
||||||
|
SSL_REQUIRED = True
|
||||||
|
HTTPS_PORT = 443
|
||||||
|
HTTP_DISABLED = True
|
||||||
|
|
||||||
|
# Performance-Optimierungen
|
||||||
|
DEBUG = False
|
||||||
|
TESTING = False
|
||||||
|
OPTIMIZED_MODE = True
|
||||||
|
USE_MINIFIED_ASSETS = True
|
||||||
|
DISABLE_ANIMATIONS = True
|
||||||
|
|
||||||
|
# Sicherheits-Einstellungen
|
||||||
|
SESSION_COOKIE_SECURE = True
|
||||||
|
SESSION_COOKIE_HTTPONLY = True
|
||||||
|
SESSION_COOKIE_SAMESITE = 'Strict'
|
||||||
|
WTF_CSRF_ENABLED = True
|
||||||
|
|
||||||
|
# SSL-Konfiguration
|
||||||
|
SSL_CERT_PATH = '/opt/myp/ssl/cert.pem'
|
||||||
|
SSL_KEY_PATH = '/opt/myp/ssl/key.pem'
|
||||||
|
|
||||||
|
# Firewall-freundliche Konfiguration
|
||||||
|
SINGLE_PORT_MODE = True
|
||||||
|
NO_ADDITIONAL_PORTS = True
|
||||||
|
|
||||||
|
# Wende Produktions-Konfiguration an
|
||||||
|
app.config.from_object(ProductionConfig)
|
||||||
|
|
||||||
|
# =========================== SSL-SETUP ===========================
|
||||||
|
|
||||||
|
def setup_production_ssl():
|
||||||
|
"""Stelle sicher, dass browser-kompatible SSL-Zertifikate vorhanden sind"""
|
||||||
|
|
||||||
|
ssl_dir = '/opt/myp/ssl'
|
||||||
|
cert_file = f'{ssl_dir}/cert.pem'
|
||||||
|
key_file = f'{ssl_dir}/key.pem'
|
||||||
|
|
||||||
|
app_logger.info("🔐 Prüfe SSL-Zertifikate für Produktionsbetrieb...")
|
||||||
|
|
||||||
|
# Erstelle SSL-Verzeichnis
|
||||||
|
os.makedirs(ssl_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Prüfe ob Zertifikate existieren und gültig sind
|
||||||
|
cert_valid = False
|
||||||
|
if os.path.exists(cert_file) and os.path.exists(key_file):
|
||||||
|
try:
|
||||||
|
# Prüfe Zertifikat-Gültigkeit
|
||||||
|
import subprocess
|
||||||
|
result = subprocess.run([
|
||||||
|
'openssl', 'x509', '-in', cert_file, '-noout', '-checkend', '86400'
|
||||||
|
], capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
# Prüfe Browser-Kompatibilität
|
||||||
|
cert_info = subprocess.run([
|
||||||
|
'openssl', 'x509', '-in', cert_file, '-noout', '-text'
|
||||||
|
], capture_output=True, text=True)
|
||||||
|
|
||||||
|
if ('Digital Signature' in cert_info.stdout and
|
||||||
|
'Key Encipherment' in cert_info.stdout and
|
||||||
|
'TLS Web Server Authentication' in cert_info.stdout and
|
||||||
|
'Subject Alternative Name' in cert_info.stdout):
|
||||||
|
cert_valid = True
|
||||||
|
app_logger.info("✅ Browser-kompatible SSL-Zertifikate gefunden")
|
||||||
|
else:
|
||||||
|
app_logger.warning("⚠️ SSL-Zertifikate nicht browser-kompatibel")
|
||||||
|
else:
|
||||||
|
app_logger.warning("⚠️ SSL-Zertifikate abgelaufen")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.warning(f"⚠️ SSL-Zertifikat-Prüfung fehlgeschlagen: {e}")
|
||||||
|
|
||||||
|
# Erstelle neue browser-kompatible Zertifikate falls nötig
|
||||||
|
if not cert_valid:
|
||||||
|
app_logger.info("🔧 Erstelle neue browser-kompatible SSL-Zertifikate...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Führe SSL-Fix-Skript aus falls vorhanden
|
||||||
|
ssl_fix_script = '/opt/myp/fix_ssl_raspberry.sh'
|
||||||
|
if os.path.exists(ssl_fix_script):
|
||||||
|
import subprocess
|
||||||
|
result = subprocess.run(['sudo', ssl_fix_script],
|
||||||
|
capture_output=True, text=True, timeout=60)
|
||||||
|
if result.returncode == 0:
|
||||||
|
app_logger.info("✅ SSL-Fix-Skript erfolgreich ausgeführt")
|
||||||
|
else:
|
||||||
|
app_logger.error(f"❌ SSL-Fix-Skript Fehler: {result.stderr}")
|
||||||
|
raise Exception("SSL-Fix-Skript fehlgeschlagen")
|
||||||
|
else:
|
||||||
|
# Fallback: Manuelle SSL-Erstellung
|
||||||
|
create_production_ssl_certificates(ssl_dir)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"❌ SSL-Zertifikat-Erstellung fehlgeschlagen: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
return cert_file, key_file
|
||||||
|
|
||||||
|
def create_production_ssl_certificates(ssl_dir):
|
||||||
|
"""Erstelle browser-kompatible SSL-Zertifikate manuell"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
app_logger.info("🔧 Erstelle browser-kompatible SSL-Zertifikate...")
|
||||||
|
|
||||||
|
# OpenSSL-Konfiguration für Browser-Kompatibilität
|
||||||
|
openssl_config = f"""[req]
|
||||||
|
distinguished_name = req_distinguished_name
|
||||||
|
req_extensions = v3_req
|
||||||
|
prompt = no
|
||||||
|
|
||||||
|
[req_distinguished_name]
|
||||||
|
C = DE
|
||||||
|
ST = Baden-Wuerttemberg
|
||||||
|
L = Stuttgart
|
||||||
|
O = Mercedes-Benz AG
|
||||||
|
OU = MYP Druckerverwaltung
|
||||||
|
CN = m040tbaraspi001
|
||||||
|
|
||||||
|
[v3_req]
|
||||||
|
# KRITISCH für Browser-Kompatibilität
|
||||||
|
basicConstraints = critical, CA:FALSE
|
||||||
|
keyUsage = critical, digitalSignature, keyEncipherment, keyAgreement
|
||||||
|
extendedKeyUsage = critical, serverAuth, clientAuth
|
||||||
|
subjectAltName = critical, @alt_names
|
||||||
|
nsCertType = server
|
||||||
|
nsComment = "MYP Production SSL - Browser Compatible"
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
# Lokale Entwicklung
|
||||||
|
DNS.1 = localhost
|
||||||
|
DNS.2 = *.localhost
|
||||||
|
IP.1 = 127.0.0.1
|
||||||
|
IP.2 = ::1
|
||||||
|
|
||||||
|
# Raspberry Pi Hostname
|
||||||
|
DNS.3 = m040tbaraspi001
|
||||||
|
DNS.4 = m040tbaraspi001.local
|
||||||
|
DNS.5 = raspberrypi
|
||||||
|
DNS.6 = raspberrypi.local
|
||||||
|
|
||||||
|
# Intranet-Domain
|
||||||
|
DNS.7 = m040tbaraspi001.de040.corpintra.net
|
||||||
|
DNS.8 = *.de040.corpintra.net
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Schreibe Konfiguration in temporäre Datei
|
||||||
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.conf', delete=False) as f:
|
||||||
|
f.write(openssl_config)
|
||||||
|
config_file = f.name
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Generiere Private Key
|
||||||
|
subprocess.run([
|
||||||
|
'openssl', 'genrsa', '-out', f'{ssl_dir}/key.pem', '2048'
|
||||||
|
], check=True, capture_output=True)
|
||||||
|
|
||||||
|
# Generiere browser-kompatibles Zertifikat
|
||||||
|
subprocess.run([
|
||||||
|
'openssl', 'req', '-new', '-x509',
|
||||||
|
'-key', f'{ssl_dir}/key.pem',
|
||||||
|
'-out', f'{ssl_dir}/cert.pem',
|
||||||
|
'-days', '365',
|
||||||
|
'-config', config_file,
|
||||||
|
'-extensions', 'v3_req',
|
||||||
|
'-sha256'
|
||||||
|
], check=True, capture_output=True)
|
||||||
|
|
||||||
|
# Setze korrekte Berechtigungen
|
||||||
|
os.chmod(f'{ssl_dir}/cert.pem', 0o644)
|
||||||
|
os.chmod(f'{ssl_dir}/key.pem', 0o600)
|
||||||
|
|
||||||
|
app_logger.info("✅ Browser-kompatible SSL-Zertifikate erstellt")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Räume temporäre Datei auf
|
||||||
|
try:
|
||||||
|
os.unlink(config_file)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# =========================== PRODUKTIONS-SSL-KONTEXT ===========================
|
||||||
|
|
||||||
|
def get_production_ssl_context():
|
||||||
|
"""Erstelle optimierten SSL-Kontext für Produktionsbetrieb"""
|
||||||
|
|
||||||
|
cert_file, key_file = setup_production_ssl()
|
||||||
|
|
||||||
|
# Erstelle SSL-Kontext mit optimalen Einstellungen
|
||||||
|
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||||
|
|
||||||
|
# Lade Zertifikat und Key
|
||||||
|
context.load_cert_chain(cert_file, key_file)
|
||||||
|
|
||||||
|
# Optimale SSL-Einstellungen für Browser-Kompatibilität
|
||||||
|
context.set_ciphers('ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!MD5:!DSS')
|
||||||
|
context.options |= ssl.OP_NO_SSLv2
|
||||||
|
context.options |= ssl.OP_NO_SSLv3
|
||||||
|
context.options |= ssl.OP_NO_TLSv1
|
||||||
|
context.options |= ssl.OP_NO_TLSv1_1
|
||||||
|
context.options |= ssl.OP_SINGLE_DH_USE
|
||||||
|
context.options |= ssl.OP_SINGLE_ECDH_USE
|
||||||
|
|
||||||
|
# Deaktiviere Kompression (CRIME-Angriff-Schutz)
|
||||||
|
context.options |= ssl.OP_NO_COMPRESSION
|
||||||
|
|
||||||
|
app_logger.info("✅ Produktions-SSL-Kontext konfiguriert")
|
||||||
|
return context
|
||||||
|
|
||||||
|
# =========================== HTTPS-REDIRECT MIDDLEWARE ===========================
|
||||||
|
|
||||||
|
@app.before_request
|
||||||
|
def force_https():
|
||||||
|
"""Erzwinge HTTPS für alle Anfragen"""
|
||||||
|
if not request.is_secure and app.config.get('FORCE_HTTPS', False):
|
||||||
|
# Redirect zu HTTPS
|
||||||
|
url = request.url.replace('http://', 'https://', 1)
|
||||||
|
# Ändere Port zu 443 falls anders
|
||||||
|
if ':5000' in url:
|
||||||
|
url = url.replace(':5000', ':443')
|
||||||
|
elif ':80' in url:
|
||||||
|
url = url.replace(':80', ':443')
|
||||||
|
|
||||||
|
return redirect(url, code=301)
|
||||||
|
|
||||||
|
# =========================== SICHERHEITS-HEADERS ===========================
|
||||||
|
|
||||||
|
@app.after_request
|
||||||
|
def add_security_headers(response):
|
||||||
|
"""Füge Sicherheits-Headers für Produktionsbetrieb hinzu"""
|
||||||
|
|
||||||
|
# HTTPS-Sicherheits-Headers
|
||||||
|
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
|
||||||
|
response.headers['X-Content-Type-Options'] = 'nosniff'
|
||||||
|
response.headers['X-Frame-Options'] = 'SAMEORIGIN'
|
||||||
|
response.headers['X-XSS-Protection'] = '1; mode=block'
|
||||||
|
response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
|
||||||
|
|
||||||
|
# Content Security Policy für Kiosk-Modus
|
||||||
|
csp = (
|
||||||
|
"default-src 'self'; "
|
||||||
|
"script-src 'self' 'unsafe-inline' 'unsafe-eval'; "
|
||||||
|
"style-src 'self' 'unsafe-inline'; "
|
||||||
|
"img-src 'self' data: blob:; "
|
||||||
|
"font-src 'self'; "
|
||||||
|
"connect-src 'self'; "
|
||||||
|
"frame-ancestors 'self'"
|
||||||
|
)
|
||||||
|
response.headers['Content-Security-Policy'] = csp
|
||||||
|
|
||||||
|
# Cache-Control für statische Assets
|
||||||
|
if request.endpoint and 'static' in request.endpoint:
|
||||||
|
response.headers['Cache-Control'] = 'public, max-age=31536000'
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
# =========================== PRODUKTIONS-LOGGING ===========================
|
||||||
|
|
||||||
|
def setup_production_logging():
|
||||||
|
"""Konfiguriere optimiertes Logging für Produktionsbetrieb"""
|
||||||
|
|
||||||
|
# Reduziere Log-Level für Performance
|
||||||
|
logging.getLogger('werkzeug').setLevel(logging.WARNING)
|
||||||
|
logging.getLogger('urllib3').setLevel(logging.WARNING)
|
||||||
|
|
||||||
|
# Produktions-Log-Format
|
||||||
|
formatter = logging.Formatter(
|
||||||
|
'%(asctime)s [%(levelname)s] %(name)s: %(message)s',
|
||||||
|
datefmt='%Y-%m-%d %H:%M:%S'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stelle sicher, dass App-Logger korrekt konfiguriert ist
|
||||||
|
app_logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# Entferne Debug-Handler falls vorhanden
|
||||||
|
for handler in app_logger.handlers[:]:
|
||||||
|
if handler.level == logging.DEBUG:
|
||||||
|
app_logger.removeHandler(handler)
|
||||||
|
|
||||||
|
app_logger.info("✅ Produktions-Logging konfiguriert")
|
||||||
|
|
||||||
|
# =========================== HAUPTFUNKTION ===========================
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Hauptfunktion für Produktions-Server"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
app_logger.info("🚀 MYP Produktions-Server startet...")
|
||||||
|
app_logger.info(f"📅 Start-Zeit: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||||
|
app_logger.info(f"🖥️ Hostname: {os.uname().nodename}")
|
||||||
|
app_logger.info(f"🐍 Python: {sys.version}")
|
||||||
|
|
||||||
|
# Produktions-Logging einrichten
|
||||||
|
setup_production_logging()
|
||||||
|
|
||||||
|
# Prüfe Root-Berechtigung für Port 443
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
app_logger.error("❌ Root-Berechtigung erforderlich für Port 443")
|
||||||
|
app_logger.error("💡 Führe aus mit: sudo python3 app_production.py")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# SSL-Kontext erstellen
|
||||||
|
ssl_context = get_production_ssl_context()
|
||||||
|
|
||||||
|
# Datenbank initialisieren (aus Haupt-App)
|
||||||
|
from app import init_database, create_initial_admin
|
||||||
|
init_database()
|
||||||
|
create_initial_admin()
|
||||||
|
|
||||||
|
# Queue Manager und Scheduler starten
|
||||||
|
from app import start_queue_manager, get_job_scheduler
|
||||||
|
start_queue_manager()
|
||||||
|
|
||||||
|
scheduler = get_job_scheduler()
|
||||||
|
if scheduler:
|
||||||
|
scheduler.start()
|
||||||
|
app_logger.info("✅ Job-Scheduler gestartet")
|
||||||
|
|
||||||
|
# Server-Konfiguration
|
||||||
|
host = '0.0.0.0' # Alle Interfaces
|
||||||
|
port = 443 # Nur HTTPS Port 443
|
||||||
|
|
||||||
|
app_logger.info("🔐 HTTPS-Only Produktions-Modus")
|
||||||
|
app_logger.info(f"🌐 Server läuft auf: https://{host}:{port}")
|
||||||
|
app_logger.info(f"🏠 Lokaler Zugriff: https://localhost")
|
||||||
|
app_logger.info(f"🌍 Intranet-Zugriff: https://m040tbaraspi001.de040.corpintra.net")
|
||||||
|
app_logger.info("🔥 Firewall: Nur Port 443 erforderlich")
|
||||||
|
app_logger.info("🛡️ SSL-Zertifikate: Browser-kompatibel")
|
||||||
|
|
||||||
|
# Starte Flask-Server mit SSL
|
||||||
|
app.run(
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
ssl_context=ssl_context,
|
||||||
|
threaded=True,
|
||||||
|
debug=False,
|
||||||
|
use_reloader=False
|
||||||
|
)
|
||||||
|
|
||||||
|
except PermissionError:
|
||||||
|
app_logger.error("❌ Berechtigung verweigert für Port 443")
|
||||||
|
app_logger.error("💡 Führe aus mit: sudo python3 app_production.py")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
except OSError as e:
|
||||||
|
if "Address already in use" in str(e):
|
||||||
|
app_logger.error("❌ Port 443 bereits belegt")
|
||||||
|
app_logger.error("💡 Stoppe andere Services: sudo systemctl stop apache2 nginx")
|
||||||
|
else:
|
||||||
|
app_logger.error(f"❌ Netzwerk-Fehler: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"❌ Kritischer Fehler beim Server-Start: {e}")
|
||||||
|
import traceback
|
||||||
|
app_logger.error(f"Traceback: {traceback.format_exc()}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Cleanup
|
||||||
|
try:
|
||||||
|
from app import stop_queue_manager, cleanup_rate_limiter
|
||||||
|
stop_queue_manager()
|
||||||
|
if 'scheduler' in locals() and scheduler:
|
||||||
|
scheduler.shutdown()
|
||||||
|
cleanup_rate_limiter()
|
||||||
|
app_logger.info("✅ Cleanup abgeschlossen")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
193
backend/deploy_production.sh
Normal file
193
backend/deploy_production.sh
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# MYP Production Deployment - HTTPS-Only
|
||||||
|
# Deployed die optimierte Produktions-Version mit SSL-Fix
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Farben
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo -e "${BLUE}🚀 MYP PRODUCTION DEPLOYMENT${NC}"
|
||||||
|
echo -e "${BLUE}HTTPS-Only Produktions-Setup${NC}"
|
||||||
|
echo "=============================================="
|
||||||
|
|
||||||
|
# Prüfe Root-Berechtigung
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
echo -e "${RED}❌ Root-Berechtigung erforderlich${NC}"
|
||||||
|
echo -e "${YELLOW}💡 Führe aus mit: sudo $0${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 1. Stoppe alte Services
|
||||||
|
echo -e "${YELLOW}🛑 Schritt 1: Stoppe alte HTTP-Services${NC}"
|
||||||
|
OLD_SERVICES=("myp-https" "myp-app" "myp-kiosk")
|
||||||
|
|
||||||
|
for service in "${OLD_SERVICES[@]}"; do
|
||||||
|
if systemctl is-active "$service" >/dev/null 2>&1; then
|
||||||
|
echo " Stoppe $service..."
|
||||||
|
systemctl stop "$service" 2>/dev/null || true
|
||||||
|
systemctl disable "$service" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 2. SSL-Zertifikate erstellen/reparieren
|
||||||
|
echo -e "${YELLOW}🔐 Schritt 2: Browser-kompatible SSL-Zertifikate${NC}"
|
||||||
|
if [ -f "/opt/myp/fix_ssl_raspberry.sh" ]; then
|
||||||
|
echo " Führe SSL-Fix-Skript aus..."
|
||||||
|
bash /opt/myp/fix_ssl_raspberry.sh
|
||||||
|
else
|
||||||
|
echo " Erstelle SSL-Zertifikate manuell..."
|
||||||
|
SSL_DIR="/opt/myp/ssl"
|
||||||
|
mkdir -p "$SSL_DIR"
|
||||||
|
|
||||||
|
# Browser-kompatible SSL-Konfiguration
|
||||||
|
cat > /tmp/ssl.conf << 'EOF'
|
||||||
|
[req]
|
||||||
|
distinguished_name = req_distinguished_name
|
||||||
|
req_extensions = v3_req
|
||||||
|
prompt = no
|
||||||
|
|
||||||
|
[req_distinguished_name]
|
||||||
|
C = DE
|
||||||
|
ST = Baden-Wuerttemberg
|
||||||
|
L = Stuttgart
|
||||||
|
O = Mercedes-Benz AG
|
||||||
|
OU = MYP Druckerverwaltung
|
||||||
|
CN = m040tbaraspi001
|
||||||
|
|
||||||
|
[v3_req]
|
||||||
|
basicConstraints = critical, CA:FALSE
|
||||||
|
keyUsage = critical, digitalSignature, keyEncipherment, keyAgreement
|
||||||
|
extendedKeyUsage = critical, serverAuth, clientAuth
|
||||||
|
subjectAltName = critical, @alt_names
|
||||||
|
nsCertType = server
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
DNS.1 = localhost
|
||||||
|
DNS.2 = m040tbaraspi001
|
||||||
|
DNS.3 = m040tbaraspi001.local
|
||||||
|
DNS.4 = m040tbaraspi001.de040.corpintra.net
|
||||||
|
IP.1 = 127.0.0.1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Generiere Zertifikate
|
||||||
|
openssl genrsa -out "$SSL_DIR/key.pem" 2048
|
||||||
|
openssl req -new -x509 -key "$SSL_DIR/key.pem" -out "$SSL_DIR/cert.pem" \
|
||||||
|
-days 365 -config /tmp/ssl.conf -extensions v3_req -sha256
|
||||||
|
|
||||||
|
chmod 644 "$SSL_DIR/cert.pem"
|
||||||
|
chmod 600 "$SSL_DIR/key.pem"
|
||||||
|
rm /tmp/ssl.conf
|
||||||
|
|
||||||
|
echo " ✅ Browser-kompatible SSL-Zertifikate erstellt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Produktions-Service installieren
|
||||||
|
echo -e "${YELLOW}📦 Schritt 3: Produktions-Service installieren${NC}"
|
||||||
|
if [ -f "/opt/myp/systemd/myp-production.service" ]; then
|
||||||
|
cp /opt/myp/systemd/myp-production.service /etc/systemd/system/
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable myp-production
|
||||||
|
echo " ✅ myp-production.service installiert"
|
||||||
|
else
|
||||||
|
echo -e "${RED} ❌ myp-production.service nicht gefunden${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. Kiosk-Service für HTTPS aktualisieren
|
||||||
|
echo -e "${YELLOW}🖥️ Schritt 4: Kiosk-Service für HTTPS aktualisieren${NC}"
|
||||||
|
if [ -f "/opt/myp/systemd/myp-kiosk.service" ]; then
|
||||||
|
cp /opt/myp/systemd/myp-kiosk.service /etc/systemd/system/
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable myp-kiosk
|
||||||
|
echo " ✅ myp-kiosk.service für HTTPS aktualisiert"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. Firewall für HTTPS-Only konfigurieren
|
||||||
|
echo -e "${YELLOW}🔥 Schritt 5: Firewall für HTTPS-Only${NC}"
|
||||||
|
if [ -f "/opt/myp/setup_production_firewall.sh" ]; then
|
||||||
|
bash /opt/myp/setup_production_firewall.sh
|
||||||
|
else
|
||||||
|
# Fallback: Manuelle Firewall-Konfiguration
|
||||||
|
if command -v ufw >/dev/null 2>&1; then
|
||||||
|
ufw allow 443/tcp
|
||||||
|
ufw deny 5000/tcp
|
||||||
|
ufw deny 80/tcp
|
||||||
|
ufw --force enable
|
||||||
|
echo " ✅ Firewall manuell konfiguriert"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 6. Produktions-Service starten
|
||||||
|
echo -e "${YELLOW}🚀 Schritt 6: Produktions-Service starten${NC}"
|
||||||
|
systemctl start myp-production
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
if systemctl is-active myp-production >/dev/null 2>&1; then
|
||||||
|
echo " ✅ myp-production läuft"
|
||||||
|
else
|
||||||
|
echo -e "${RED} ❌ myp-production Start-Fehler${NC}"
|
||||||
|
echo " Logs: journalctl -u myp-production -f"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 7. Kiosk-Service starten
|
||||||
|
echo -e "${YELLOW}🖥️ Schritt 7: Kiosk-Service starten${NC}"
|
||||||
|
systemctl start myp-kiosk
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
if systemctl is-active myp-kiosk >/dev/null 2>&1; then
|
||||||
|
echo " ✅ myp-kiosk läuft"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW} ⚠️ myp-kiosk Start-Problem (normal bei fehlendem Display)${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 8. Verbindungstest
|
||||||
|
echo -e "${YELLOW}🌐 Schritt 8: HTTPS-Verbindungstest${NC}"
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
if timeout 10 bash -c "</dev/tcp/localhost/443" 2>/dev/null; then
|
||||||
|
echo " ✅ Port 443 (HTTPS) erreichbar"
|
||||||
|
else
|
||||||
|
echo -e "${RED} ❌ Port 443 nicht erreichbar${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test mit curl
|
||||||
|
if curl -k -s --connect-timeout 5 https://localhost >/dev/null 2>&1; then
|
||||||
|
echo " ✅ HTTPS-Webserver antwortet"
|
||||||
|
else
|
||||||
|
echo -e "${RED} ❌ HTTPS-Webserver antwortet nicht${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 9. Status-Übersicht
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}🏁 PRODUCTION DEPLOYMENT ABGESCHLOSSEN!${NC}"
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}📊 Service-Status:${NC}"
|
||||||
|
systemctl is-active myp-production && echo -e " ✅ myp-production: $(systemctl is-active myp-production)"
|
||||||
|
systemctl is-active myp-kiosk && echo -e " ✅ myp-kiosk: $(systemctl is-active myp-kiosk)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}🌐 Zugriff über:${NC}"
|
||||||
|
echo " • https://localhost (lokal)"
|
||||||
|
echo " • https://m040tbaraspi001.de040.corpintra.net (Intranet)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}🔐 SICHERHEITS-STATUS:${NC}"
|
||||||
|
echo " ✅ Nur Port 443 (HTTPS) ist öffentlich"
|
||||||
|
echo " ✅ Port 5000 (HTTP) ist blockiert"
|
||||||
|
echo " ✅ Browser-kompatible SSL-Zertifikate"
|
||||||
|
echo " ✅ Kiosk-Modus verwendet HTTPS"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}📋 NÄCHSTE SCHRITTE:${NC}"
|
||||||
|
echo " 1. Browser-Zertifikat-Warnung akzeptieren"
|
||||||
|
echo " 2. Kiosk sollte automatisch HTTPS verwenden"
|
||||||
|
echo " 3. Bei Problemen: journalctl -u myp-production -f"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}✨ MYP läuft jetzt im sicheren HTTPS-Only Modus!${NC}"
|
@@ -14,9 +14,9 @@ NC='\033[0m'
|
|||||||
echo -e "${BLUE}🚀 MYP QUICK FIX - Connection Refused${NC}"
|
echo -e "${BLUE}🚀 MYP QUICK FIX - Connection Refused${NC}"
|
||||||
echo "=============================================="
|
echo "=============================================="
|
||||||
|
|
||||||
# 1. Services stoppen und neu starten
|
# 1. Services stoppen und neu starten (HTTPS-Only)
|
||||||
echo -e "${YELLOW}🔄 Schritt 1: Services neu starten${NC}"
|
echo -e "${YELLOW}🔄 Schritt 1: Services neu starten${NC}"
|
||||||
services=("myp-kiosk" "myp-https" "myp-app")
|
services=("myp-kiosk" "myp-production" "myp-https" "myp-app")
|
||||||
|
|
||||||
for service in "${services[@]}"; do
|
for service in "${services[@]}"; do
|
||||||
if systemctl is-enabled "$service" >/dev/null 2>&1; then
|
if systemctl is-enabled "$service" >/dev/null 2>&1; then
|
||||||
@@ -35,13 +35,14 @@ for service in "${services[@]}"; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# 2. Ports freigeben
|
# 2. Firewall für HTTPS-Only konfigurieren
|
||||||
echo -e "${YELLOW}🔥 Schritt 2: Firewall-Ports öffnen${NC}"
|
echo -e "${YELLOW}🔥 Schritt 2: Firewall für HTTPS-Only${NC}"
|
||||||
if command -v ufw >/dev/null 2>&1; then
|
if command -v ufw >/dev/null 2>&1; then
|
||||||
ufw allow 443 >/dev/null 2>&1 || true
|
ufw allow 443 >/dev/null 2>&1 || true
|
||||||
ufw allow 5000 >/dev/null 2>&1 || true
|
ufw deny 5000 >/dev/null 2>&1 || true
|
||||||
ufw allow 80 >/dev/null 2>&1 || true
|
ufw deny 80 >/dev/null 2>&1 || true
|
||||||
echo " ✅ Ports 443, 5000, 80 geöffnet"
|
echo " ✅ Port 443 (HTTPS) geöffnet"
|
||||||
|
echo " ✅ Port 5000/80 (HTTP) blockiert"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 3. SSL-Zertifikate prüfen/erstellen
|
# 3. SSL-Zertifikate prüfen/erstellen
|
||||||
@@ -82,17 +83,23 @@ except Exception as e:
|
|||||||
print(f' ❌ App-Import-Fehler: {e}')
|
print(f' ❌ App-Import-Fehler: {e}')
|
||||||
" 2>/dev/null || echo " ⚠️ App-Test unvollständig"
|
" 2>/dev/null || echo " ⚠️ App-Test unvollständig"
|
||||||
|
|
||||||
# 6. Verbindungstest
|
# 6. Verbindungstest (HTTPS-Only)
|
||||||
echo -e "${YELLOW}🌐 Schritt 6: Verbindungstest${NC}"
|
echo -e "${YELLOW}🌐 Schritt 6: HTTPS-Verbindungstest${NC}"
|
||||||
sleep 3
|
sleep 3
|
||||||
|
|
||||||
for port in 5000 443; do
|
# Teste nur HTTPS Port 443
|
||||||
if timeout 3 bash -c "</dev/tcp/localhost/$port" 2>/dev/null; then
|
if timeout 3 bash -c "</dev/tcp/localhost/443" 2>/dev/null; then
|
||||||
echo -e " ✅ Port $port erreichbar"
|
echo -e " ✅ Port 443 (HTTPS) erreichbar"
|
||||||
else
|
else
|
||||||
echo -e " ❌ Port $port nicht erreichbar"
|
echo -e " ❌ Port 443 (HTTPS) nicht erreichbar"
|
||||||
fi
|
fi
|
||||||
done
|
|
||||||
|
# Prüfe dass HTTP-Ports blockiert sind
|
||||||
|
if timeout 3 bash -c "</dev/tcp/localhost/5000" 2>/dev/null; then
|
||||||
|
echo -e " ⚠️ Port 5000 noch offen (sollte blockiert sein)"
|
||||||
|
else
|
||||||
|
echo -e " ✅ Port 5000 korrekt blockiert"
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${GREEN}🏁 Quick Fix abgeschlossen!${NC}"
|
echo -e "${GREEN}🏁 Quick Fix abgeschlossen!${NC}"
|
||||||
|
32
backend/scripts/get_kiosk_url.sh
Normal file
32
backend/scripts/get_kiosk_url.sh
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# MYP Kiosk URL Ermittlung - HTTPS-Only
|
||||||
|
# Ermittelt die beste HTTPS-URL für den Kiosk-Modus
|
||||||
|
|
||||||
|
# Prioritäten für URL-Ermittlung:
|
||||||
|
# 1. Intranet-Domain (falls erreichbar)
|
||||||
|
# 2. Lokaler Hostname (falls erreichbar)
|
||||||
|
# 3. Localhost (Fallback)
|
||||||
|
|
||||||
|
# Teste Intranet-Domain
|
||||||
|
INTRANET_URL="https://m040tbaraspi001.de040.corpintra.net"
|
||||||
|
if curl -k -s --connect-timeout 2 --max-time 3 "$INTRANET_URL" >/dev/null 2>&1; then
|
||||||
|
echo "$INTRANET_URL"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Teste lokalen Hostname
|
||||||
|
HOSTNAME=$(hostname)
|
||||||
|
LOCAL_URL="https://$HOSTNAME"
|
||||||
|
if curl -k -s --connect-timeout 2 --max-time 3 "$LOCAL_URL" >/dev/null 2>&1; then
|
||||||
|
echo "$LOCAL_URL"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Teste localhost mit Port 443
|
||||||
|
if curl -k -s --connect-timeout 2 --max-time 3 "https://localhost:443" >/dev/null 2>&1; then
|
||||||
|
echo "https://localhost:443"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fallback: localhost ohne Port
|
||||||
|
echo "https://localhost"
|
1
backend/setup_production_complete.sh
Normal file
1
backend/setup_production_complete.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
137
backend/setup_production_firewall.sh
Normal file
137
backend/setup_production_firewall.sh
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# MYP Production Firewall Setup - Nur Port 443
|
||||||
|
# Konfiguriert UFW für maximale Sicherheit mit nur HTTPS-Zugriff
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Farben für Output
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo -e "${BLUE}🔥 MYP PRODUCTION FIREWALL SETUP${NC}"
|
||||||
|
echo -e "${BLUE}Konfiguriert UFW für HTTPS-Only Betrieb${NC}"
|
||||||
|
echo "=============================================="
|
||||||
|
|
||||||
|
# Prüfe Root-Berechtigung
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
echo -e "${RED}❌ Root-Berechtigung erforderlich${NC}"
|
||||||
|
echo -e "${YELLOW}💡 Führe aus mit: sudo $0${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prüfe ob UFW installiert ist
|
||||||
|
if ! command -v ufw >/dev/null 2>&1; then
|
||||||
|
echo -e "${YELLOW}📦 Installiere UFW...${NC}"
|
||||||
|
apt update && apt install -y ufw
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${YELLOW}🔧 Konfiguriere Firewall für HTTPS-Only Betrieb...${NC}"
|
||||||
|
|
||||||
|
# UFW zurücksetzen für saubere Konfiguration
|
||||||
|
echo " Setze UFW-Regeln zurück..."
|
||||||
|
ufw --force reset >/dev/null 2>&1
|
||||||
|
|
||||||
|
# Standard-Policies setzen (alles blockieren)
|
||||||
|
echo " Setze restriktive Standard-Policies..."
|
||||||
|
ufw default deny incoming >/dev/null 2>&1
|
||||||
|
ufw default deny outgoing >/dev/null 2>&1
|
||||||
|
ufw default deny forward >/dev/null 2>&1
|
||||||
|
|
||||||
|
# Loopback-Interface erlauben (wichtig für lokale Verbindungen)
|
||||||
|
echo " Erlaube Loopback-Interface..."
|
||||||
|
ufw allow in on lo >/dev/null 2>&1
|
||||||
|
ufw allow out on lo >/dev/null 2>&1
|
||||||
|
|
||||||
|
# SSH-Zugriff beibehalten (falls aktiv)
|
||||||
|
if systemctl is-active ssh >/dev/null 2>&1 || systemctl is-active sshd >/dev/null 2>&1; then
|
||||||
|
echo " Erlaube SSH (Port 22) für Administration..."
|
||||||
|
ufw allow 22/tcp >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# HTTPS-Port 443 öffnen (einziger öffentlicher Port)
|
||||||
|
echo " Öffne HTTPS Port 443..."
|
||||||
|
ufw allow 443/tcp >/dev/null 2>&1
|
||||||
|
|
||||||
|
# Ausgehende Verbindungen für System-Updates erlauben
|
||||||
|
echo " Erlaube ausgehende System-Updates..."
|
||||||
|
ufw allow out 53/udp >/dev/null 2>&1 # DNS
|
||||||
|
ufw allow out 80/tcp >/dev/null 2>&1 # HTTP für Updates
|
||||||
|
ufw allow out 443/tcp >/dev/null 2>&1 # HTTPS für Updates
|
||||||
|
|
||||||
|
# NTP für Zeitsynchonisation
|
||||||
|
echo " Erlaube NTP für Zeitsynchonisation..."
|
||||||
|
ufw allow out 123/udp >/dev/null 2>&1
|
||||||
|
|
||||||
|
# Lokales Netzwerk für Drucker-Kommunikation
|
||||||
|
echo " Erlaube lokales Netzwerk für Drucker..."
|
||||||
|
ufw allow out on eth0 to 192.168.0.0/16 >/dev/null 2>&1
|
||||||
|
ufw allow out on wlan0 to 192.168.0.0/16 >/dev/null 2>&1
|
||||||
|
ufw allow out on eth0 to 10.0.0.0/8 >/dev/null 2>&1
|
||||||
|
ufw allow out on wlan0 to 10.0.0.0/8 >/dev/null 2>&1
|
||||||
|
|
||||||
|
# Explizit blockiere alle anderen Ports
|
||||||
|
echo " Blockiere explizit gefährliche Ports..."
|
||||||
|
|
||||||
|
# Häufige Service-Ports blockieren
|
||||||
|
BLOCKED_PORTS=(
|
||||||
|
"21" # FTP
|
||||||
|
"23" # Telnet
|
||||||
|
"25" # SMTP
|
||||||
|
"53" # DNS (incoming)
|
||||||
|
"110" # POP3
|
||||||
|
"143" # IMAP
|
||||||
|
"993" # IMAPS
|
||||||
|
"995" # POP3S
|
||||||
|
"3389" # RDP
|
||||||
|
"5000" # Flask Development (nicht mehr benötigt)
|
||||||
|
"5432" # PostgreSQL
|
||||||
|
"3306" # MySQL
|
||||||
|
"1433" # MSSQL
|
||||||
|
"6379" # Redis
|
||||||
|
"27017" # MongoDB
|
||||||
|
"8080" # Alternative HTTP
|
||||||
|
"8443" # Alternative HTTPS
|
||||||
|
"9000" # Verschiedene Services
|
||||||
|
)
|
||||||
|
|
||||||
|
for port in "${BLOCKED_PORTS[@]}"; do
|
||||||
|
ufw deny "$port" >/dev/null 2>&1
|
||||||
|
done
|
||||||
|
|
||||||
|
# UFW aktivieren
|
||||||
|
echo " Aktiviere UFW..."
|
||||||
|
ufw --force enable >/dev/null 2>&1
|
||||||
|
|
||||||
|
# Status anzeigen
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}✅ Firewall erfolgreich konfiguriert!${NC}"
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}📋 Firewall-Status:${NC}"
|
||||||
|
ufw status numbered
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}🔐 SICHERHEITS-ZUSAMMENFASSUNG:${NC}"
|
||||||
|
echo -e " ✅ Nur Port 443 (HTTPS) ist öffentlich zugänglich"
|
||||||
|
echo -e " ✅ Port 5000 (HTTP) ist blockiert"
|
||||||
|
echo -e " ✅ SSH bleibt für Administration verfügbar"
|
||||||
|
echo -e " ✅ Lokales Netzwerk für Drucker erlaubt"
|
||||||
|
echo -e " ✅ System-Updates möglich"
|
||||||
|
echo -e " ✅ Alle anderen Ports sind gesperrt"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}🌐 Zugriff nur noch über:${NC}"
|
||||||
|
echo -e " • https://localhost (lokal)"
|
||||||
|
echo -e " • https://m040tbaraspi001.de040.corpintra.net (Intranet)"
|
||||||
|
echo -e " • https://[IP-Adresse] (direkt)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}⚠️ WICHTIG:${NC}"
|
||||||
|
echo -e " • HTTP (Port 80/5000) ist jetzt blockiert"
|
||||||
|
echo -e " • Nur HTTPS-Verbindungen funktionieren"
|
||||||
|
echo -e " • Browser-Zertifikat-Warnung ist normal"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}🏁 Production Firewall Setup abgeschlossen!${NC}"
|
@@ -1,8 +1,8 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=MYP Kiosk Browser Autostart (Chromium HTTPS) - Wartungsfreier Produktionsbetrieb
|
Description=MYP Kiosk Browser Autostart (Chromium HTTPS) - Wartungsfreier Produktionsbetrieb
|
||||||
Documentation=https://github.com/MYP-Druckerverwaltung
|
Documentation=https://github.com/MYP-Druckerverwaltung
|
||||||
After=graphical-session.target myp-https.service network-online.target
|
After=graphical-session.target myp-production.service network-online.target
|
||||||
Wants=myp-https.service network-online.target
|
Wants=myp-production.service network-online.target
|
||||||
Requires=graphical-session.target
|
Requires=graphical-session.target
|
||||||
StartLimitBurst=5
|
StartLimitBurst=5
|
||||||
StartLimitInterval=600
|
StartLimitInterval=600
|
||||||
@@ -33,17 +33,20 @@ ExecStartPre=/bin/bash -c '\
|
|||||||
sleep 2; \
|
sleep 2; \
|
||||||
done; \
|
done; \
|
||||||
\
|
\
|
||||||
# Warte auf HTTP-Backend mit verbesserter Erkennung \
|
# Warte auf HTTPS-Backend (Port 443) \
|
||||||
echo "🔍 Warte auf HTTP Backend..."; \
|
echo "🔍 Warte auf HTTPS Backend (Port 443)..."; \
|
||||||
for i in {1..120}; do \
|
for i in {1..120}; do \
|
||||||
if curl -s --connect-timeout 3 --max-time 5 http://localhost:5000/api/kiosk/status >/dev/null 2>&1; then \
|
if curl -k -s --connect-timeout 3 --max-time 5 https://localhost:443/api/kiosk/status >/dev/null 2>&1; then \
|
||||||
echo "✅ HTTP Backend erreichbar und API verfügbar"; \
|
echo "✅ HTTPS Backend erreichbar und API verfügbar"; \
|
||||||
break; \
|
break; \
|
||||||
elif curl -s --connect-timeout 3 --max-time 5 http://localhost:5000 >/dev/null 2>&1; then \
|
elif curl -k -s --connect-timeout 3 --max-time 5 https://localhost:443 >/dev/null 2>&1; then \
|
||||||
echo "✅ HTTP Backend erreichbar"; \
|
echo "✅ HTTPS Backend erreichbar"; \
|
||||||
|
break; \
|
||||||
|
elif curl -k -s --connect-timeout 3 --max-time 5 https://localhost >/dev/null 2>&1; then \
|
||||||
|
echo "✅ HTTPS Backend erreichbar (Standard-Port)"; \
|
||||||
break; \
|
break; \
|
||||||
fi; \
|
fi; \
|
||||||
echo "⏳ Warte auf Backend... ($i/120)"; \
|
echo "⏳ Warte auf HTTPS Backend... ($i/120)"; \
|
||||||
sleep 3; \
|
sleep 3; \
|
||||||
done; \
|
done; \
|
||||||
\
|
\
|
||||||
@@ -162,9 +165,9 @@ ExecStart=/bin/bash -c '\
|
|||||||
--new-instance"; \
|
--new-instance"; \
|
||||||
fi; \
|
fi; \
|
||||||
\
|
\
|
||||||
# URL mit intelligenter Ermittlung \
|
# URL mit intelligenter Ermittlung (HTTPS-Only) \
|
||||||
TARGET_URL=$(/opt/myp/scripts/get_kiosk_url.sh); \
|
TARGET_URL=$(/opt/myp/scripts/get_kiosk_url.sh); \
|
||||||
[ -z "$TARGET_URL" ] && TARGET_URL="http://localhost:5000"; \
|
[ -z "$TARGET_URL" ] && TARGET_URL="https://localhost"; \
|
||||||
\
|
\
|
||||||
# Browser starten mit Fehlerbehandlung \
|
# Browser starten mit Fehlerbehandlung \
|
||||||
echo "🖥️ Starte $BROWSER im Kiosk-Modus..."; \
|
echo "🖥️ Starte $BROWSER im Kiosk-Modus..."; \
|
||||||
|
69
backend/systemd/myp-production.service
Normal file
69
backend/systemd/myp-production.service
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=MYP Druckerverwaltung HTTPS Production Server (Port 443 Only)
|
||||||
|
Documentation=https://github.com/MYP-Druckerverwaltung
|
||||||
|
After=network.target network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
Requires=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
WorkingDirectory=/opt/myp
|
||||||
|
|
||||||
|
# Produktions-App mit HTTPS-Only auf Port 443
|
||||||
|
ExecStart=/usr/bin/python3 /opt/myp/app_production.py
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
StartLimitBurst=5
|
||||||
|
StartLimitInterval=300
|
||||||
|
|
||||||
|
# Umgebungsvariablen für Produktionsbetrieb
|
||||||
|
Environment=PYTHONUNBUFFERED=1
|
||||||
|
Environment=FLASK_ENV=production
|
||||||
|
Environment=FLASK_HOST=0.0.0.0
|
||||||
|
Environment=FLASK_PORT=443
|
||||||
|
Environment=PYTHONPATH=/opt/myp
|
||||||
|
Environment=LC_ALL=C.UTF-8
|
||||||
|
Environment=LANG=C.UTF-8
|
||||||
|
Environment=KIOSK_MODE=true
|
||||||
|
Environment=USE_OPTIMIZED_CONFIG=true
|
||||||
|
Environment=HTTPS_ONLY=true
|
||||||
|
Environment=SSL_REQUIRED=true
|
||||||
|
|
||||||
|
# Logging-Konfiguration
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
SyslogIdentifier=myp-production
|
||||||
|
|
||||||
|
# Sicherheitseinstellungen für Produktionsbetrieb
|
||||||
|
NoNewPrivileges=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ProtectHome=true
|
||||||
|
ReadWritePaths=/opt/myp
|
||||||
|
ReadWritePaths=/var/log
|
||||||
|
|
||||||
|
# Netzwerk-Sicherheit
|
||||||
|
PrivateNetwork=false
|
||||||
|
RestrictAddressFamilies=AF_INET AF_INET6
|
||||||
|
IPAddressDeny=any
|
||||||
|
IPAddressAllow=localhost
|
||||||
|
IPAddressAllow=127.0.0.0/8
|
||||||
|
IPAddressAllow=10.0.0.0/8
|
||||||
|
IPAddressAllow=192.168.0.0/16
|
||||||
|
IPAddressAllow=172.16.0.0/12
|
||||||
|
|
||||||
|
# Ressourcen-Limits
|
||||||
|
LimitNOFILE=65536
|
||||||
|
LimitNPROC=4096
|
||||||
|
MemoryHigh=512M
|
||||||
|
MemoryMax=1G
|
||||||
|
CPUQuota=80%
|
||||||
|
|
||||||
|
# Capabilities für Port 443 (privilegierter Port)
|
||||||
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||||
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
Reference in New Issue
Block a user