A lightweight Docker container that automatically monitors your external IP address and updates Pangolin rules when changes are detected. Perfect for home servers, VPS instances, or any infrastructure that needs to maintain dynamic IP-based firewall rules.
- Automatic IP Monitoring: Checks your external IP address every minute (configurable)
- Smart Updates: Only updates firewall rules when IP actually changes
- Environment-Based Configuration: All settings managed through
.envfile - Docker Compose Ready: Easy deployment with single command
- Robust Error Handling: Continues running even if API calls fail temporarily
- Detailed Logging: Track all IP changes and rule updates
- Docker and Docker Compose installed
- Enable the Integration API: https://docs.digpangolin.com/manage/integration-api
- Valid Pangolin API access token
- Permission required: Resource Rule -> List Resource Rules
- Permission required: Resource Rule -> Update Resource Rule
- Pangolin rule ID that you want to update
- Visit the Swagger API at https://api.url.com/v1/docs Authorize using your Pangolin API token Enter your Resource ID (from the URL in Pangolin) into the Rules /resource/{resourceId}/rules API and click "Execute". This will list out all the Rules and the Rule ID associated with the Pangolin Resource
-
Clone the repository
git clone https://github.com/olizimmermann/pangolin_rule_updater.git cd pangolin_rule_updater -
Create your environment file
cp .env.example .env
-
Configure your settings (see Configuration section below)
-
Build and start the container
docker compose up -d
Create a .env file in the project root with the following variables:
# Pangolin credentials
API_KEY=YOUR_LONG_BEARER_TOKEN
RESOURCE_ID=1 # replace with your resource id
RULE_ID=1 # replace with your rule
RULE_PRIORITY=1 # replace with yours
RULE_ACTION=ACCEPT
RULE_MATCH=IP # IP, CIDR, PATH
RULE_ENABLED=True
TARGET_DOMAIN=my.dyn.dns.com # your dynamic DNS hostname or leave empty to check for current IP of the host
PANGOLIN_HOST=https://api.pangolin.example
# Runtime controls (optional)
IP_SERVICE_URL=https://wtfismyip.com/text # any plain-text IP service
LOOP_SECONDS=60 # check interval in seconds
# Enable this to expose a website to trigger an update, make sure that only trusted clients can access it/know it
EXPOSE_TRIGGER_WEBSITE=False
TRIGGER_WEBSITE_DOMAIN=trigger.my.dyn.dns.com
TRIGGER_WEBSITE_PATH=/update
TRIGGER_WEBSITE_PORT=8080 # check interval in seconds| Parameter | Required | Default | Description |
|---|---|---|---|
API_KEY |
✅ | - | Your Pangolin API Bearer token |
RESOURCE_ID |
✅ | - | The resource ID in Pangolin API |
RULE_ID |
✅ | - | The specific rule ID to update |
PANGOLIN_HOST |
✅ | https://api.pangolin.example |
Pangolin API base URL |
RULE_PRIORITY |
❌ | 100 | The specific rule priority |
RULE_ACTION |
❌ | ACCEPT | The specific rule action [ACCEPT, DROP] |
RULE_MATCH |
❌ | IP | The specific rule match [IP, CIDR, PATH] |
RULE_ENABLED |
❌ | True | Enable or disable the rule |
IP_SERVICE_URL |
❌ | https://api.ipify.org |
External IP detection service |
LOOP_SECONDS |
❌ | 60 |
Check interval in seconds |
TARGET_DOMAIN |
❌ | my.dyn.dns.com |
Your dynamic DNS hostname (disables the default self-ip-check) |
EXPOSE_TRIGGER_WEBSITE |
❌ | False | Enable trigger website for manual updates (disables automatic updates) |
TRIGGER_WEBSITE_DOMAIN |
❌ | trigger.my.dyn.dns.com |
Domain for the trigger website |
TRIGGER_WEBSITE_PATH |
❌ | /update |
Path for the trigger website |
TRIGGER_WEBSITE_PORT |
❌ | 8080 | Port for the trigger website |
docker compose up -ddocker compose logs -fdocker compose downdocker compose build --no-cache
docker compose up -dJust set the TARGET_DOMAIN variable in your .env file to your dynamic DNS hostname. This will replace the default self-IP check.
The trigger webservice allows you to manually trigger an IP update by sending a request to the specified endpoint, or just by visiting the URL in your browser. Set the following in your docker-compose.yml:
services:
ip-updater:
build: .
env_file: .env
restart: unless-stopped
ports:
- "${TRIGGER_WEBSITE_PORT}:${TRIGGER_WEBSITE_PORT}"In your .env file, set the following variables:
EXPOSE_TRIGGER_WEBSITE=True
TRIGGER_WEBSITE_DOMAIN=trigger.my.dyn.dns.com
TRIGGER_WEBSITE_PATH=/update
TRIGGER_WEBSITE_PORT=8080Warning: Exposing the trigger website can pose security risks. Ensure that only trusted clients can access it.
Choose a slightly cryptic subdomain name for your trigger website to make it less predictable. As a best practice, avoid using easily guessable names. Same goes for the path and port.
If you have enabled the trigger webservice, the self-IP check and the dynamic DNS update will be disabled, and you will need to manually trigger updates via the webservice.
services:
pangolin-rule-updater:
container_name: pangolin-rule-updater
build:
context: https://github.com/olizimmermann/pangolin_rule_updater.git#main
dockerfile: Dockerfile
restart: unless-stopped
environment:
# --- Required ---
API_KEY: YOUR_API_TOKEN # Pangolin API Token
RESOURCE_ID: "1" # ID of your Pangolin Resource
RULE_ID: "1" # ID of your Rule
# --- Optional ---
RULE_PRIORITY: "1"
RULE_ACTION: "ACCEPT" # ACCEPT oder DROP
RULE_MATCH: "IP" # IP, CIDR oder PATH
RULE_ENABLED: "True"
PANGOLIN_HOST: "https://api.example.com"
IP_SERVICE_URL: "https://api.ipify.org" # External IP
LOOP_SECONDS: "60" # Check interval in secondspangolin-ip-updater/
├── Dockerfile # Container definition
├── docker-compose.yml # Service orchestration
├── update_ip.py # Main application logic
├── requirements.txt # Python dependencies
├── .env.example # Template for environment variables
├── .env # Your actual configuration (create this)
├── .gitignore # Git ignore rules
└── README.md # This file
The application interacts with Pangolin API using these endpoints:
curl -X 'GET' \
'https://api.pangolin.example/v1/resource/{RESOURCE_ID}/rules' \
-H 'Authorization: Bearer {API_KEY}'curl -X 'POST' \
'https://api.pangolin.example/v1/resource/{RESOURCE_ID}/rule/{RULE_ID}' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer {API_KEY}' \
-d '{
"action": "ACCEPT",
"match": "IP",
"value": "NEW.IP.ADDRESS.HERE",
"priority": 2,
"enabled": true
}'Container exits immediately
- Check your
.envfile exists and has all required variables - Verify your API key is valid
- Check logs:
docker compose logs
API authentication errors
- Ensure your
API_KEYis correct and active - Verify the Bearer token format
Rule not updating
- Confirm
RESOURCE_IDandRULE_IDare correct - Test API access manually with curl commands above
- Check if your IP actually changed
Network connectivity issues
- Verify container has internet access
- Try different IP detection service in
IP_SERVICE_URL
To run with more verbose logging:
docker compose logs -f ip-updater- Never commit your
.envfile - it contains sensitive API credentials - Store your
.envfile securely and restrict file permissions - Consider using Docker secrets for production deployments
- Regularly rotate your API keys
To update multiple rules, deploy separate containers with different .env files:
# Rule 1
docker compose -f docker-compose.rule1.yml up -d
# Rule 2
docker compose -f docker-compose.rule2.yml up -dAdjust the LOOP_SECONDS variable for different check frequencies:
30- Every 30 seconds (aggressive)300- Every 5 minutes (conservative)3600- Every hour (minimal)
To monitor IPv6 addresses, update your .env:
IP_SERVICE_URL=https://api6.ipify.org- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Pangolin for providing this great project
- ipify for reliable IP detection service
- Docker community for containerization best practices
If you encounter any issues or have questions:
- Check the Troubleshooting section
- Review existing Issues
- Create a new issue with detailed information about your problem
⭐ If this project helped you, please consider giving it a star!