PHP Script to Edit DNS Records in CPanel
Asked Answered
T

3

8

I would like to become self-sufficient, and therefore do without services such as DNSDynamic and DYNDNS. And I don't like paying for services that I could do myself.

So here's the scenario - I have my main website hosted with a hosting company. I also have a home server with my music, etc. on it. But the problem is that my ISP (BT) does not offer consumers Static IP addresses.

I would like to have a subdomain of my main domain (which points to my main host) point to my home IP. This is done with a simple A record - which I have done myself.

This boils down to me wanting to make a PHP script (run by a cron job on my home server) to update the A records in cPanel to the current IP of my home server.

Here's some sample code - of course the bit that's missing is the API Code to communicate with cPanel, and I'd be very thankful to anyone who could fill in the gaps for me.

<?php
    $current_ip = file_get_contents("http://mydomain.com/getip.php");
    $username = "CPANEL_USERNAME";
    $password = "CPANEL_PASSWORD";
    $domain = "CPANEL_DOMAIN";

    $request = file_get_contents("http://someapipage?username=".$username."&pw=".$password."&domain=".$domain."&ip=".$current_ip);

?>

The code in http://mydomain.com/getip.php is something along the lines of simply

<?php echo $_SERVER["REMOTE_ADDR"]; ?>

I already have the grasp of how to set up a cron job, as my home server is running Ubuntu, and I have read tutorials that call my cron.php in my localhost directory using wget.

I have tried this link but I couldn't fathom what he was doing. Thanks in advance.

Terrarium answered 27/5, 2012 at 13:5 Comment(5)
Can we see the code of your attempt to implement the approach on jordih.net?Hodge
Bear in mind that (afaik) every time your DNS address changes, you'll have to wait for the TTL to expire before the changes are reflected worldwide. I should think the dynamic DNS servers would have a very low TTL for that reason.Hodge
@Hodge Thanks for the pointers - the problem is that the code on jordih.net is not really explained, and there are a load of variables with no definition; and so I don't really know where to start with that.Terrarium
Well, it would be $CPANEL_DOMAIN = 'https://mydomain.com:2083/'; (for secure access) and $core_domain = 'mydomain.com'; plus the first block of code. Try print_r($response); ?> to see what you get, and to lead you to working the rest of it out. The one thing missing is authentication to the cPanel system - you may need to log on, get a cookie, and supply it to future calls. That requires a "context" to be supplied to file_get_contents, which in turn requires a bit of research!Hodge
If port 2083 doesn't work btw, try 2082 with simple http - that leaves your session unencrypted, but might be easier to get to work.Hodge
E
14

I have just written this library for cPanel's JSON-API based on their documentation and the jordih.net links to that documentation. It's not so well documented, but the gist of it is:

Create a zone_records object by calling

$zones = new zone_records("cpaneluser", "pass", "website_to_login", "domain_of_records")

Note that the website to login is usually 127.0.0.1 if you are running this from the server you want to change the records on.

Once called, you can then access a member $zones->DNSrecords. This contains an array of the DNS A records and CNAME records (both of which are DNSrecord objects). The others (except TXT) are irrelevant since you cannot edit them without extra additions (functions) to the classes.

Each DNSrecord has some members (e.g target, ttl, name, type) which, while private, can be accessed via $record->ttl because I have added the "magic" __get method. The "magic" __set method is implemented to change the ttl and target only (you cannot change other properties using this API function, and the object will raise an exception if you try to do so).

You can use

$zones->addrecord($type, $target, $name, $ttl)

to add a record, or

$zones->deleterecord($line)

to delete the record that is on line $line in the zone file - you can find it via $record->line.

If you want to make some of your own queries in the ZoneEdit module, you can call

$zones->doquery("function_from_API", array("parameters=>"here"), array("headers"=>"here"))

and it will return the cPanel response (as will the addrecord and deleterecord methods). Finally, I would advise you to use try {...} catch (Exception $e) {...} since my objects throw exceptions if/when something goes wrong (you can edit them out of course).

This code is in the public domain - you can get it at https://github.com/ShadowLNC/cpanel_dns (classdns.php is the main file, and dns_update.php shows an example).

Earldom answered 21/12, 2012 at 9:13 Comment(0)
O
2

Edit: The link below is now broken. Here is the entire script for reference:

#!/usr/bin/perl
# -------------------------------------------------------------------------------
# neobitti_update_ip.pl
#
# Version 1.0 - 16.01.2012
#
# PERL script to dynamically update the IP of a host via the cPanel-API. This
# script was written to work with the Finnish hoster Neobitti but it might work
# with other hosters which use cPanel too.
#
# Copyright (C) 2012 Stefan Gofferje - http://stefan.gofferje.net/
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
# -------------------------------------------------------------------------------
use strict;
use LWP::UserAgent;
use MIME::Base64;
use XML::Simple;
use Data::Dumper;
# --- Command line parameters ------------------------------------------------
my $param_domain=$ARGV[0];
my $param_host=$ARGV[1];
my $param_ip=$ARGV[2];
# --- cPanel information -----------------------------------------------------
# Storing passwords in clear text is ugly!
my $cpanel_domain = "example.com";
my $user = "username";
my $pass = "password";
my $auth = "Basic " . MIME::Base64::encode( $user . ":" . $pass );
# --- Deactivate SSL certificate validation ----------------------------------
# This is ugly but neccessary because Neobitti uses self-signed SSL
# certificates which will fail validation
my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 });
# --- Find out the linenumber for the A-record we want to change -------------
sub getlinenumber_a {
  my $domain=$_[0];
  my $hostname=$_[1].".";
  my $xml = new XML::Simple;
  my $request = HTTP::Request->new( GET => "https://$cpanel_domain:2083/xml-api/cpanel?cpanel_xmlapi_module=ZoneEdit&cpanel_xmlapi_func=fetchzone&domain=$domain" );
  $request->header( Authorization => $auth );
  my $response = $ua->request($request);
  my $zone = $xml->XMLin($response->content);
  my $linenumber="";
  print $response->content . "\n";
  print $zone . "\n";
  print $zone->{'data'}->{'status'} . "\n";
  print $zone->{'data'}->{'record'} . "\n";
  if ($zone->{'data'}->{'status'} eq "1") {
    my $count = @{$zone->{'data'}->{'record'}};
    my $oldip="";
    for (my $item=0;$item<=$count;$item++) {
        my $name=$zone->{'data'}->{'record'}[$item]->{'name'};
        my $type=$zone->{'data'}->{'record'}[$item]->{'type'};
        print $name;
        if ( ($name eq $hostname) && ($type eq "A") ) {
          $linenumber=$zone->{'data'}->{'record'}[$item]->{'Line'};
          $oldip=$zone->{'data'}->{'record'}[$item]->{'record'};
          print "Found $hostname in line $linenumber with IP $oldip.\n"; # DEBUG
        }
    }
  } else {
    $linenumber="0";
    print $zone->{'event'}->{'data'}->{'statusmsg;'}
  }
  return($linenumber);
}
# --- Change the IP address record for a certain linenumber ------------------
sub setip {
  my $domain=$_[0];
  my $linenumber=$_[1];
  my $newip=$_[2];
  my $result="";
  my $xml = new XML::Simple;
  my $request = HTTP::Request->new( GET => "https://$cpanel_domain:2083/xml-api/cpanel?cpanel_xmlapi_module=ZoneEdit&cpanel_xmlapi_func=edit_zone_record&domain=$domain&line=$linenumber&address=$newip" );
  $request->header( Authorization => $auth );
  my $response = $ua->request($request);

  my $reply = $xml->XMLin($response->content);
  if ($reply->{'data'}->{'status'} eq "1") {
    $result="1";
  } else {
    $result=$reply->{'data'}->{'statusmsg'};
  }
  return($result);
}
# --- Main procedure ---------------------------------------------------------
print "Trying to find the linenumber for $param_host in $param_domain...\n";
my $line=getlinenumber_a($param_domain,$param_host);
if ( ($line ne "0") && ($line ne "") ) {
  print "Trying to update IP...\n";
  my $result=setip ($param_domain,$line,$param_ip);
  if ($result eq "1") {
    print "Update successful!\n";
  } else {
    print "$result\n";
  }
} else {
  print "Error - check domain and hostname!\n";
}

You need to replace "username" and "password" with your own credentials.

Run the script and pass in the domain name, the subdomain name and the new IP of the subdomain:

./neobitti_update_ip.pl <domain> <subdomain> <ip>

Example:

./neobitti_update_ip.pl example.com subdomain.example.com 93.184.216.34

Below is my original answer with a link to the source:


There is a Perl-script doing the exact thing you are requesting here:

http://stefan.gofferje.net/it-stuff/scripts/50-dynamic-dns-update-via-cpanel-api

If it has to be PHP I suppose it should be fairly simple to translate from Perl to PHP (or any other language). The author of the script has posted some background information here.

Otilia answered 21/12, 2012 at 1:2 Comment(2)
"You do not have permission to view this page", too bad link is brokenAtchison
Yes, it seems like it is now broken. I added a copy of the script to the post for reference.Otilia
B
0

There is a bash script for linux to solve the original question asked, namely how to automate the update of an web address to point to a changing IP. The well known and well working ddclient is the standard tool for many providers, but unfortunately not (yet) working for cPanel driven providers (I use serverprofis.de but there is a long list of others).

The bash script is found at github and I have just edited in the code the credentials etc. as found on cPanel and then added a cron job to execute it every few minutes. The script checks, like ddclient, whether the IP has changed and stops if no change is detected compared to the last update of the provider. If the IP has changed, it changes the record at the provider to point to the new IP.

It works well so far.

Blastomere answered 21/11, 2018 at 7:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.