4 minute read

I need to remotely maintain DNS entries at my InterServer webhosting instance, and I want to use the cPanel API v2 for that, because that’s basically all InterServer, the DNS and hosting service I currently use, is providing access to.

Link: cPanel documentation

Current situation and difficulties

My main goal was to find a way of implementing this with acme.sh or certbot to enable automatic wildcard certificate renewals with Let’s Encrypt in a reverse proxy container. The reason for this (likely overly complex) setup is that I have a Synology DiskStation behind my home router, that serves some applications available publicly (e.g. a photo gallery). This device isn’t the only device that’s hosting externally accessible resources, but until now that wasn’t much of an issue: DSM, the OS that’s running Synology devices, comes with a reverse proxy package, that can serve other applications too, additionally to those installed directly on the DiskStation.

Recently I’ve switched to automated installations of my RaspberryPis and other stuff, including applications hosted in containers on these RaspberryPis and the DiskStation. So now the main problem is, that in order to get external services and more complex setups covered by the Synology reverse proxy, it’s configuration needs customization that needs to be carefully built, maintained and backed up, because it’s unsupported and gets overwritten with any update of the DSM. The whole process is hacky and highly annoying and unreliable.

First steps toward a solution

Docker container

The very first thing to do was setting up a Docker container that takes over the role of the reverse proxy. I’ve used a linuxserver/swag container for that, because it comes with nginx and certbot already. Docker is available through a package, and besides some more configuration hacking inside the DiskStation (that’s still way easier to replicate, if needed, and doesn’t need maintenance) it is a breeze to set up with the help of docker-compose. I’ll describe that setup in another post later…

Nginx as reverse proxy

When this container is up and running it needs to be configured to serve as reverse proxy for all desired applications. The setup of nginx is relatively easy to do for people not that much into such technical details, and also is pretty well documented. I may also write about my setup later, if I think it is special enough to be of value for anyone else but me.

Certbot for certificate auto-renewal

The next component in this setup is certbot which is responsible for the automatic requests and renewals of SSL certificates. The easiest way for me to do this so far was letting the DSM do this. BUT: this implementation doesn’t support wildcard certificates, and that meant I needed a different solution now. I no longer wanted to go through the hassle of maintaining a dozen different certificates or have multiple unrelated server names hosted by one certificate. So for me the obvious solution for a centralized home-network reverse proxy is a wildcard certificate.

In a company’s network, or in bigger installations I probably wouldn’t use one wildcard certificate for everything, but - it’s my stuff, and I want one, so I’ll get one!…


The last piece of this puzzle is access to DNS, because the automated implementations of Let’s Encrypt auto-renewal of wildcard certificates works only with TXT records in DNS. Bots like acme.sh and certbot come with a host of plugins for several DNS providers - but InterServer is not amongst them. Fortunately they provide access to the cPanel API, so this makes things a lot easier…right?

Well, not exactly.

Extra hurdles put up by shared webhosting

No password?

The price of a webhosting package can be higher than what’s on the regular invoice. In the case of InterServer it is the lack of access to cPanel functionality in their shared Webhosting. Specifically the missing password to my own account. The way the InterServer webhosting is logging me into cPanel is by creating a child session in cPanel from out of my current session in the parent portal. I’ll then get forwarded to said child session and can administer my package from there. Except: I can not change my password, and I can not create additional cPanel users (only FTP, Email etc.).

Use an API key instead

Luckily the system does allow for creating an API key, and after studying the cPanel documentation I also found out how to use it. So here are some example calls that one can use to either play around with it, put them into scripts for recurring tasks, or wrap a Python or PowerShell script around it for more complex usage.

BTW, the reason for using the outdated version 2 of the API is that there are no equivalent commands available in cPanels newer UAPI.

Manual API calls

I’ve came up with the following calls against the API to test the communication with the API, as well as the creation and removal of TXT (and CNAME) records, which is necessary to get wildcard certificates issued by Let’s Encrypt.

Simple domain lookup

This is an easy way to verify general functionality, authentication, access permission etc.

curl -H'Authorization: cpanel USER:API_KEY' 'https://my_domain.com:2083/execute/DNS/lookup?domain=my_domain.com'

Get entire zone file

This dumps the entire zone file as is.

curl -H'Authorization: cpanel USER:API_KEY' 'https://my_domain.com:2083/json-api/cpanel?cpanel_jsonapi_user=user&cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzone&domain=my_domain.com'

Add CNAME record

The record name in this example is cname-test.

curl -H'Authorization: cpanel USER:API_KEY' 'https://my_domain.com:2083/json-api/cpanel?cpanel_jsonapi_user=user&cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=add_zone_record&domain=my_domain.com&name=cname-test&type=CNAME&cname=www.other_domain.com'

Add TXT record

The record name in this example is le-test.

curl -H'Authorization: cpanel USER:API_KEY' 'https://my_domain.com:2083/json-api/cpanel?cpanel_jsonapi_user=user&cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=add_zone_record&domain=my_domain.com&name=le-test&type=TXT&txtdata=1234567890ABCDEF'

Get line number for specific name in zone file

In order to remove an entry we need to know first where that entry is located in the file.

Note: the name in the zone file is an FQDN including a trailing dot! So here the name to look up is le-test.my_domain.com..

curl -H'Authorization: cpanel USER:API_KEY' 'https://my_domain.com:2083/json-api/cpanel?cpanel_jsonapi_user=user&cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzone_records&domain=my_domain.com&name=le-test.my_domain.com.&type=TXT'

Remove TXT record

When we know the number, the respective entry can be removed from the zone file.

curl -H'Authorization: cpanel USER:API_KEY' 'https://my_domain.com:2083/json-api/cpanel?cpanel_jsonapi_user=user&cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=remove_zone_record&domain=my_domain.com&line=59'