mirror of
https://gitlab.com/ArkHost/WHMCS-ArkHost-HetznerVPS.git
synced 2026-07-24 15:55:53 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb4e94b086 | ||
|
|
3bfc327763 | ||
|
|
8b7d6b2c62 | ||
|
|
3c526260cd | ||
|
|
8d4673378c | ||
|
|
5421cd0b30 | ||
|
|
8887733e0e |
@@ -86,36 +86,70 @@ Create in Setup → Products/Services → Configurable Options:
|
|||||||
- Option Name: `datacenter`
|
- Option Name: `datacenter`
|
||||||
- Option Type: `Dropdown`
|
- Option Type: `Dropdown`
|
||||||
- Options:
|
- Options:
|
||||||
- `fsn1|Falkenstein, Germany`
|
- `fsn1-dc14|Falkenstein, Germany`
|
||||||
- `nbg1|Nuremberg, Germany`
|
- `nbg1-dc3|Nuremberg, Germany`
|
||||||
- `hel1|Helsinki, Finland`
|
- `hel1-dc2|Helsinki, Finland`
|
||||||
- `ash|Ashburn, USA`
|
- `ash-dc1|Ashburn, USA`
|
||||||
- `hil|Hillsboro, USA`
|
- `hil-dc1|Hillsboro, USA`
|
||||||
|
- `sin-dc1|Singapore, Singapore`
|
||||||
|
|
||||||
**3\. Server Type**
|
**3\. Server Type**
|
||||||
|
|
||||||
- Option Name: `planid`
|
- Option Name: `planid`
|
||||||
- Option Type: `Dropdown`
|
- Option Type: `Dropdown`
|
||||||
- Options:
|
- Options:
|
||||||
- `cx11|CX11 (1 vCPU, 2GB RAM, 20GB SSD)`
|
- `cpx11|CPX 11 - 2 vCPU, 2 GB RAM, 40 GB Disk, shared`
|
||||||
- `cx21|CX21 (2 vCPU, 4GB RAM, 40GB SSD)`
|
- `cpx21|CPX 21 - 3 vCPU, 4 GB RAM, 80 GB Disk, shared`
|
||||||
- `cx31|CX31 (2 vCPU, 8GB RAM, 80GB SSD)`
|
- `cpx31|CPX 31 - 4 vCPU, 8 GB RAM, 160 GB Disk, shared`
|
||||||
- `cx41|CX41 (4 vCPU, 16GB RAM, 160GB SSD)`
|
- `cpx41|CPX 41 - 8 vCPU, 16 GB RAM, 240 GB Disk, shared`
|
||||||
- `cx51|CX51 (8 vCPU, 32GB RAM, 240GB SSD)`
|
- `cpx51|CPX 51 - 16 vCPU, 32 GB RAM, 360 GB Disk, shared`
|
||||||
|
- `cax11|CAX11 - 2 vCPU, 4 GB RAM, 40 GB Disk, shared`
|
||||||
|
- `cax21|CAX21 - 4 vCPU, 8 GB RAM, 80 GB Disk, shared`
|
||||||
|
- `cax31|CAX31 - 8 vCPU, 16 GB RAM, 160 GB Disk, shared`
|
||||||
|
- `cax41|CAX41 - 16 vCPU, 32 GB RAM, 320 GB Disk, shared`
|
||||||
|
- `ccx13|CCX13 Dedicated CPU - 2 vCPU, 8 GB RAM, 80 GB Disk, dedicated`
|
||||||
|
- `ccx23|CCX23 Dedicated CPU - 4 vCPU, 16 GB RAM, 160 GB Disk, dedicated`
|
||||||
|
- `ccx33|CCX33 Dedicated CPU - 8 vCPU, 32 GB RAM, 240 GB Disk, dedicated`
|
||||||
|
- `ccx43|CCX43 Dedicated CPU - 16 vCPU, 64 GB RAM, 360 GB Disk, dedicated`
|
||||||
|
- `ccx53|CCX53 Dedicated CPU - 32 vCPU, 128 GB RAM, 600 GB Disk, dedicated`
|
||||||
|
- `ccx63|CCX63 Dedicated CPU - 48 vCPU, 192 GB RAM, 960 GB Disk, dedicated`
|
||||||
|
- `cx22|CX22 - 2 vCPU, 4 GB RAM, 40 GB Disk, shared`
|
||||||
|
- `cx32|CX32 - 4 vCPU, 8 GB RAM, 80 GB Disk, shared`
|
||||||
|
- `cx42|CX42 - 8 vCPU, 16 GB RAM, 160 GB Disk, shared`
|
||||||
|
- `cx52|CX52 - 16 vCPU, 32 GB RAM, 320 GB Disk, shared`
|
||||||
|
|
||||||
|
|
||||||
**4\. Operating System**
|
**4\. Operating System**
|
||||||
|
|
||||||
- Option Name: `osid`
|
- Option Name: `osid`
|
||||||
- Option Type: `Dropdown`
|
- Option Type: `Dropdown`
|
||||||
- Options:
|
- Options:
|
||||||
- `ubuntu-20.04|Ubuntu 20.04 LTS`
|
- `lamp|lamp`
|
||||||
- `ubuntu-22.04|Ubuntu 22.04 LTS`
|
-`wordpress|wordpress`
|
||||||
|
-`jitsi|jitsi`
|
||||||
|
-`nextcloud|nextcloud`
|
||||||
|
- `docker-ce|docker-ce`
|
||||||
|
- `gitlab|gitlab`
|
||||||
- `debian-11|Debian 11`
|
- `debian-11|Debian 11`
|
||||||
- `debian-12|Debian 12`
|
- `rocky-8|Rocky Linux 8`
|
||||||
- `centos-stream-8|CentOS Stream 8`
|
|
||||||
- `centos-stream-9|CentOS Stream 9`
|
- `centos-stream-9|CentOS Stream 9`
|
||||||
|
- `ubuntu-22.04|Ubuntu 22.04`
|
||||||
|
- `prometheus-grafana|prometheus-grafana`
|
||||||
|
- `rocky-9|Rocky Linux 9`
|
||||||
|
- `wireguard|wireguard`
|
||||||
|
- `owncast|owncast`
|
||||||
|
- `photoprism|photoprism`
|
||||||
|
- `rustdesk|rustdesk`
|
||||||
|
- `centos-stream-9|CentOS Stream 9`
|
||||||
|
- `debian-11|Debian 11`
|
||||||
- `rocky-8|Rocky Linux 8`
|
- `rocky-8|Rocky Linux 8`
|
||||||
- `rocky-9|Rocky Linux 9`
|
- `rocky-9|Rocky Linux 9`
|
||||||
|
- `ubuntu-22.04|Ubuntu 22.04`
|
||||||
|
- `alma-8|AlmaLinux 8`
|
||||||
|
- `alma-9|AlmaLinux 9`
|
||||||
|
- `jitsi|jitsi`
|
||||||
|
- `owncast|owncast`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -167,9 +201,27 @@ We're exploring secure implementations using cloud-init or per-server user data
|
|||||||
|
|
||||||
Enable module debugging: Configuration → System Logs → Module Log
|
Enable module debugging: Configuration → System Logs → Module Log
|
||||||
|
|
||||||
## Support
|
## Support Policy
|
||||||
|
|
||||||
[support@arkhost.com](mailto:support@arkhost.com "mailto:support@arkhost.com")
|
This is free, open-source software provided AS-IS.
|
||||||
|
|
||||||
|
**NO SUPPORT** is provided except through paid channels:
|
||||||
|
- Premium Support: €100/hour (2 hour minimum)
|
||||||
|
- Email: support@arkhost.com (paid support only)
|
||||||
|
|
||||||
|
### Before Requesting Support
|
||||||
|
- English only
|
||||||
|
- Must provide complete error logs
|
||||||
|
- Must provide steps to reproduce
|
||||||
|
- Vague reports like "doesn't work" will be ignored
|
||||||
|
|
||||||
|
### GitHub Issues
|
||||||
|
- For documented bugs only
|
||||||
|
- Requires complete technical information
|
||||||
|
- Issues lacking proper information will be closed immediately
|
||||||
|
- This is not a support forum
|
||||||
|
|
||||||
|
If you need help with basic installation or configuration, purchase premium support.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* WHMCS Server Module - Hetzner VPS
|
* WHMCS Server Module - Hetzner VPS
|
||||||
*
|
*
|
||||||
* @package WHMCS
|
* @package WHMCS
|
||||||
* @version 1.0
|
* @version 1.1
|
||||||
* @copyright Copyright (c) ArkHost 2025
|
* @copyright Copyright (c) ArkHost 2025
|
||||||
* @author ArkHost <support@arkhost.com>
|
* @author ArkHost <support@arkhost.com>
|
||||||
* @link https://arkhost.com
|
* @link https://arkhost.com
|
||||||
@@ -387,11 +387,14 @@ function ArkHostHetznerVPS_API(array $params) {
|
|||||||
case 'Apply Firewall':
|
case 'Apply Firewall':
|
||||||
$url .= 'firewalls/' . $params['firewall_id'] . '/actions/apply_to_resources';
|
$url .= 'firewalls/' . $params['firewall_id'] . '/actions/apply_to_resources';
|
||||||
$method = 'POST';
|
$method = 'POST';
|
||||||
|
$serverId = ArkHostHetznerVPS_GetVPSID($params);
|
||||||
$data = array(
|
$data = array(
|
||||||
'apply_to' => array(
|
'apply_to' => array(
|
||||||
array(
|
array(
|
||||||
'type' => 'server',
|
'type' => 'server',
|
||||||
'server' => ArkHostHetznerVPS_GetVPSID($params)
|
'server' => array(
|
||||||
|
'id' => intval($serverId)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -446,17 +449,47 @@ function ArkHostHetznerVPS_API(array $params) {
|
|||||||
// No firewall attached, create one
|
// No firewall attached, create one
|
||||||
$createParams = $params;
|
$createParams = $params;
|
||||||
$createParams['action'] = 'Create Firewall';
|
$createParams['action'] = 'Create Firewall';
|
||||||
$createParams['name'] = 'firewall-server-' . $serverId;
|
// Simple unique name
|
||||||
|
$createParams['name'] = 'server-' . $serverId . '-' . time();
|
||||||
$createParams['rules'] = array();
|
$createParams['rules'] = array();
|
||||||
|
|
||||||
|
try {
|
||||||
$createResult = ArkHostHetznerVPS_API($createParams);
|
$createResult = ArkHostHetznerVPS_API($createParams);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// If name is still not unique, try with random suffix
|
||||||
|
if (strpos($e->getMessage(), 'uniqueness_error') !== false || strpos($e->getMessage(), 'name is already used') !== false) {
|
||||||
|
$createParams['name'] = 'firewall-server-' . $serverId . '-' . time() . '-' . rand(1000, 9999);
|
||||||
|
$createResult = ArkHostHetznerVPS_API($createParams);
|
||||||
|
} else {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
$firewallId = $createResult['firewall']['id'];
|
$firewallId = $createResult['firewall']['id'];
|
||||||
|
|
||||||
// Attach firewall to server
|
// Attach firewall to server
|
||||||
$attachParams = $params;
|
$attachParams = $params;
|
||||||
$attachParams['action'] = 'Apply Firewall';
|
$attachParams['action'] = 'Apply Firewall';
|
||||||
$attachParams['firewall_id'] = $firewallId;
|
$attachParams['firewall_id'] = $firewallId;
|
||||||
|
$attachResult = ArkHostHetznerVPS_API($attachParams);
|
||||||
|
|
||||||
|
// Wait a moment for the firewall to be applied
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
// Verify the firewall was attached
|
||||||
|
$verifyParams = $params;
|
||||||
|
$verifyParams['action'] = 'Server Info';
|
||||||
|
$verifyInfo = ArkHostHetznerVPS_API($verifyParams);
|
||||||
|
|
||||||
|
// Check if firewall is actually attached
|
||||||
|
if (!isset($verifyInfo['server']['public_net']['firewalls']) ||
|
||||||
|
empty($verifyInfo['server']['public_net']['firewalls']) ||
|
||||||
|
$verifyInfo['server']['public_net']['firewalls'][0]['id'] != $firewallId) {
|
||||||
|
// Try to attach again if it failed
|
||||||
|
$attachParams = $params;
|
||||||
|
$attachParams['action'] = 'Apply Firewall';
|
||||||
|
$attachParams['firewall_id'] = $firewallId;
|
||||||
ArkHostHetznerVPS_API($attachParams);
|
ArkHostHetznerVPS_API($attachParams);
|
||||||
|
}
|
||||||
|
|
||||||
$existingRules = array();
|
$existingRules = array();
|
||||||
}
|
}
|
||||||
@@ -468,8 +501,8 @@ function ArkHostHetznerVPS_API(array $params) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Handle source IPs - ensure CIDR notation
|
// Handle source IPs - ensure CIDR notation
|
||||||
if (!empty($params['source']) && $params['source'] !== '0.0.0.0/0') {
|
if (!empty($params['source']) && $params['source'] !== '0.0.0.0/0' && $params['source'] !== 'Any') {
|
||||||
$sourceIp = $params['source'];
|
$sourceIp = trim($params['source']);
|
||||||
// If no CIDR notation, add /32 for IPv4 or /128 for IPv6
|
// If no CIDR notation, add /32 for IPv4 or /128 for IPv6
|
||||||
if (strpos($sourceIp, '/') === false) {
|
if (strpos($sourceIp, '/') === false) {
|
||||||
if (filter_var($sourceIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
if (filter_var($sourceIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||||
@@ -480,12 +513,13 @@ function ArkHostHetznerVPS_API(array $params) {
|
|||||||
}
|
}
|
||||||
$newRule['source_ips'] = array($sourceIp);
|
$newRule['source_ips'] = array($sourceIp);
|
||||||
} else {
|
} else {
|
||||||
|
// Empty array means all sources are allowed in Hetzner API
|
||||||
$newRule['source_ips'] = array();
|
$newRule['source_ips'] = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle port
|
// Handle port - Hetzner expects port as a string
|
||||||
if (!empty($params['port']) && $params['protocol'] !== 'icmp') {
|
if (!empty($params['port']) && $params['protocol'] !== 'icmp') {
|
||||||
$newRule['port'] = $params['port'];
|
$newRule['port'] = strval($params['port']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add description if provided
|
// Add description if provided
|
||||||
@@ -493,10 +527,10 @@ function ArkHostHetznerVPS_API(array $params) {
|
|||||||
$newRule['description'] = $params['note'];
|
$newRule['description'] = $params['note'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only add ACCEPT rules (Hetzner default is DROP for non-matched)
|
// Add the new rule to existing rules
|
||||||
if ($params['firewallAction'] === 'ACCEPT') {
|
// Note: Hetzner only supports ACCEPT rules for inbound traffic
|
||||||
|
// The default policy is DROP for non-matched traffic
|
||||||
$existingRules[] = $newRule;
|
$existingRules[] = $newRule;
|
||||||
}
|
|
||||||
|
|
||||||
// Update firewall with new rules
|
// Update firewall with new rules
|
||||||
$updateParams = $params;
|
$updateParams = $params;
|
||||||
@@ -1767,52 +1801,13 @@ function ArkHostHetznerVPS_ClientAreaAPI(array $params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (empty($rules)) {
|
if (empty($rules)) {
|
||||||
$results['message'] = 'This server has ' . count($result['server']['firewall_ids']) . ' firewall(s) attached but no inbound rules configured.';
|
$results['message'] = 'This server has ' . count($firewallIds) . ' firewall(s) attached but no inbound rules configured.';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No firewalls attached - show default rules indicating all traffic is allowed
|
// No firewalls attached - don't show any rules
|
||||||
$rules[] = array(
|
$results['message'] = 'No firewall attached to this server. All traffic is allowed by default. Create a firewall rule to enable protection.';
|
||||||
'id' => '1',
|
// Return empty rules array
|
||||||
'action' => 'ACCEPT',
|
$rules = array();
|
||||||
'protocol' => 'TCP',
|
|
||||||
'port' => '22',
|
|
||||||
'source' => '0.0.0.0/0',
|
|
||||||
'note' => 'SSH (Default Open)'
|
|
||||||
);
|
|
||||||
$rules[] = array(
|
|
||||||
'id' => '2',
|
|
||||||
'action' => 'ACCEPT',
|
|
||||||
'protocol' => 'TCP',
|
|
||||||
'port' => '80',
|
|
||||||
'source' => '0.0.0.0/0',
|
|
||||||
'note' => 'HTTP (Default Open)'
|
|
||||||
);
|
|
||||||
$rules[] = array(
|
|
||||||
'id' => '3',
|
|
||||||
'action' => 'ACCEPT',
|
|
||||||
'protocol' => 'TCP',
|
|
||||||
'port' => '443',
|
|
||||||
'source' => '0.0.0.0/0',
|
|
||||||
'note' => 'HTTPS (Default Open)'
|
|
||||||
);
|
|
||||||
$rules[] = array(
|
|
||||||
'id' => '4',
|
|
||||||
'action' => 'ACCEPT',
|
|
||||||
'protocol' => 'TCP/UDP',
|
|
||||||
'port' => 'All',
|
|
||||||
'source' => '0.0.0.0/0',
|
|
||||||
'note' => 'All other ports (Default Open)'
|
|
||||||
);
|
|
||||||
$rules[] = array(
|
|
||||||
'id' => '5',
|
|
||||||
'action' => 'ACCEPT',
|
|
||||||
'protocol' => 'ICMP',
|
|
||||||
'port' => 'N/A',
|
|
||||||
'source' => '0.0.0.0/0',
|
|
||||||
'note' => 'Ping/ICMP (Default Open)'
|
|
||||||
);
|
|
||||||
|
|
||||||
$results['message'] = 'No firewall attached. All traffic is allowed by default.';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return rules with numeric keys for JavaScript compatibility
|
// Return rules with numeric keys for JavaScript compatibility
|
||||||
|
|||||||
Reference in New Issue
Block a user