WWW-Hetzner
Perl client for Hetzner APIs (Cloud and Robot).
Installation
cpanm WWW::Hetzner
Cloud API
use WWW::Hetzner::Cloud;
my $cloud = WWW::Hetzner::Cloud->new(
token => $ENV{HETZNER_API_TOKEN},
);
# Servers
my $servers = $cloud->servers->list;
my $server = $cloud->servers->create(
name => 'my-server',
server_type => 'cx22',
image => 'debian-12',
location => 'fsn1',
ssh_keys => ['my-key'],
);
$server->power_off;
$server->power_on;
$server->reboot;
$server->delete;
# Volumes
my $volume = $cloud->volumes->create(
name => 'data',
size => 50,
location => 'fsn1',
);
$cloud->volumes->attach($volume->id, server => $server->id);
$cloud->volumes->resize($volume->id, size => 100);
# Networks
my $network = $cloud->networks->create(
name => 'my-network',
ip_range => '10.0.0.0/8',
);
$cloud->networks->add_subnet($network->id,
ip_range => '10.0.1.0/24',
type => 'cloud',
network_zone => 'eu-central',
);
# Firewalls
my $firewall = $cloud->firewalls->create(name => 'web-fw');
$cloud->firewalls->set_rules($firewall->id, [
{ direction => 'in', protocol => 'tcp', port => '80', source_ips => ['0.0.0.0/0'] },
{ direction => 'in', protocol => 'tcp', port => '443', source_ips => ['0.0.0.0/0'] },
]);
# Floating IPs
my $ip = $cloud->floating_ips->create(type => 'ipv4', home_location => 'fsn1');
$cloud->floating_ips->assign($ip->id, server => $server->id);
# Load Balancers
my $lb = $cloud->load_balancers->create(
name => 'my-lb',
load_balancer_type => 'lb11',
location => 'fsn1',
);
# DNS Zones
my $zone = $cloud->zones->create(name => 'example.com');
$zone->rrsets->add_a('www', '203.0.113.10');
$zone->rrsets->add_cname('blog', 'www.example.com.');
$zone->rrsets->add_mx('@', 'mail.example.com.', 10);
# SSH Keys
my $key = $cloud->ssh_keys->create(
name => 'my-key',
public_key => 'ssh-ed25519 AAAA...',
);
Robot API (Dedicated Servers)
use WWW::Hetzner::Robot;
my $robot = WWW::Hetzner::Robot->new(
user => $ENV{HETZNER_ROBOT_USER},
password => $ENV{HETZNER_ROBOT_PASSWORD},
);
# Dedicated servers
my $servers = $robot->servers->list;
my $server = $robot->servers->get(123456);
print $server->server_name, " - ", $server->product, "\n";
# SSH Keys
my $keys = $robot->keys->list;
$robot->keys->create(name => 'my-key', data => 'ssh-ed25519 AAAA...');
# IPs
my $ips = $robot->ips->list;
# Server reset
$robot->reset->software(123456); # CTRL+ALT+DEL
$robot->reset->hardware(123456); # Power cycle
$robot->reset->wol(123456); # Wake-on-LAN
# Traffic statistics
my $traffic = $robot->traffic->query(
ip => '1.2.3.4',
from => '2024-01-01',
to => '2024-01-31',
);
CLI Tools
hcloud.pl (Cloud)
export HETZNER_API_TOKEN=your-token
# Servers
hcloud.pl server list
hcloud.pl server create --name test --type cx22 --image debian-12
hcloud.pl server describe 12345
hcloud.pl server poweron 12345
hcloud.pl server poweroff 12345
hcloud.pl server delete 12345
# Volumes
hcloud.pl volume list
hcloud.pl volume create --name data --size 50 --location fsn1
hcloud.pl volume attach 12345 --server 67890
hcloud.pl volume resize 12345 --size 100
# Networks
hcloud.pl network list
hcloud.pl network create --name mynet --ip-range 10.0.0.0/8
hcloud.pl network add-subnet 12345 --ip-range 10.0.1.0/24 --type cloud --network-zone eu-central
# Firewalls
hcloud.pl firewall list
hcloud.pl firewall create --name web-fw
hcloud.pl firewall add-rule 12345 --direction in --protocol tcp --port 80
# Floating IPs
hcloud.pl floating-ip list
hcloud.pl floating-ip create --type ipv4 --home-location fsn1
hcloud.pl floating-ip assign 12345 --server 67890
# Primary IPs
hcloud.pl primary-ip list
# Load Balancers
hcloud.pl load-balancer list
hcloud.pl load-balancer create --name lb --type lb11 --location fsn1
# Placement Groups
hcloud.pl placement-group list
hcloud.pl placement-group create --name spread --type spread
# Certificates
hcloud.pl certificate list
# DNS
hcloud.pl zone list
hcloud.pl record list --zone example.com
# Info
hcloud.pl servertype list
hcloud.pl image list
hcloud.pl location list
hcloud.pl datacenter list
hcloud.pl sshkey list
# JSON output
hcloud.pl -o json server list
hrobot.pl (Robot)
export HETZNER_ROBOT_USER=your-user
export HETZNER_ROBOT_PASSWORD=your-password
hrobot.pl server list
hrobot.pl server describe 123456
hrobot.pl key list
hrobot.pl reset 123456 --type sw
hrobot.pl wol 123456
hrobot.pl traffic query --ip 1.2.3.4 --from 2024-01-01
Cloud API Resources
| Resource | API Methods | |----------|-------------| | Servers | list, get, create, delete, power_on, power_off, shutdown, reboot, reset, rebuild, rescue | | Volumes | list, get, create, delete, attach, detach, resize | | Networks | list, get, create, update, delete, add_subnet, delete_subnet, add_route, delete_route | | Firewalls | list, get, create, update, delete, set_rules, apply_to_resources, remove_from_resources | | Floating IPs | list, get, create, delete, assign, unassign | | Primary IPs | list, get, create, delete, assign, unassign | | Load Balancers | list, get, create, delete, add_target, add_service | | Certificates | list, get, create, delete | | Placement Groups | list, get, create, update, delete | | SSH Keys | list, get, get_by_name, create, update, delete, ensure | | DNS Zones | list, get, create, update, delete, export | | DNS Records | add_a, add_aaaa, add_cname, add_mx, add_txt | | Server Types | list, get, get_by_name | | Images | list, get, get_by_name | | Locations | list, get, get_by_name | | Datacenters | list, get, get_by_name |
Async Support
For non-blocking IO::Async integration, see Net::Async::Hetzner:
use IO::Async::Loop;
use Net::Async::Hetzner::Cloud;
my $loop = IO::Async::Loop->new;
my $cloud = Net::Async::Hetzner::Cloud->new(token => $ENV{HETZNER_API_TOKEN});
$loop->add($cloud);
my $data = $cloud->get('/servers')->get; # Future-based
Custom HTTP Backend
HTTP transport is pluggable via WWW::Hetzner::Role::IO. The default backend
is WWW::Hetzner::LWPIO (synchronous, LWP::UserAgent). You can swap it for
custom backends:
my $cloud = WWW::Hetzner::Cloud->new(
token => $ENV{HETZNER_API_TOKEN},
io => My::CustomIO->new,
);
A custom backend implements WWW::Hetzner::Role::IO and its call method:
package My::CustomIO;
use Moo;
with 'WWW::Hetzner::Role::IO';
sub call {
my ($self, $req) = @_;
# $req->method, $req->url, $req->headers, $req->content
# ... execute HTTP request ...
return WWW::Hetzner::HTTPResponse->new(status => $status, content => $body);
}
Logging
Uses Log::Any for flexible logging integration.
# Enable logging to STDERR
use Log::Any::Adapter ('Stderr', log_level => 'debug');
# Or to a file
use Log::Any::Adapter ('File', '/var/log/hetzner.log');
# Or integrate with Log::Log4perl
use Log::Any::Adapter ('Log4perl');
Log levels: debug (requests/responses), info (successful calls), error (API errors).
HTTP Debugging
For full HTTP request/response dumps (headers, bodies, status), use LWP::ConsoleLogger::Everywhere:
perl -MLWP::ConsoleLogger::Everywhere your_script.pl
Hetzner APIs
| API | Base URL | Purpose | |-----|----------|---------| | Cloud API | api.hetzner.cloud | Cloud Servers, Volumes, Networks, DNS, Load Balancers | | Robot API | robot-ws.your-server.de | Dedicated Servers, IPs, Reset |
Note: The old standalone DNS API (dns.hetzner.com) no longer exists. DNS is now part of the Cloud API.
Development
# Run tests
prove -l t/
# Run integration tests (requires API token)
HETZNER_TEST_TOKEN=xxx prove -lv t/integration_cloud.t
# Build
dzil build
# Release
dzil release
License
This is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Author
Torsten Raudssus torsten@raudssus.de (GETTY)