Ctrl K
ring2all.com

Debian 13 Packaging & Clustering Series โ€” Part 10: Securing and Exposing the External API

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

  1. 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;
       }
   }
   

  1. 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

  1. 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;
       }
   }
   

  1. 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.
AI Assistant

๐Ÿ‘‹ Hello! I'm your Ring2All documentation assistant. I can help you find information about configuring and using the Ring2All PBX platform.

How can I help you today?