--- title: "10. External API & Security (Debian 13)" description: "Documentation for 10. External API & Security" --- In the previous parts of this series, we successfully packaged and deployed the Ring2All core databases, Kamailio SBCs, GlusterFS clusters, and RTPEngine media nodes. In this tenth installment, we will focus on exposing and securing the **Ring2All Fastify API Backend** for external integrations (such as CRMs, custom ERP systems, or notification bots). By default, the Ring2All API backend listens locally on port `3000`/`3001`. We will deploy a secure **Nginx Reverse Proxy** on the Portal/Admin nodes to expose the API over HTTPS (port `443`) and write custom **NFTables** filtering rules (the native packet filter framework in Debian 13) to restrict API access to trusted external source IPs. --- ## ๐Ÿ› ๏ธ Step 1: Configuring Nginx Secure Reverse Proxy To proxy incoming external HTTPS requests to our internal API listener on port `3000`, we configure Nginx with upstream proxy blocks and secure SSL/TLS protocols. 1. Create a new Nginx virtual host configuration: `nano /etc/nginx/sites-available/ring2all-api.conf` 2. Add the following upstream and server block config: ```nginx upstream ring2all_api { server 127.0.0.1:3000; keepalive 32; } server { listen 443 ssl http2; server_name pbx.softswitchone.com; # SSL Certificates ssl_certificate /etc/letsencrypt/live/pbx.softswitchone.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/pbx.softswitchone.com/privkey.pem; # Strong TLS configuration (Debian 13 default openssl 3.x) ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; # Security Headers add_header X-Frame-Options "DENY" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; # Logging access_log /var/log/nginx/ring2all_api_access.log; error_log /var/log/nginx/ring2all_api_error.log warn; # Proxy to Fastify Backend API location /api/ { proxy_pass http://ring2all_api/; proxy_http_version 1.1; # Keep-alive headers proxy_set_header Connection ""; # Real IP headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; # Timeouts proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; # Max upload limit (e.g. for CSV bulk provisioning imports) client_max_body_size 100M; } } ``` 3. Enable the configuration and test Nginx: ```bash ln -s /etc/nginx/sites-available/ring2all-api.conf /etc/nginx/sites-enabled/ nginx -t systemctl reload nginx ``` --- ## ๐Ÿ”’ Step 2: Securing Access with NFTables (Debian 13 Native) Debian 13 utilizes `nftables` as the default packet filtering framework, replacing the legacy iptables backend. We will define an address set representing authorized CRM and external developer IPs, allowing traffic to port `443` only from those addresses while dropping all other requests. 1. Open the nftables configuration file: `nano /etc/nftables.conf` 2. Update the input chain rules to define a set of allowed external IPs. Replace the configuration with the following structure: ```nftables #!/usr/sbin/nft -f flush ruleset table inet filter { # Set of authorized external IPs (CRMs, third-party developers, webhooks) set authorized_api_ips { type ipv4_addr flags interval elements = { 192.168.1.50, # Corporate Office IP 76.13.102.153, # Dev Server IP 104.16.0.0/12 # CRM Provider / HubSpot webhooks IP block example } } chain input { type filter hook input priority filter; policy drop; # Allow loopback interface iif "lo" accept # Allow established/related state connections ct state established,related accept # Drop invalid connections ct state invalid drop # Allow SSH (Port 22) - Restrict to Admin subnet in production tcp dport 22 accept # Allow HTTP (Port 80) for Let's Encrypt SSL verification challenges tcp dport 80 accept # Allow HTTPS (Port 443) only from the authorized sets ip saddr @authorized_api_ips tcp dport 443 accept # Logging and dropping unauthorized packets log prefix "NFTABLES-INPUT-BLOCKED: " flags all counter drop } chain forward { type filter hook forward priority filter; policy drop; } chain output { type filter hook output priority filter; policy accept; } } ``` 3. Validate and load the new nftables rules: ```bash # Test rule compilation syntax nft -c -f /etc/nftables.conf # Reload service systemctl restart nftables systemctl enable nftables ``` --- ## ๐Ÿงช Step 3: Verification Once Nginx and NFTables are loaded on your Debian 13 portal server: ### 1. Test from an Unauthorized IP Address Attempting to connect to the API from an IP not listed inside the `authorized_api_ips` set will block connection negotiations: ```bash curl -I -v https://pbx.softswitchone.com/api/telephony/extensions # Output should timeout or report "Connection refused/timed out" ``` ### 2. Test from an Authorized IP Address Connecting from a whitelisted IP with the correct API Key header will query the platform successfully: ```bash curl -i -H "X-API-Key: ak_your_key" \ https://pbx.softswitchone.com/api/telephony/extensions # Output: HTTP/1.1 200 OK ``` ### 3. Check NFTables Block Logs You can monitor blocked attempts in real-time in the system log: ```bash journalctl -k -f | grep "NFTABLES-INPUT-BLOCKED" ``` --- *This concludes Part 10 of our series. Exposing your Ring2All cluster to external CRM integrations is now completely locked down and secure.*