# 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=<random-64-character-hex-string>
FLASK_ENV=production

# Server Configuration
PORT=5000
HOST=0.0.0.0

# Database Configuration
DATABASE_URL=postgresql://nordabiz_app:<password>@127.0.0.1:5432/nordabiz

# Google Gemini API
GOOGLE_GEMINI_API_KEY=<gemini-api-key>

# Google PageSpeed Insights API
GOOGLE_PAGESPEED_API_KEY=<pagespeed-api-key>

# Google Places API
GOOGLE_PLACES_API_KEY=<places-api-key>

# Brave Search API
BRAVE_SEARCH_API_KEY=<brave-api-key>

# Microsoft Graph API (OAuth 2.0)
MS_GRAPH_CLIENT_ID=<client-id>
MS_GRAPH_CLIENT_SECRET=<client-secret>
MS_GRAPH_TENANT_ID=<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:<password>@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
