257 lines
8.6 KiB
Markdown
257 lines
8.6 KiB
Markdown
# ip2nginx
|
||
<p align="center">
|
||
<a href="https://safe-cap.com/" target="_blank">
|
||
<img src="img/ip2nginx-small.png">
|
||
</a>
|
||
<br><br>
|
||
<img src="https://img.shields.io/badge/version-0.0.1-green.svg?style=for-the-badge">
|
||
<a href="https://www.paypal.com/donate/?hosted_button_id=JNFS79EFEM7C6" target="_blank">
|
||
<img src="https://img.shields.io/badge/Donate-PayPal-blue.svg?style=for-the-badge">
|
||
</a>
|
||
</p>
|
||
|
||
---
|
||
|
||
## 💡 Project Overview
|
||
|
||
**ip2nginx** is a lightweight and secure system for dynamically updating NGINX reverse proxy configurations based on public IP address changes, typically reported by edge devices like **pfSense**. It ensures that NGINX always routes traffic through the correct IP, even in dynamic environments.
|
||
|
||
---
|
||
|
||
<!-- TOC -->
|
||
## 📚 Table of Contents
|
||
|
||
- [💡 Project Overview](#-project-overview)
|
||
- [🏠 What is ip2nginx?](#-what-is-ip2nginx)
|
||
- [💡 Example Use Case](#-example-use-case)
|
||
- [⚙️ Features](#-features)
|
||
- [📁 Project Structure](#-project-structure)
|
||
- [🚀 Update Process: update.php](#-remote-update-api-updatephp)
|
||
- [🚀 Update Process: updater.php](#-update-process-updaterphp)
|
||
- [🛠 Environment Setup: check_env.php](#-check_envphp-environment-setup)
|
||
- [📅 Cron Setup with run.sh](#-cron-setup-runsh)
|
||
- [🔄 Usage Example from pfSense](#-pfsense-shell-example)
|
||
- [✅ Example Entry in token.json](#-example-tokenjson)
|
||
- [✅ Example Entry in meta.json](#-example-metajson)
|
||
- [🛡 Security](#-security-highlights)
|
||
- [✅ Requirements](#-requirements)
|
||
- [📜 License](#-license)
|
||
- [🤝 Author](#-author)
|
||
<!-- /TOC -->
|
||
|
||
---
|
||
|
||
🏠 What is ip2nginx?
|
||
|
||
ip2nginx is a self-hosted system that allows you to securely expose services running on your private home network (e.g. NAS, internal web interfaces, or a self-hosted app) under your own domain — without using third-party dynamic DNS services.
|
||
|
||
Instead of changing DNS records, it updates the reverse proxy (NGINX) configuration on your public server — making it the only point that needs to be publicly reachable.
|
||
🔐 Why is this more secure?
|
||
|
||
Your home server does not need to be exposed to the entire internet. Only your external server (running ip2nginx) needs access. This allows you to:
|
||
|
||
Restrict incoming firewall access at home to just one remote IP (your public server).
|
||
|
||
Avoid direct exposure of your internal services to DDOS or scanning attempts.
|
||
|
||
Offload all public traffic to the external server, preventing your home bandwidth from being overwhelmed.
|
||
|
||
⚙️ How it works:
|
||
|
||
Your home gateway (e.g. pfSense or another device) periodically sends its current public IP to your external server using an authenticated API call.
|
||
|
||
The external server updates only the proxy_pass directive inside a specific location block in the NGINX config for your domain.
|
||
|
||
NGINX is automatically reloaded to apply the changes.
|
||
|
||
From the outside world, visitors reach your external server, which transparently proxies to your home server — using your latest IP.
|
||
|
||
This gives you full control, avoids third-party dependencies, and increases the security of your home infrastructure.
|
||
|
||
<p align="center">
|
||
<img src="https://safe-cap.com/git/ip2nginx-server-small.png" alt="Diagram of a secure home-server access flow using an external NGINX proxy and API updates from the home server.">
|
||
<br><br>
|
||
</p>
|
||
|
||
---
|
||
|
||
## 💡 Example Use Case
|
||
You want to host https://home.example.com and route it to a web interface at your home (like pfSense or a Raspberry Pi), but your IP changes regularly due to your ISP.
|
||
|
||
With ip2nginx, the server automatically updates the NGINX reverse proxy so your domain continues working — securely and without dynamic DNS services.
|
||
|
||
---
|
||
|
||
## ⚙️ Features
|
||
|
||
- Accepts remote updates via `update.php` using **token-authenticated** requests.
|
||
- Supports both `POST` and `GET`, though **POST is preferred** to avoid token caching.
|
||
- Updates only the `proxy_pass` line in the relevant `location` block of `nginx.conf`.
|
||
- Automatically marks entries in `meta.json` as `"changed": 1` when input changes.
|
||
- Logs all changes to `log.json` with timestamps.
|
||
- Automatically reloads NGINX: `nginx -t && systemctl reload nginx` (requires root).
|
||
- Built-in abuse protection: failed requests tracked and blocked.
|
||
- `.htaccess` ensures that only `update.php` is externally accessible.
|
||
|
||
---
|
||
|
||
## 📁 Project Structure
|
||
|
||
```
|
||
ip2nginx/
|
||
├── index.php # Shared configuration and fallback error handler
|
||
├── update.php # Receives incoming remote IP update requests
|
||
├── updater.php # CLI-only: applies changes to nginx.conf if marked
|
||
├── run.sh # Wrapper script for cron automation
|
||
├── check_env.php # Environment validator and bootstrapper
|
||
├── .htaccess # Blocks unauthorized access, routes traffic
|
||
├── data/
|
||
│ ├── meta.json # Stores current configuration state per domain
|
||
│ ├── token.json # Stores allowed tokens (auth)
|
||
│ ├── log.json # Stores audit log of changes
|
||
│ ├── blocklist.json # Temporarily blocked IPs (48h ban)
|
||
│ └── failures.json # Tracks failed attempts per IP
|
||
```
|
||
|
||
---
|
||
|
||
## 🌐 Remote Update API: `update.php`
|
||
|
||
Supports **POST** (preferred) and **GET** methods.
|
||
|
||
| Parameter | Required | Description |
|
||
|------------|----------|-----------------------------------------------------------------------------|
|
||
| `name` | ✅ | Identifier (e.g. `domain1.to.com`) |
|
||
| `token` | ✅ | Secret token assigned for this name |
|
||
| `ip` | ❌ | New public IP (default: auto-detected from request) |
|
||
| `domain` | ❌ | Backend domain to proxy to (default: same as IP) |
|
||
| `port` | ❌ | Port number (default: 443 for https, 80 for http) |
|
||
| `protocol` | ❌ | One of `http` or `https` (default: `https`) |
|
||
|
||
Any change in `ip`, `domain`, `port`, or `protocol` triggers `"changed": 1` in `meta.json`.
|
||
|
||
If **any parameter is received via GET**, then `ip` and `domain` will be overridden with the **client’s real IP** for security.
|
||
|
||
---
|
||
|
||
## 🧩 Update Process: `updater.php`
|
||
|
||
To apply updates made via `update.php`:
|
||
|
||
1. Load all entries from `meta.json`
|
||
2. Check for entries marked `"changed": 1`
|
||
3. Find `/var/www/vhosts/system/<domain>/conf/nginx.conf`
|
||
4. Modify the appropriate `location` block’s `proxy_pass` directive only
|
||
5. Validate and reload NGINX
|
||
6. Reset `"changed": 0`
|
||
|
||
---
|
||
|
||
## 🛠 `check_env.php`: Environment Setup
|
||
|
||
This CLI script validates:
|
||
|
||
- Config files and permissions
|
||
- JSON structure of each config file
|
||
- Auto-creates missing files (with defaults)
|
||
- Token file includes example if missing
|
||
|
||
---
|
||
|
||
## ⏱ Cron Setup: `run.sh`
|
||
|
||
To automate updates, add `run.sh` to your crontab as root:
|
||
|
||
```sh
|
||
sudo crontab -e
|
||
```
|
||
|
||
Then add:
|
||
|
||
```cron
|
||
*/5 * * * * /path/to/ip2nginx/run.sh
|
||
```
|
||
|
||
This ensures automatic application of proxy changes to NGINX config and reloads.
|
||
|
||
---
|
||
|
||
## 🔄 pfSense Shell Example
|
||
|
||
Add the following script to `pfSense` via `System > Advanced > Cron`:
|
||
|
||
```sh
|
||
#!/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"
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ Example: `token.json`
|
||
|
||
```json
|
||
{
|
||
"domain1.to.com": "SECRET_TOKEN_8v73jDKsdLzAq9DkeUz1",
|
||
"domain2.to.com": "SECRET_TOKEN_3im83jUj28mjo2mI23un"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ Example: `meta.json`
|
||
|
||
```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
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔒 Security Highlights
|
||
|
||
- `.htaccess` denies access to all files except `update.php`.
|
||
- Only HTTPS connections should be used.
|
||
- All tokens are stored securely and verified per name.
|
||
- After 3 failed attempts, IP is banned for 48 hours.
|
||
- Generic error messages avoid leaking details to attackers.
|
||
|
||
---
|
||
|
||
## ✅ Requirements
|
||
|
||
- PHP 7.4 or newer
|
||
- NGINX with reload access (`sudo systemctl reload nginx`)
|
||
- `curl` on the client side
|
||
- Token definitions in `token.json`
|
||
|
||
---
|
||
|
||
## 📜 License
|
||
|
||
MIT (or similar): Open-source, free for use and modification.
|
||
|
||
---
|
||
|
||
## 🤝 Author
|
||
<p align="center">
|
||
<a href="https://safe-cap.com" target="_blank">
|
||
<img src="img/safe-cap-logo-small.png" width="100" height="100" alt="SAFE-CAP">
|
||
</a>
|
||
<br><br>
|
||
**Maintained by SAFE-CAP / Alexander Schiemann / https://safe-cap.com**
|
||
</p> |