Acme & cPanel/WHM



  • Hello,

    I am seeking for a way to automatically copy my Let's Encrypt certificate from my cPanel host to pfSense. cPanel does the auto-renewal for this (wildcard) certificate.
    I copied the certificate manually by opening a FTP session to my cPanel host and grabbing the lets-encrypt config file from my domain.
    The certificate data is stored as JSON in file /.cpanel/nvdata/letsencrypt-cpanel. This file holds every certificate requested by the Let's encrypt plugin in cPanel. I have manually extracted the private and public key (for my wildcard domain *.lan.domain.com) and inserted these in pfSense. This seems to work great. The router and even my captive portal have a valid certificate now. Great!

    Next step is to automate the renewal process... Do I need to write a pfSense plugin for this? Or am I overlooking something?
    I still have to figure out if I need to copy the private key again after a certificate renewal. I assume that the private key stays the same and I only need the public key to be renewed on pfSense. Which would be easier as I can grab this key from an https request.

    What would be the best option to automate these renewals with a host running on cPanel/WHM? Any advice?

    Sincerely yours, VinzzB



  • I have never developed on freenas or pfSense before so i am searching for good (and easy) ways to accomplish my task.

    I just discovered the PHP shell and i made a small script to download the json file from my host. This seems to work just fine.
    Now i need to parse this json file and extract the necessary ssl keys (public/private/issuer). This should be an easy one. But the next step is still unknown territory for me.
    How can i replace a certificate in pfSense within this PHP shell?
    Can i run this script as a cronjob (including the php pfsense tools)?

    This is the code i have so far (downloading file through FTPS protocol):

    <?php
    $ftp_server = 'ftp.domain.com';
    $local_file = '/home/letsencrypt-cpanel';
    $server_file = '/.cpanel/nvdata/letsencrypt-cpanel';
    $ftp_user_name = 'username';
    $ftp_user_pass = 'password';
    $conn_id = ftp_ssl_connect($ftp_server);
    $login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
    ftp_pasv($conn_id, true);
    if (!$login_result)
        die("can't login");
    
    if (ftp_get($conn_id, $local_file, $server_file, FTP_BINARY))
        echo "Successfully written to $local_file\n";
    else
        echo "There was a problem\n";
    ftp_close($conn_id);
    

    I will update this post when i got more stuff working. (json parser, updating certs on pfsense)



  • I've completed my small php script and it seems to work well.
    This is the result in case anyone needs it:

    // -- CONFIG 
    $certname = 'lan.domain.com'; //a registered FQDN in cPanel with acme let's encrypt enabled (wildcard cert)
    $pfsense_cert_id = 1; // certificate id in pfsense to overwrite. (The correct ID can be found by hovering over an icon in the cert manager or by looking in the config file.
    $ftp_server = 'ftp.domain.com'; //ftps location to your domain (cpanel).
    $ftp_user_name = ''; 
    $ftp_user_pass = '';
    $server_file = '/.cpanel/nvdata/letsencrypt-cpanel'; //download file used by cPanel holding every certificate (in JSON format).
    
    // -- PROGRAM
    $conn_id = ftp_ssl_connect($ftp_server);
    $login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
    ftp_pasv($conn_id, true);
    if (!$login_result)
        die("can't login");
    
    ob_start();
    $dataLoaded = ftp_get($conn_id, "php://output", $server_file, FTP_BINARY);
    $data = ob_get_contents();
    ob_end_clean();
    ftp_close($conn_id);
    
    if (!$dataLoaded)
    	die("There was a problem downloading the json data from $ftp_server");
    
    $jsonData = json_decode($data, true);
    $cert = $jsonData['certs'][$certname];
    
    if(empty($cert))
    	die("Certificate with name $certname not found");
    
    $config['cert'][$pfsense_cert_id ]['prv'] = base64_encode($cert['key']);
    $config['cert'][$pfsense_cert_id ]['crt'] = base64_encode($cert['cert']);
    write_config();
    exec('/etc/rc.restart_webgui');
    
    //echo 'Certificate:', PHP_EOL, $cert['cert'], PHP_EOL;
    //echo 'Key:', PHP_EOL, $cert['key'], PHP_EOL;
    echo 'New certificate for ', $certname, ' is valid untill ', gmdate('r',$cert['cert_expiry']), PHP_EOL;
    exit;
    
    

    I've uploaded the file (named sslupdate) to the /etc/phpshellsessions directory in pfsense and I added the following cron job (through the cron package):

    0 0 1 1/3 * :  /usr/local/sbin/pfSsh.php playback sslupdate
    

Log in to reply