# Critical Configurations Reference **Document Version:** 1.0 **Last Updated:** 2026-01-10 **Status:** Production LIVE **Diagram Type:** Configuration Reference / Operations Guide --- ## Overview This document provides a **comprehensive reference** of all critical configurations for the Norda Biznes Partner infrastructure. It serves as the **single source of truth** for: - **NPM reverse proxy configuration** (includes critical port 5000 warning) - **Port mappings** across all servers and services - **SSL/TLS certificate configuration** (Let's Encrypt) - **Environment variables** and secrets management - **Database connection strings** and credentials - **Gunicorn/WSGI configuration** for Flask application - **Systemd service configuration** for application lifecycle - **Git repository configuration** for deployment - **Critical file paths** and directory structure - **Firewall rules** and network ACLs **Abstraction Level:** Infrastructure Configuration **Audience:** System Administrators, DevOps Engineers, Production Support **Purpose:** Configuration reference, incident response, disaster recovery, new server provisioning **⚠️ WARNING:** This document contains references to production configurations. Actual secrets are stored in `.env` files and are **never** committed to version control. **Related Documentation:** - [Deployment Architecture](03-deployment-architecture.md) - Infrastructure overview - [Network Topology](07-network-topology.md) - Network layout and zones - [HTTP Request Flow](flows/06-http-request-flow.md) - Request path details - [Incident Report 2026-01-02](../INCIDENT_REPORT_20260102.md) - NPM port misconfiguration incident --- ## Table of Contents 1. [NPM Reverse Proxy Configuration](#npm-reverse-proxy-configuration) 2. [Port Mappings Reference](#port-mappings-reference) 3. [SSL/TLS Configuration](#ssltls-configuration) 4. [Environment Variables](#environment-variables) 5. [Database Configuration](#database-configuration) 6. [Gunicorn WSGI Configuration](#gunicorn-wsgi-configuration) 7. [Systemd Service Configuration](#systemd-service-configuration) 8. [Git Repository Configuration](#git-repository-configuration) 9. [Critical File Paths](#critical-file-paths) 10. [Firewall and Network Rules](#firewall-and-network-rules) 11. [Backup and Recovery Locations](#backup-and-recovery-locations) 12. [Configuration Management](#configuration-management) 13. [Verification Checklist](#verification-checklist) --- ## NPM Reverse Proxy Configuration ### ⚠️ CRITICAL: Port 5000 Configuration **Proxy Host ID:** 27 **Domains:** nordabiznes.pl, www.nordabiznes.pl > **CRITICAL WARNING:** NPM must forward to **port 5000**, NOT port 80! > > Forwarding to port 80 causes an infinite redirect loop (ERR_TOO_MANY_REDIRECTS). > This was the root cause of the 2026-01-02 production incident. > > See: [INCIDENT_REPORT_20260102.md](../INCIDENT_REPORT_20260102.md) ### Complete NPM Configuration ```json { "id": 27, "domain_names": [ "nordabiznes.pl", "www.nordabiznes.pl" ], "forward_scheme": "http", "forward_host": "10.22.68.249", "forward_port": 5000, // ⚠️ CRITICAL: Must be 5000, NOT 80! "certificate_id": 27, "ssl_forced": true, "http2_support": true, "block_exploits": true, "allow_websocket_upgrade": true, "hsts_enabled": true, "hsts_subdomains": true, "advanced_config": "", "access_list_id": 0, "meta": { "letsencrypt_agree": true, "dns_challenge": false } } ``` ### NPM Server Details | Parameter | Value | |-----------|-------| | **Server** | R11-REVPROXY-01 | | **VM ID** | 119 | | **IP Address** | 10.22.68.250 | | **NPM Version** | Latest (Docker) | | **Container Name** | `nginx-proxy-manager_app_1` | | **Admin Panel** | http://10.22.68.250:81 | | **Database** | SQLite (`/data/database.sqlite`) | ### Verification Commands ```bash # 1. Check NPM proxy host configuration ssh maciejpi@10.22.68.250 "docker exec nginx-proxy-manager_app_1 \ sqlite3 /data/database.sqlite \ \"SELECT id, domain_names, forward_host, forward_port FROM proxy_host WHERE id = 27;\"" # Expected output: 27|["nordabiznes.pl","www.nordabiznes.pl"]|10.22.68.249|5000 # 2. Verify website is accessible curl -I https://nordabiznes.pl/health # Expected: HTTP/2 200 OK # 3. Check NPM logs for errors ssh maciejpi@10.22.68.250 "docker logs nginx-proxy-manager_app_1 --tail 50" # 4. Verify SSL certificate openssl s_client -connect nordabiznes.pl:443 -servername nordabiznes.pl < /dev/null 2>/dev/null | \ openssl x509 -noout -dates -subject -issuer ``` ### NPM Configuration Update Procedure **IMPORTANT:** Always verify port 5000 after making any changes to NPM! ```python # NPM API configuration update (Python) import requests NPM_URL = "http://10.22.68.250:81/api" NPM_EMAIL = "admin@example.com" NPM_PASSWORD = "your_npm_password" # Step 1: Authenticate auth_response = requests.post( f"{NPM_URL}/tokens", json={"identity": NPM_EMAIL, "secret": NPM_PASSWORD} ) token = auth_response.json()["token"] headers = {"Authorization": f"Bearer {token}"} # Step 2: Get current configuration current = requests.get( f"{NPM_URL}/nginx/proxy-hosts/27", headers=headers ).json() # Step 3: Verify port is 5000 if current["forward_port"] != 5000: print("⚠️ WARNING: Port is not 5000! Current:", current["forward_port"]) # Update to correct port current["forward_port"] = 5000 requests.put( f"{NPM_URL}/nginx/proxy-hosts/27", headers=headers, json=current ) print("✓ Port corrected to 5000") else: print("✓ Port is correctly set to 5000") # Step 4: Verify website works import subprocess result = subprocess.run(["curl", "-I", "https://nordabiznes.pl/health"], capture_output=True) if b"200 OK" in result.stdout: print("✓ Website is accessible") else: print("❌ Website check failed!") ``` --- ## Port Mappings Reference ### Complete Port Matrix | Server | Service | Port | Protocol | Access | Purpose | |--------|---------|------|----------|--------|---------| | **Fortigate (WAN)** | Public Gateway | 443 | HTTPS | Public | SSL entry point | | Fortigate (WAN) | HTTP Redirect | 80 | HTTP | Public | Redirect to HTTPS | | **R11-REVPROXY-01** | NPM Proxy | 443 | HTTPS | LAN | SSL termination | | R11-REVPROXY-01 | NPM Proxy | 80 | HTTP | LAN | HTTP → HTTPS redirect | | R11-REVPROXY-01 | NPM Admin | 81 | HTTP | LAN | Admin panel | | R11-REVPROXY-01 | SSH | 22 | SSH | Admin | Remote management | | **NORDABIZ-01** | **Flask/Gunicorn** | **5000** | **HTTP** | **LAN** | **Application (CRITICAL!)** | | NORDABIZ-01 | PostgreSQL | 5432 | TCP | Localhost | Database | | NORDABIZ-01 | Nginx (System) | 80 | HTTP | LAN | ⚠️ DO NOT USE (causes redirect loop) | | NORDABIZ-01 | Nginx (System) | 443 | HTTPS | LAN | ⚠️ DO NOT USE | | NORDABIZ-01 | SSH | 22 | SSH | Admin | Remote management | | **r11-git-inpi** | Gitea HTTPS | 3000 | HTTPS | LAN | Git repository | | r11-git-inpi | SSH | 22 | SSH | Admin | Remote management | ### NAT/Port Forwarding Rules (Fortigate) ``` Public → Internal NAT Mappings: 85.237.177.83:443 → 10.22.68.250:443 (NPM Proxy - HTTPS) 85.237.177.83:80 → 10.22.68.250:80 (NPM Proxy - HTTP) Internal → Internal Routing: 10.22.68.250:* → 10.22.68.249:5000 (NPM → Flask) ⚠️ CRITICAL PORT 10.22.68.249:* → 127.0.0.1:5432 (Flask → PostgreSQL) 10.22.68.249:* → 10.22.68.180:3000 (Flask → Gitea) ``` ### Port Usage by Zone **Public Internet Zone:** - Port 443 (HTTPS) - Public website access - Port 80 (HTTP) - Redirects to HTTPS **DMZ Zone (R11-REVPROXY-01):** - Port 443 (HTTPS) - NPM SSL termination - Port 80 (HTTP) - NPM HTTP redirect - Port 81 (HTTP) - NPM admin panel (internal only) **Application Zone (NORDABIZ-01):** - **Port 5000 (HTTP) - Flask/Gunicorn application** ⚠️ CRITICAL - Port 5432 (TCP) - PostgreSQL (localhost only) - Port 80/443 (HTTP/HTTPS) - System nginx (DO NOT USE for app) **Internal Services Zone:** - Port 3000 (HTTPS) - Gitea --- ## SSL/TLS Configuration ### Let's Encrypt Certificate **Certificate Details:** - **Provider:** Let's Encrypt - **Managed By:** NPM (Nginx Proxy Manager) - **Certificate ID:** 27 - **Domains:** - nordabiznes.pl - www.nordabiznes.pl - **Key Type:** RSA 2048-bit - **Validity:** 90 days - **Renewal:** Automatic (30 days before expiry) - **ACME Challenge:** HTTP-01 **Certificate Storage:** - **Location (NPM):** `/data/letsencrypt/live/npm-27/` - **Files:** - `fullchain.pem` - Full certificate chain - `privkey.pem` - Private key - `cert.pem` - Certificate only - `chain.pem` - Intermediate certificates ### TLS Configuration ```nginx # NPM TLS Configuration (auto-generated) ssl_certificate /data/letsencrypt/live/npm-27/fullchain.pem; ssl_certificate_key /data/letsencrypt/live/npm-27/privkey.pem; # SSL Protocols ssl_protocols TLSv1.2 TLSv1.3; # Cipher Suites (Modern configuration) ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers off; # SSL Session ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; ``` ### Security Headers (NPM) ```http # Headers added by NPM for all requests Strict-Transport-Security: max-age=31536000; includeSubDomains X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block ``` ### SSL Verification Commands ```bash # Check certificate expiry echo | openssl s_client -connect nordabiznes.pl:443 -servername nordabiznes.pl 2>/dev/null | \ openssl x509 -noout -dates # Test SSL configuration curl -vI https://nordabiznes.pl 2>&1 | grep -E "(SSL|TLS|expire)" # Check HSTS header curl -I https://nordabiznes.pl | grep -i strict # Test HTTP/2 support curl -I --http2 https://nordabiznes.pl | head -1 # Comprehensive SSL test (requires ssllabs-scan) ssllabs-scan --quiet nordabiznes.pl ``` ### Certificate Renewal Process **Automatic Renewal (NPM handles this):** 1. NPM checks certificates 30 days before expiry 2. Initiates ACME HTTP-01 challenge with Let's Encrypt 3. Creates `.well-known/acme-challenge/` endpoint 4. Let's Encrypt validates domain ownership 5. New certificate issued and NPM reloads nginx 6. Zero downtime renewal **Manual Renewal (if automatic fails):** ```bash # SSH to NPM server ssh maciejpi@10.22.68.250 # Force certificate renewal docker exec nginx-proxy-manager_app_1 \ certbot renew --force-renewal # Reload nginx docker exec nginx-proxy-manager_app_1 nginx -s reload # Verify new certificate curl -vI https://nordabiznes.pl 2>&1 | grep "expire date" ``` --- ## Environment Variables ### Production Environment Variables **Location:** `/var/www/nordabiznes/.env` **Owner:** `www-data:www-data` **Permissions:** `0600` (read/write owner only) **⚠️ WARNING:** Never commit `.env` to version control! ### Required Variables ```bash # Flask Configuration SECRET_KEY= FLASK_ENV=production # Server Configuration PORT=5000 HOST=0.0.0.0 # Database Configuration DATABASE_URL=postgresql://nordabiz_app:@127.0.0.1:5432/nordabiz # Google Gemini API GOOGLE_GEMINI_API_KEY= # Google PageSpeed Insights API GOOGLE_PAGESPEED_API_KEY= # Google Places API GOOGLE_PLACES_API_KEY= # Brave Search API BRAVE_SEARCH_API_KEY= # Microsoft Graph API (OAuth 2.0) MS_GRAPH_CLIENT_ID= MS_GRAPH_CLIENT_SECRET= MS_GRAPH_TENANT_ID= # Email Configuration (Microsoft Graph) MAIL_DEFAULT_SENDER=noreply@nordabiznes.pl # Application URLs APP_URL=https://nordabiznes.pl VERIFY_EMAIL_URL=https://nordabiznes.pl/verify-email ``` ### Environment Variable Generation ```bash # Generate SECRET_KEY (64 random hex characters) python3 -c "import secrets; print(secrets.token_hex(32))" # Generate random password (32 characters) openssl rand -base64 32 # Verify .env file permissions ls -la /var/www/nordabiznes/.env # Expected: -rw------- 1 www-data www-data ... .env ``` ### Development Environment Variables **Location:** `.env` (in project root, git-ignored) **Template:** `.env.example` ```bash # Development configuration (localhost) DATABASE_URL=postgresql://nordabiz_app:NordaBiz2025Secure@127.0.0.1:5433/nordabiz APP_URL=http://localhost:5000 FLASK_ENV=development ``` **Note:** Development uses Docker PostgreSQL on port 5433 (not 5432) --- ## Database Configuration ### Production Database **Server:** NORDABIZ-01 (10.22.68.249) **DBMS:** PostgreSQL 14 **Database Name:** `nordabiz` **Port:** 5432 (localhost only) ### Database Users and Roles | User | Role | Permissions | Purpose | |------|------|-------------|---------| | `postgres` | Superuser | ALL | Database administration | | `nordabiz_app` | Application user | CRUD on all tables | Flask application | | `nordabiz_readonly` | Read-only | SELECT only | Reporting, backups | ### Connection Strings **Production (Flask app):** ``` postgresql://nordabiz_app:@127.0.0.1:5432/nordabiz ``` **Development (Docker):** ``` postgresql://nordabiz_app:NordaBiz2025Secure@127.0.0.1:5433/nordabiz ``` **Direct psql (production):** ```bash # As application user sudo -u www-data psql -U nordabiz_app -d nordabiz -h 127.0.0.1 # As postgres superuser sudo -u postgres psql nordabiz ``` ### PostgreSQL Configuration Files **Location:** `/etc/postgresql/14/main/` **postgresql.conf (Key Settings):** ```conf # Network Settings listen_addresses = 'localhost' # ⚠️ CRITICAL: localhost only! port = 5432 # Memory Settings shared_buffers = 256MB effective_cache_size = 1GB work_mem = 16MB # Connection Settings max_connections = 100 # Logging log_destination = 'stderr' logging_collector = on log_directory = '/var/log/postgresql' log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' log_statement = 'mod' # Log all modifications log_min_duration_statement = 1000 # Log slow queries (>1s) ``` **pg_hba.conf (Access Control):** ```conf # TYPE DATABASE USER ADDRESS METHOD # Local connections local all postgres peer local nordabiz nordabiz_app md5 # IPv4 local connections host nordabiz nordabiz_app 127.0.0.1/32 md5 # ⚠️ CRITICAL: No external connections allowed! # External access is blocked by listening on localhost only ``` ### Database Backup Configuration **Backup Location:** `/var/backups/nordabiz/` **Owner:** `postgres:postgres` **Retention:** 7 days **Daily Backup Cron:** ```bash # /etc/cron.d/nordabiz-backup 0 2 * * * postgres pg_dump -U nordabiz_app nordabiz | gzip > /var/backups/nordabiz/nordabiz_$(date +\%Y\%m\%d).sql.gz ``` **Manual Backup:** ```bash # Create backup sudo -u postgres pg_dump -U nordabiz_app nordabiz > /tmp/nordabiz_backup_$(date +%Y%m%d_%H%M%S).sql # Create compressed backup sudo -u postgres pg_dump -U nordabiz_app nordabiz | gzip > /tmp/nordabiz_backup.sql.gz # Restore from backup sudo -u postgres psql -U nordabiz_app nordabiz < /tmp/nordabiz_backup.sql ``` --- ## Gunicorn WSGI Configuration ### Gunicorn Settings **Location:** Configured in systemd service file **Socket:** `0.0.0.0:5000` **Workers:** 4 (recommended: 2-4 x CPU cores) **Worker Class:** `sync` (default) **Timeout:** 120 seconds **Max Requests:** 1000 (worker restart after 1000 requests) **Access Log:** `/var/log/nordabiznes/gunicorn_access.log` **Error Log:** `/var/log/nordabiznes/gunicorn_error.log` ### Gunicorn Command ```bash gunicorn \ --bind 0.0.0.0:5000 \ --workers 4 \ --timeout 120 \ --max-requests 1000 \ --access-logfile /var/log/nordabiznes/gunicorn_access.log \ --error-logfile /var/log/nordabiznes/gunicorn_error.log \ --log-level info \ app:app ``` ### Worker Calculation ```python # Recommended workers formula workers = (2 * num_cpu_cores) + 1 # For NORDABIZ-01 (4 vCPUs) workers = (2 * 4) + 1 = 9 # Maximum workers = 4 # Current (conservative) ``` ### Gunicorn Tuning Considerations | Parameter | Current | Tuning Notes | |-----------|---------|--------------| | Workers | 4 | Increase to 6-8 under high load | | Timeout | 120s | Sufficient for AI chat (Gemini API ~2-5s) | | Max Requests | 1000 | Prevents memory leaks | | Worker Class | sync | Consider `gevent` for WebSocket support | | Keep-Alive | 5s | Default, no tuning needed | --- ## Systemd Service Configuration ### Service File Location **File:** `/etc/systemd/system/nordabiznes.service` **Owner:** `root:root` **Permissions:** `0644` ### Complete Service Configuration ```ini [Unit] Description=Norda Biznes Partner - Flask Application After=network.target postgresql.service Requires=postgresql.service [Service] Type=simple User=www-data Group=www-data WorkingDirectory=/var/www/nordabiznes Environment="PATH=/var/www/nordabiznes/venv/bin" EnvironmentFile=/var/www/nordabiznes/.env ExecStart=/var/www/nordabiznes/venv/bin/gunicorn \ --bind 0.0.0.0:5000 \ --workers 4 \ --timeout 120 \ --max-requests 1000 \ --access-logfile /var/log/nordabiznes/gunicorn_access.log \ --error-logfile /var/log/nordabiznes/gunicorn_error.log \ --log-level info \ app:app # Restart policy Restart=always RestartSec=10 # Logging StandardOutput=journal StandardError=journal SyslogIdentifier=nordabiznes # Security NoNewPrivileges=true PrivateTmp=true [Install] WantedBy=multi-user.target ``` ### Service Management Commands ```bash # Start service sudo systemctl start nordabiznes # Stop service sudo systemctl stop nordabiznes # Restart service (after code changes) sudo systemctl restart nordabiznes # Reload service (graceful restart) sudo systemctl reload nordabiznes # Check status sudo systemctl status nordabiznes # Enable autostart on boot sudo systemctl enable nordabiznes # Disable autostart sudo systemctl disable nordabiznes # View logs sudo journalctl -u nordabiznes -f # View logs (last 100 lines) sudo journalctl -u nordabiznes -n 100 # View logs (since 1 hour ago) sudo journalctl -u nordabiznes --since "1 hour ago" ``` ### Service Restart After Changes ```bash # After modifying .env file sudo systemctl restart nordabiznes # After modifying Python code sudo systemctl restart nordabiznes # After modifying systemd service file sudo systemctl daemon-reload sudo systemctl restart nordabiznes # After database schema changes # (Usually no restart needed, but recommended) sudo systemctl restart nordabiznes ``` --- ## Git Repository Configuration ### Git Remotes | Remote | URL | Purpose | |--------|-----|---------| | **inpi** (primary) | `https://10.22.68.180:3000/maciejpi/nordabiz.git` | Internal Gitea (deployment source) | | **origin** | `git@github.com:pienczyn/nordabiz.git` | GitHub (cloud backup) | ### Production Git Configuration **Repository Location:** `/var/www/nordabiznes/` **User:** `www-data` **Branch:** `master` **Git Configuration (`/var/www/nordabiznes/.git/config`):** ```ini [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote "inpi"] url = https://10.22.68.180:3000/maciejpi/nordabiz.git fetch = +refs/heads/*:refs/remotes/inpi/* [remote "origin"] url = git@github.com:pienczyn/nordabiz.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = inpi merge = refs/heads/master [http] sslVerify = false # Required for self-signed Gitea cert ``` ### Gitea Server Configuration **Server:** r11-git-inpi **IP:** 10.22.68.180 **Port:** 3000 (HTTPS) **URL:** https://10.22.68.180:3000/ **User:** `maciejpi` **Repository:** `maciejpi/nordabiz` ### Deployment Workflow ```bash # On development machine (Mac) git push inpi master # Push to internal Gitea git push origin master # Backup to GitHub (optional) # On production server (NORDABIZ-01) ssh maciejpi@10.22.68.249 cd /var/www/nordabiznes sudo -u www-data git pull # Pull from Gitea sudo systemctl restart nordabiznes # Restart application curl -I https://nordabiznes.pl/health # Verify deployment ``` ### Git Commands for Production ```bash # Check current branch and status sudo -u www-data git branch sudo -u www-data git status # Pull latest changes sudo -u www-data git pull # View commit history sudo -u www-data git log --oneline -10 # Rollback to previous commit (emergency) sudo -u www-data git reset --hard HEAD~1 # Force pull (discard local changes) sudo -u www-data git fetch --all sudo -u www-data git reset --hard inpi/master ``` ### SSH Keys for Git Access **Production Server:** - Location: `/home/www-data/.ssh/` - Public key: `id_rsa.pub` - Private key: `id_rsa` - Known hosts: `known_hosts` (includes Gitea fingerprint) **Development Machine:** - GitHub SSH key: `~/.ssh/id_rsa` (GitHub account: `pienczyn`) - Gitea HTTP access: Username/password (no SSH key required due to HTTPS) --- ## Critical File Paths ### Application Files | Path | Description | Owner | Permissions | |------|-------------|-------|-------------| | `/var/www/nordabiznes/` | Application root directory | www-data:www-data | 0755 | | `/var/www/nordabiznes/app.py` | Main Flask application | www-data:www-data | 0644 | | `/var/www/nordabiznes/.env` | Environment variables (secrets) | www-data:www-data | 0600 | | `/var/www/nordabiznes/venv/` | Python virtual environment | www-data:www-data | 0755 | | `/var/www/nordabiznes/static/` | Static assets (CSS, JS, images) | www-data:www-data | 0755 | | `/var/www/nordabiznes/templates/` | Jinja2 templates | www-data:www-data | 0755 | | `/var/www/nordabiznes/database.py` | SQLAlchemy models | www-data:www-data | 0644 | | `/var/www/nordabiznes/scripts/` | Background scripts | www-data:www-data | 0755 | ### Configuration Files | Path | Description | Owner | Permissions | |------|-------------|-------|-------------| | `/etc/systemd/system/nordabiznes.service` | Systemd service file | root:root | 0644 | | `/etc/postgresql/14/main/postgresql.conf` | PostgreSQL configuration | postgres:postgres | 0644 | | `/etc/postgresql/14/main/pg_hba.conf` | PostgreSQL access control | postgres:postgres | 0640 | ### Log Files | Path | Description | Rotation | Owner | |------|-------------|----------|-------| | `/var/log/nordabiznes/gunicorn_access.log` | Gunicorn access log | Daily | www-data | | `/var/log/nordabiznes/gunicorn_error.log` | Gunicorn error log | Daily | www-data | | `/var/log/postgresql/postgresql-*.log` | PostgreSQL logs | Weekly | postgres | | `journalctl -u nordabiznes` | Systemd service logs | 30 days | root | ### Backup Locations | Path | Description | Retention | Owner | |------|-------------|-----------|-------| | `/var/backups/nordabiz/` | Daily database backups | 7 days | postgres | | `/home/maciejpi/backups/` | Manual backups | Manual | maciejpi | ### Temporary Files | Path | Description | Cleanup | Owner | |------|-------------|---------|-------| | `/tmp/` | Temporary files (uploads, etc.) | Reboot | Various | | `/var/tmp/` | Persistent temp files | 30 days | Various | --- ## Firewall and Network Rules ### Fortigate Firewall Configuration **WAN Interface:** `wan1` (85.237.177.83) **LAN Interface:** `internal` (10.22.68.1) **NAT Rules (Destination NAT / Port Forwarding):** ``` Rule 1: HTTPS External: 85.237.177.83:443 → Internal: 10.22.68.250:443 Protocol: TCP Action: DNAT Rule 2: HTTP External: 85.237.177.83:80 → Internal: 10.22.68.250:80 Protocol: TCP Action: DNAT ``` **Firewall Policies:** ``` Policy 1: Allow HTTPS from Internet Source: all Destination: 10.22.68.250 Service: HTTPS (443) Action: ACCEPT Policy 2: Allow HTTP from Internet Source: all Destination: 10.22.68.250 Service: HTTP (80) Action: ACCEPT Policy 3: Allow SSH from Admin Network Source: admin_network (10.22.68.0/24) Destination: all_internal_servers Service: SSH (22) Action: ACCEPT Policy 4: Allow Internal Traffic Source: 10.22.68.0/24 Destination: 10.22.68.0/24 Service: any Action: ACCEPT Policy 5: Default Deny Source: all Destination: all Service: any Action: DENY ``` ### Linux iptables (NORDABIZ-01) **Status:** Not actively used (relies on Fortigate firewall) **Default Policy:** ```bash # Check iptables status sudo iptables -L -n -v # Expected: Mostly ACCEPT policies (Fortigate handles filtering) ``` ### PostgreSQL Access Control **Network Access:** `listen_addresses = 'localhost'` (127.0.0.1 only) **pg_hba.conf Rules:** ``` # Only allow localhost connections host nordabiz nordabiz_app 127.0.0.1/32 md5 # Block all other addresses (implicit) ``` --- ## Backup and Recovery Locations ### Database Backups **Automated Daily Backups:** - **Location:** `/var/backups/nordabiz/` - **Filename Pattern:** `nordabiz_YYYYMMDD.sql.gz` - **Schedule:** 2:00 AM daily (cron) - **Retention:** 7 days (automatic cleanup) - **Size:** ~5-10 MB compressed **Manual Backups:** ```bash # Create manual backup sudo -u postgres pg_dump -U nordabiz_app nordabiz > \ /home/maciejpi/backups/nordabiz_manual_$(date +%Y%m%d_%H%M%S).sql # Restore from backup sudo -u postgres psql -U nordabiz_app nordabiz < \ /home/maciejpi/backups/nordabiz_manual_20260110_120000.sql ``` ### Application Backups **Git Repository:** - **Primary:** Gitea (10.22.68.180) - internal backup - **Secondary:** GitHub (github.com/pienczyn/nordabiz) - cloud backup **VM Snapshots (Proxmox):** - **Location:** Proxmox Backup Server - **Schedule:** Weekly - **Retention:** 4 weeks - **VM ID:** 249 (NORDABIZ-01) ### Configuration Backups **NPM Configuration:** ```bash # Backup NPM database ssh maciejpi@10.22.68.250 \ "docker cp nginx-proxy-manager_app_1:/data/database.sqlite /tmp/npm_backup.sqlite" # Copy to local scp maciejpi@10.22.68.250:/tmp/npm_backup.sqlite ~/backups/ ``` **Environment Variables:** ```bash # Backup .env file (contains secrets!) sudo cp /var/www/nordabiznes/.env /home/maciejpi/backups/.env.backup sudo chmod 600 /home/maciejpi/backups/.env.backup ``` ### Disaster Recovery Procedure **Complete Server Rebuild:** 1. **Restore VM from Proxmox snapshot** (or provision new VM) 2. **Install base packages:** ```bash sudo apt update sudo apt install -y python3 python3-venv python3-pip postgresql-14 git nginx ``` 3. **Restore database:** ```bash sudo -u postgres createdb nordabiz sudo -u postgres psql nordabiz < /path/to/backup.sql ``` 4. **Clone application:** ```bash sudo mkdir -p /var/www/nordabiznes sudo chown www-data:www-data /var/www/nordabiznes sudo -u www-data git clone https://10.22.68.180:3000/maciejpi/nordabiz.git /var/www/nordabiznes ``` 5. **Restore .env file:** ```bash sudo cp /path/to/.env.backup /var/www/nordabiznes/.env sudo chown www-data:www-data /var/www/nordabiznes/.env sudo chmod 600 /var/www/nordabiznes/.env ``` 6. **Install Python dependencies:** ```bash cd /var/www/nordabiznes sudo -u www-data python3 -m venv venv sudo -u www-data venv/bin/pip install -r requirements.txt ``` 7. **Configure systemd service:** ```bash sudo cp nordabiznes.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable nordabiznes sudo systemctl start nordabiznes ``` 8. **Reconfigure NPM:** - Update proxy host 27 to point to new server IP - Verify `forward_port = 5000` 9. **Verify deployment:** ```bash curl -I https://nordabiznes.pl/health # Expected: HTTP/2 200 OK ``` --- ## Configuration Management ### Configuration Change Procedure **⚠️ ALWAYS follow this procedure for production changes:** 1. **Backup current configuration** ```bash # Database sudo -u postgres pg_dump nordabiz > /tmp/backup_before_change.sql # Application cd /var/www/nordabiznes sudo -u www-data git status # Ensure clean state ``` 2. **Test changes in development** ```bash # On local machine # Test with Docker PostgreSQL on port 5433 python3 app.py # Verify functionality ``` 3. **Document the change** - Update CLAUDE.md if architecture changes - Update this document if configuration changes - Add entry to CHANGELOG.md 4. **Apply change to production** ```bash # SSH to production ssh maciejpi@10.22.68.249 # Pull changes cd /var/www/nordabiznes sudo -u www-data git pull # Restart service sudo systemctl restart nordabiznes ``` 5. **Verify change** ```bash # Check service status sudo systemctl status nordabiznes # Check application health curl -I https://nordabiznes.pl/health # Expected: HTTP/2 200 OK # Monitor logs sudo journalctl -u nordabiznes -f ``` 6. **Rollback procedure (if needed)** ```bash # Stop service sudo systemctl stop nordabiznes # Rollback code sudo -u www-data git reset --hard HEAD~1 # Rollback database (if needed) sudo -u postgres psql nordabiz < /tmp/backup_before_change.sql # Start service sudo systemctl start nordabiznes ``` ### Configuration Version Control **Tracked in Git:** - Application code (`app.py`, `*.py`) - Templates (`templates/`) - Static assets (`static/`) - Requirements (`requirements.txt`) - Documentation (`docs/`, `CLAUDE.md`) **NOT tracked in Git (secrets):** - `.env` (environment variables) - `*.pyc` (Python bytecode) - `venv/` (virtual environment) - `__pycache__/` (Python cache) - Log files **Tracked externally (infrastructure as code):** - NPM configuration (stored in NPM SQLite database) - Systemd service files (manual versioning) - PostgreSQL configuration (manual versioning) --- ## Verification Checklist ### Pre-Deployment Verification - [ ] Code changes tested in development environment - [ ] Database migrations tested (if applicable) - [ ] `.env` variables updated (if needed) - [ ] No secrets committed to Git - [ ] CHANGELOG.md updated - [ ] Documentation updated (if architecture changed) ### Post-Deployment Verification - [ ] **NPM configuration verified: `forward_port = 5000`** ⚠️ CRITICAL - [ ] Website accessible: `curl -I https://nordabiznes.pl/health` returns 200 - [ ] SSL certificate valid: No browser warnings - [ ] Database connection working: Query returns data - [ ] Service running: `systemctl status nordabiznes` shows active - [ ] No errors in logs: `journalctl -u nordabiznes -n 50` - [ ] External APIs working: Test chat, SEO audit - [ ] Authentication working: Test login/logout - [ ] Static assets loading: Check browser console for 404s ### NPM Configuration Verification (CRITICAL!) ```bash # ⚠️ ALWAYS run this after ANY NPM changes! # 1. Check proxy host configuration ssh maciejpi@10.22.68.250 "docker exec nginx-proxy-manager_app_1 \ sqlite3 /data/database.sqlite \ \"SELECT id, domain_names, forward_host, forward_port FROM proxy_host WHERE id = 27;\"" # Expected output: # 27|["nordabiznes.pl","www.nordabiznes.pl"]|10.22.68.249|5000 # ^^^^ # MUST BE 5000! # 2. Test website accessibility curl -I https://nordabiznes.pl/health # Expected: HTTP/2 200 OK # 3. Test from external network (use phone without WiFi) # Browse to: https://nordabiznes.pl # Should load without ERR_TOO_MANY_REDIRECTS ``` ### Database Verification ```bash # Check database connectivity sudo -u www-data psql -U nordabiz_app -d nordabiz -h 127.0.0.1 -c "SELECT COUNT(*) FROM companies;" # Check recent data sudo -u www-data psql -U nordabiz_app -d nordabiz -h 127.0.0.1 -c \ "SELECT name, slug FROM companies ORDER BY created_at DESC LIMIT 5;" # Check database size sudo -u postgres psql -c "SELECT pg_size_pretty(pg_database_size('nordabiz'));" ``` ### Service Health Verification ```bash # Systemd service status sudo systemctl status nordabiznes # Process check ps aux | grep gunicorn # Port listening check sudo netstat -tlnp | grep 5000 # Expected: gunicorn listening on 0.0.0.0:5000 # Application logs (last 50 lines) sudo journalctl -u nordabiznes -n 50 --no-pager # Error log check (should be minimal) sudo journalctl -u nordabiznes -p err -n 20 ``` --- ## Emergency Contacts and Resources ### Server Access | Server | IP | SSH User | Purpose | |--------|-----|----------|---------| | NORDABIZ-01 | 10.22.68.249 | `maciejpi` | Application server | | R11-REVPROXY-01 | 10.22.68.250 | `maciejpi` | NPM proxy | | r11-git-inpi | 10.22.68.180 | `maciejpi` | Gitea repository | **⚠️ NEVER SSH as root!** Always use `maciejpi` user and `sudo` for elevated privileges. ### Key Commands for Incidents ```bash # 1. Quick health check curl -I https://nordabiznes.pl/health # 2. Check service status ssh maciejpi@10.22.68.249 "sudo systemctl status nordabiznes" # 3. Check NPM proxy configuration ssh maciejpi@10.22.68.250 "docker exec nginx-proxy-manager_app_1 \ sqlite3 /data/database.sqlite \ \"SELECT forward_port FROM proxy_host WHERE id = 27;\"" # 4. View recent errors ssh maciejpi@10.22.68.249 "sudo journalctl -u nordabiznes -p err -n 20" # 5. Restart application ssh maciejpi@10.22.68.249 "sudo systemctl restart nordabiznes" ``` ### Documentation Resources - **This Document:** `docs/architecture/08-critical-configurations.md` - **Incident Report:** `docs/INCIDENT_REPORT_20260102.md` - **Deployment Architecture:** `docs/architecture/03-deployment-architecture.md` - **Network Topology:** `docs/architecture/07-network-topology.md` - **HTTP Request Flow:** `docs/architecture/flows/06-http-request-flow.md` - **Main Documentation:** `CLAUDE.md` --- ## Appendix: Quick Reference Cards ### Quick Reference: NPM Proxy ``` Proxy Host ID: 27 Domains: nordabiznes.pl, www.nordabiznes.pl Backend: 10.22.68.249:5000 ⚠️ PORT 5000 (NOT 80!) SSL: Let's Encrypt (auto-renew) ``` ### Quick Reference: Port Mappings ``` Internet → Fortigate → NPM → Flask :443 → :443 → :5000 ⚠️ CRITICAL: NPM → Flask must use port 5000 ``` ### Quick Reference: Database ``` Host: 127.0.0.1 (localhost only) Port: 5432 Database: nordabiz User: nordabiz_app ``` ### Quick Reference: Service Management ```bash sudo systemctl restart nordabiznes # Restart app sudo journalctl -u nordabiznes -f # View logs curl -I https://nordabiznes.pl/health # Test health ``` ### Quick Reference: Emergency Rollback ```bash ssh maciejpi@10.22.68.249 cd /var/www/nordabiznes sudo systemctl stop nordabiznes sudo -u www-data git reset --hard HEAD~1 sudo systemctl start nordabiznes curl -I https://nordabiznes.pl/health ``` --- **Document Maintenance:** - Update this document after ANY configuration changes - Verify accuracy quarterly - Include in onboarding materials for new team members - Reference in incident response procedures **Last Verified:** 2026-01-10 **Next Review:** 2026-04-10