A secure PHP-based Dynamic DNS server that interfaces with Virtualmin web panels through session-based authentication. This server provides encrypted credential storage, comprehensive logging, and both web and CLI interfaces for DNS record management.
- Encrypted Security: AES-256-CBC encryption with PBKDF2 key derivation for credential storage
- Session Authentication: Cookie-based Virtualmin login via
/session_login.cgi - Comprehensive Logging: Daily log files with automatic rotation and cleanup
- Multiple Interfaces: Web API, CLI, and direct PHP class integration
- HTTPS Enforcement: Required HTTPS for all non-localhost connections
- DNS Validation: Built-in DNS record verification using
gethostbyname()and dig - Record Management: Only modify existing records
The system has evolved into a complete DNS management solution with these components:
ddns.php- Main API logic with encryption, logging, and DNS operationssetup.php- Web-based setup interface with encrypted credential storagecli.php- Command-line interface for automated updatespublic_html/index.php- Web endpoint that routes to main DDNS logic
virtualmin.php- Virtualmin session management and DNS record operationsencrypt.php- AES-256-CBC encryption class for secure credential storagelog.php- Daily logging system with automatic cleanup.config- Five-line encrypted configuration (credentials, endpoint, log retention, nameserver)
- PHP 7.4+ with OpenSSL and cURL extensions
- Web Server (Apache/Nginx) with HTTPS support
- Virtualmin Panel with
/session_login.cgiand/save_record.cgiendpoints - File Permissions: Write access for
.config,.webminsesh, andlogs/directory - Virtualmin Web Panel User credentials
- Clone or download this repository to your web server
- Set proper permissions for PHP to create configuration and session files
- Configure web server to serve the
public_htmldirectory as document root - Ensure HTTPS is available (required for all non-localhost connections)
- Navigate to the setup page:
https://ddns.yourdomain.com/setup.php - Fill in the required fields:
- Username: Virtualmin master administrator username
- Password: Virtualmin master administrator password
- Virtualmin URL: Full URL to your Virtualmin panel (e.g.,
https://server.example.com:10000) - Log Age: Number of days to retain log files (default: 7)
- Nameserver: Optional DNS server for record verification
- Click "Setup" to encrypt credentials and generate API key
- Save the generated API key - required for all DDNS requests
The setup creates a .config file with encrypted data:
<encrypted_username_base64>
<encrypted_password_base64>
https://server.example.com:10000
7
8.8.8.8
Send HTTP GET requests to your DDNS endpoint with these parameters:
https://yourdomain.com/?api_key=YOUR_API_KEY&domain_id=DOMAIN_ID&type=RECORD_TYPE&name=RECORD_NAME&value=RECORD_VALUE
Required Parameters:
api_key- The API key generated during setup (also serves as decryption key)domain_id- Virtualmin's internal domain identifier (not the domain name)type- DNS record type (A, AAAA, CNAME, MX, etc.)name- Full record name including domain (e.g., "test.example.com")value- Record value (IP address, target, etc.)
Example:
curl "https://ddns.example.com/?api_key=abc123def456789&domain_id=123456789&type=A&name=home.example.com&value=192.168.1.100"Use cli.php for automated updates or scripts:
php cli.php <domain_id> <type> <name> <value> <username> <password> [endpoint] [nameserver]Example:
php cli.php 123456789 A home.example.com 192.168.1.100 admin secret123 https://server.example.com:10000 8.8.8.8For integration in PHP applications, use the Virtualmin class:
<?php
require_once 'virtualmin.php';
// Initialize with Virtualmin endpoint and credentials
$virtualmin = new Virtualmin(
'https://your-virtualmin-server:10000',
'admin_username',
'admin_password'
);
// Modify an existing DNS record
$result = $virtualmin->updateRecord(1234567890, 'test.example.com', 'A', '192.168.1.200');
// Check results
if ($result['status_code'] == 200) {
echo "Result: " . $result['response'] . "\n";
} else {
echo "Result: " . $result['response'] . "\n";
echo "Error: " . $result['error'] . "\n";
echo "Status Code: " . $result['status_code'] . "\n";
}
?>For secure credential storage:
<?php
require_once 'encrypt.php';
$encryption = new Encryption();
$api_key = bin2hex(random_bytes(16));
// Encrypt credentials
$encrypted_username = $encryption->encrypt('admin', $api_key);
$encrypted_password = $encryption->encrypt('password123', $api_key);
// Decrypt when needed
$username = $encryption->decrypt($encrypted_username, $api_key);
$password = $encryption->decrypt($encrypted_password, $api_key);
?>- Location:
logs/YYYY-MM-DD.log - Content: Client IP, timestamp, request URI, operations, and errors
- Rotation: Automatic cleanup based on
logagesetting - CLI Logging: Command-line operations logged with 'CLI' identifier
$logger = new DDNSLog($client_ip, $log_retention_days);
$logger->write("DNS update successful for test.example.com");- AES-256-CBC Encryption: Credentials encrypted with PBKDF2 (1000 iterations, SHA256)
- Session-Based Auth: Uses Virtualmin's
/session_login.cgifor secure API access - HTTPS Enforcement: Required for all non-localhost connections
- API Key as Password: Dual purpose authentication token and encryption key
- DNS Validation: Record verification using
gethostbyname()and optional dig - Session Cleanup: Temporary
.webminseshcookie files automatically removed
JSON responses with detailed error information:
- 200 OK - Successful DNS operation with response details
- 400 Bad Request - Missing domain_id, type, name, or value parameters
- 401 Unauthorized - Invalid or missing API key
- 500 Internal Server Error - Virtualmin communication or DNS operation failures
-
401 Unauthorized
- Verify API key matches generated key from setup
- Ensure API key is exactly 32 hexadecimal characters
- Check that all required parameters are provided
-
400 Bad Request
- Verify
domain_idis Virtualmin's numeric domain identifier - Check record
nameincludes full domain (e.g., "test.example.com") - Ensure
typeandvalueparameters are valid for DNS record type
- Verify
-
Session Authentication Failures
- Verify Virtualmin URL includes correct port (usually :10000)
- Check
/session_login.cgiendpoint is accessible - Ensure virtualmin user credentials are correct
- Verify encrypted credentials can be decrypted with API key
-
DNS Operation Failures
- Check that domain exists in Virtualmin and user has DNS permissions
- Verify record format matches Virtualmin expectations
- Review
logs/YYYY-MM-DD.logfor detailed error messages - Test DNS resolution with
gethostbyname()or dig if configured
All responses include comprehensive debugging data:
- HTTP status codes and Virtualmin responses
- Complete request URLs and parameters
- Encryption/decryption operations
- Session management details
- DNS verification results
For security purposes this server uses session-based authentication instead of Remote API (which requires the Master Administrator credentials):
- Login Endpoint:
/session_login.cgiwith POST username/password - DNS Endpoint:
/save_record.cgiwith session cookie authentication - Session Management: Temporary
.webminseshcookie files (auto-cleaned) - Success Detection: HTTP 302 redirect indicates successful DNS update
Adding Records (via updateRecord method):
$domain_id = "123456789"; // Virtualmin's internal domain ID
$type = "A";
$name = "test.example.com";
$value = "192.168.1.100";Record Format for Virtualmin:
dom=123456789&id=test.%2FA%2F&name=test&value=192.168.1.100&ttl_def=1
- Algorithm: AES-256-CBC with PBKDF2 key derivation
- Key Derivation: 1000 iterations, SHA256 digest
- Salt: 16-byte random salt per encryption
- IV: Random initialization vector per encryption
- Output: Base64-encoded (salt + IV + encrypted_data)
/ddns/
├── .config # 5-line encrypted config
├── .webminsesh # Temporary session cookie (auto-cleaned)
├── ddns.php # Core API logic
├── cli.php # Command-line interface
├── setup.php # Web setup interface
├── virtualmin.php # Session management class
├── encrypt.php # AES-256-CBC encryption
├── log.php # Daily logging system
├── logs/ # Daily log files (YYYY-MM-DD.log)
└── public_html/ # Web document root
└── index.php # Main web endpoint
This project is provided as-is for educational and practical use. Modify as needed for your environment.