ip2nginx/README.md

6.4 KiB
Raw Blame History

ip2nginx

ip2nginx is a lightweight and secure system for dynamically updating NGINX reverse proxy configurations based on IP address changes reported by remote systems (e.g., pfSense). It is particularly useful in scenarios where IP addresses change dynamically and need to be synchronized with a web servers reverse proxy configuration.

⚙️ Features

  • Accepts remote updates via update.php (must be present on the server).
  • Logs all changes to log.json.
  • Access is controlled using tokens stored in token.json.
  • Protects against abuse by blocking IPs after repeated failed attempts, using blocklist.json and failures.json.
  • The core function is to locate a specific location block inside the domains nginx.conf and update only the proxy_pass value — without overwriting the entire file.
  • Automatically reloads NGINX using nginx -t && systemctl reload nginx.

📁 Project Structure

ip2nginx/
├── .htaccess             # Restricts access, routes all requests to updater
├── updater.php           # Applies proxy_pass updates to nginx.conf
├── update.php            # Processes and applies external IP update requests
├── run.sh                # CLI wrapper script for triggering update
├── index.php             # Default entry point and fallback error handling
├── data/                 # Data storage directory
│   ├── meta.json         # Central metadata file for all domains
│   ├── token.json        # Authorized tokens for each client
│   ├── log.json          # Log of updates and timestamps
│   ├── blocklist.json    # IPs blocked after repeated failed attempts
│   └── failures.json     # Failed authentication tracking

Example Entry in token.json

{
  "domain1.to.com": "SECRET_TOKEN_8v73jDKsdLzAq9DkeUz1",
  "domain2.to.com": "SECRET_TOKEN_3im83jUj28mjo2mI23un"
}

Example Entry in meta.json

{
  "domain1.to.com": {
    "domain": "domain.from.com",
    "ip": "192.0.2.4",
    "port": "443",
    "protocol": "https",
    "location": "/",
    "time": "2025-05-16T09:00:00+00:00",
    "changed": 1
  }
}

🚀 Remote update Process: update.php

The API supports both GET and POST requests, though POST is recommended to prevent token caching by proxies or browsers.

Parameter Required Description
name Identifier for the configuration entry (e.g., domain1.to.com)
token Secret token assigned to the client for authentication
ip New public IP address (auto-detected if omitted)
domain Target domain name to connect to (e.g., domain.from.com)
(default: IP address)
port Proxy port (default: 443 for HTTPS, 80 for HTTP)
protocol Protocol to use: http or https (default: http)
location Specific location block in NGINX to update (default: /)

If the domain, IP, port, or protocol differ from the previously saved values, the entry in meta.json is automatically marked with "changed": 1.

🚀 Local update Process: updater.php

This script is meant to be run via CLI (e.g. cronjob). It will:

  1. Load all entries from meta.json
  2. Process only those marked as "changed": 1
  3. Locate the virtual host config: /var/www/vhosts/system/<domain>/conf/nginx.conf
  4. Replace only the proxy_pass inside the matching location block
  5. Validate and reload Nginx (sudo nginx -t && sudo systemctl reload nginx)
  6. Reset the "changed" flag in meta.json

⏱ Cronjob Setup: Running run.sh Every 5 Minutes

To automatically apply updates to nginx.conf when new data is received via update.php, you should schedule the run.sh script to run regularly. This ensures that any entries marked as "changed": 1 in meta.json are processed and deployed without manual intervention.

To run the update script every 5 or 10 minutes as root (required for writing to NGINX config files and reloading the server):

  1. Open the root users crontab:
sudo crontab -e
  1. Add the following line:
*/5 * * * * /path/to/ip2nginx/run.sh

Replace /path/to/ip2nginx/ with the actual path where your run.sh script is located.

Why It Must Run as Root

The updater modifies system-level files, typically located in:

/var/www/vhosts/system/<domain>/conf/nginx.conf

These files usually require root privileges for writing. Additionally, reloading NGINX via:

sudo nginx -t && sudo systemctl reload nginx

also requires elevated permissions. If run.sh is not run as root, the updates will silently fail or be skipped due to insufficient access rights.

🛡 Security

  • .htaccess blocks direct access to internal logic.
  • Only HTTPS connections should be used.
  • Only update.php is directly accessible. All other access is routed through index.php.
  • All access is name and token-authenticated
  • IP addresses are blocked for 48 hours after 3 failed attempts
  • API responses are intentionally generic to prevent brute-force probing

🔄 Usage Example from pfSense

You can create a cron task in pfSense or use a shell script to send updated IP info to the server:

#!/bin/sh

SERVER="https://your-server.com/ip2nginx"
NAME="domain1.to.com"
DOMAIN="domain.from.com"
TOKEN="YOUR_SECRET_TOKEN"

curl -s -X POST "$SERVER/update.php" \
  -d "name=$NAME" \
  -d "domain=$DOMAIN" \
  -d "protocol=https" \
  -d "port=443" \
  -d "token=$TOKEN"

OR

curl -s -X POST "https://your-server.com/ip2nginx/update.php" "name=domain1.to.com" -d "token=SECRET_TOKEN_8v73jDKsdLzAq9DkeUz1" -d "protocol=https"

Add this script to pfSense via System > Advanced > Cron and run it every 5 or 10 minutes.

Dependencies

  • PHP 7.4+
  • nginx installed with permissions to reload via systemctl
  • curl for shell scripts (on client side)
  • Token-based access configuration in token.json

📜 License

MIT or similar — free to use, modify, and deploy.


Created by SAFE-CAP / https://safe-cap.com / Alexander Schiemann