Netgate Discussion Forum
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search
    • Register
    • Login

    How to Install Certificates from PFsense to other servers?

    Scheduled Pinned Locked Moved ACME
    25 Posts 7 Posters 11.2k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • L
      lrossi
      last edited by

      I am new to this whole certificates thing and pfSense in general so bear with me.

      I have successfully setup ACME in pfSense to create let's encrypt certificates for my subdomain which is provided by the DDNS service provider duckdns.

      Now, how do i install these certificates after pfSense has obtained them? My question is about their distribution more than anything else as I'm not expecting support here on how to install certificates on my webserver application.

      Is there any way to "push" these certificates out of pfSense, like with an "mv" or "cp" script to move or copy them to my samba server for example?

      Or is there a way for my servers to retrieve such certificates from pfSense, with a "wget" script maybe?

      How have you guys done it in the past?

      1 Reply Last reply Reply Quote 0
      • P
        psp
        last edited by

        It is possible from inside the GUI, downloading them directly with a browser. From System/Certificate Manager on every certificate you have on the right (under "Actions" column) one icon to export the certificate and one to export its key only.

        L 1 Reply Last reply Reply Quote 0
        • L
          lrossi @psp
          last edited by

          @psp Thanks for your quick reply!!!.
          Your suggestion is definitely an option but it requires manual intervention at least once every 90 days (since the certificates expire in 90 days).

          This is not ideal for me as I will eventually forget to do this on time. I was hoping to automate the certificates renewal and installation to avoid this from happening.

          Do you know if this is possible? maybe with a post script that runs after the certificate has been created/renewed?

          GertjanG 1 Reply Last reply Reply Quote 0
          • P
            psp
            last edited by psp

            I'm currently not aware of any changes more recent than this answer.

            1 Reply Last reply Reply Quote 0
            • GertjanG
              Gertjan @lrossi
              last edited by

              @lrossi said in How to Install Certificates from PFsense to other servers?:

              at least once every 90 days

              More like 60 days.

              @lrossi said in How to Install Certificates from PFsense to other servers?:

              Now, how do i install these certificates after pfSense has obtained them?

              The certifacte obtained is meant to used for the GUI, so the https access won't throw warnings any more.
              If you asked for a wild card cert, lie *.your-domain.tld then you can export the cert and install it on other devices like printers, NAS, etc : everything that

              1. has a GUI
              2. permit you to upload your own certs.

              If you want to script all this, then : the devices where you want to use the cert on, has a SSH (telnet ?) access ? Does it permit you to upload info like that ? Place the certs ?

              pfSense has a SSH access, so some scripting can be used to access the files from here : /cf/conf/acme
              pfSense is 'open' enough to script - the question is : the other devices, to where you want to export the certs to ?

              Normally, I export my wold card cert, and import it into my NAS and 2 printers.
              But when I forget it, well, not an issue, I click away the warning.

              If you other devices are web services, then you have SSH etc.
              Tel us how your what you scripted ;)

              No "help me" PM's please. Use the forum, the community will thank you.
              Edit : and where are the logs ??

              L 1 Reply Last reply Reply Quote 0
              • L
                lrossi @Gertjan
                last edited by

                @gertjan At the moment i only care about the certificate for an Owncloud instance that i have installed in an Ubuntu server box. So, my device is capable of SSH and scripting.

                About the scripting itself for the ubuntu box, well, i haven't gone that far yet as I'm in the research phase at the moment and I was wondering how other people have done it with pfSense.

                Your answer made me realize that automatically exporting certificates may not be so common since the ACME package is really tailored for the pfSense GUI or to be used in conjunction with HAproxy.

                I tried to follow the videos from Lawrence Technologies for the HAProxy but for the life of me I couldn't make it work.

                I may just have to deal with the certificate issue/renew directly in the ubuntu box.

                I honestly wanted to make use of the excellent ACME package because "it just works!!!!" with duckdns.

                GertjanG 1 Reply Last reply Reply Quote 0
                • GertjanG
                  Gertjan @lrossi
                  last edited by

                  @lrossi said in How to Install Certificates from PFsense to other servers?:

                  I tried to follow the videos from Lawrence Technologies for the HAProxy but for the life of me I couldn't make it work.

                  HAProxy uses a cert from the cert list.
                  Like the GUI select box for the acme cert :

                  6311c2fc-30e6-4683-90b0-73545be4e8ca-image.png

                  Like this :

                  e0d9f7a2-5d7e-4c3b-bde6-a251a00c1f2b-image.png

                  that should do it.

                  Btw : I'm not using ha-proxy myself.

                  No "help me" PM's please. Use the forum, the community will thank you.
                  Edit : and where are the logs ??

                  1 Reply Last reply Reply Quote 0
                  • V
                    victorlclopes
                    last edited by victorlclopes

                    There is a relatively simple way to do this:

                    https://victorlclopes.medium.com/copy-pfsense-acme-certificate-to-another-server-e42c611c47ec

                    I'm reviving this post just to make it easier for others looking for this solution. Beyond of what the article says, I would suggest using a dedicated, low privileged user to copy the certificate.

                    While we're in the subject, HAproxy works amazingly with ACME certificates, as others said. If your internal web service will be accessed only through the pfSense firewall, you could leave a self-signed certificate on the server itself, for example, and then use HAproxy to serve the website using an automated Let's Encrypt certificate (not having to copy certs around). But sometimes you need the certificate on the internal server as well, either because it is supposed to be accessed internally too or because other (non-web) services will also need that same certificate, like IMAP, LDAPS, etc.

                    L B 2 Replies Last reply Reply Quote 2
                    • L
                      lrossi @victorlclopes
                      last edited by

                      @victorlclopes thank you so much for your reply. I ended up using the same solution you are suggesting on your post.

                      I wish i found your post back then because you explained everything in a very simple and systematic manner. Kudos to you.

                      I tried the HA Proxy solution but i couldn’t make it work for the life of me. I even followed the videos from Lawrence on youtube without success. That’s when i found about the “scp” and have been using it since.

                      In addition to what you suggested, I wanted to automate the process of downloading the certificate from the pfsense firewall and installing it in the local server because i knew that at some point i was going to forget to manually check if there was a new certificate.

                      So, i created a scrip that runs as a cron job on the local server once a day. The scripts checks if there is a new certificate available in the pfsence firewall and only attempts to download such certificate if there is a new one.

                      Then, it sends me an email letting me know that a new certificate was installed. It doesn’t send me any emails unless a new certificate is found and installed.

                      I wanted to share this solution before but i was waiting to see if the script worked before posting it here. You just beat me by a couple of days because my certificate was successfully updated this morning. Although the email portion failed for some reason, i need to hunt down that bug.

                      If anybody is interested, my script is as follows, i figured this could be my contribution to the community. Just make sure to adjust the variables to match your enviroment:

                      #!/bin/bash
                      #script to download the SSL certficicates
                      #from pfsense for the indicated domain
                      #
                      #by lrossi 07-18-2021
                      
                      ##################################################################
                      # modify the variables for host, cert, key
                      # localcert, localkey and TMP_output
                      # to meet your needs
                      
                      # change host to match the name of the ssh
                      # connection to the pfsense firewall
                      # as defined in the file ~/.ssh/config
                      host='pfsense'
                      
                      # location of the ssl certificate and
                      # keyfile in pfsense firewall
                      cert='/cf/conf/acme/URLOFVERTIFICATE.com.crt'
                      key='/cf/conf/acme/URLOFVERTIFICATE.com.key'
                      
                      # location of the ssl certificate and
                      # key file in local server
                      localcert='/etc/apache2/ssl/URLOFVERTIFICATE.com.crt'
                      localkey='/etc/apache2/ssl/URLOFVERTIFICATE.com.key'
                      
                      #name and location of the log file in the local server
                      TMP_OUTPUT="/var/log/pfsense-certificates.log"
                      
                      #information for email notifications
                      EMAIL_SUBJECT_PREFIX="SSL Certificate -"
                      TO_EMAIL_ADDRESS="EMAIL-OF-ADMIN@@DOMAIN.com"
                      FROM_EMAIL_ADDRESS="EMAIL-OF-LOCAL-SERVER@DOMAIN.com"
                      FROM_NAME="HOSTNAME OF LOCAL SERVER"
                      
                      # end of variables
                      
                      # start of script
                      
                      # DO NOT MODIFY BELOW THIS LINE unless you understand the code
                      #####################################################################
                      
                      #create a log file if one is not found.
                      if [ ! -f $TMP_OUTPUT ]; then
                              touch $TMP_OUTPUT
                      fi
                      
                      echo '==============================='  >$TMP_OUTPUT
                      echo '==============================='  >>$TMP_OUTPUT
                      echo 'Verification of SSL Certificate'  >>$TMP_OUTPUT
                      echo 'from PFSense'                     >>$TMP_OUTPUT
                      echo $(date)                            >>$TMP_OUTPUT
                      echo '==============================='  >>$TMP_OUTPUT
                      echo ''                                 >>$TMP_OUTPUT
                      
                      #download the online certificate and key only if certificate is newer
                      if cmp -s $localcert <(ssh $host "cat $cert")
                      then
                      	echo 'the online certificate'		>>$TMP_OUTPUT
                      	echo 'has not been updated.'		>>$TMP_OUTPUT
                      	echo 'nothing to do'			>>$TMP_OUTPUT
                      	echo ''					>>$TMP_OUTPUT
                      	echo '==============================='	>>$TMP_OUTPUT
                      	echo '==============================='	>>$TMP_OUTPUT
                      
                      else
                      	echo 'There is a new certificate'	>>$TMP_OUTPUT
                      	echo ''					>>$TMP_OUTPUT
                      	echo 'Downloading new certificate'	>>$TMP_OUTPUT
                      	scp $host:$cert $localcert		>>$TMP_OUTPUT
                      	wait
                      	
                      	echo ''					>>$TMP_OUTPUT
                      	echo 'Downloading new Key'		>>$TMP_OUTPUT
                      	scp $host:$key $localkey		>>$TMP_OUTPUT
                      	wait
                      	
                      	echo ''					>>$TMP_OUTPUT
                      	echo 'Restarting the apache webserver'	>>$TMP_OUTPUT
                      	systemctl restart apache2		>>$TMP_OUTPUT
                      	wait
                      	
                      	echo''					>>$TMP_OUTPUT
                      	echo 'New certificate has been installed'	>>$TMP_OUTPUT
                      	echo ''					>>$TMP_OUTPUT
                      	echo '================================='	>>$TMP_OUTPUT
                      	echo '================================='	>>$TMP_OUTPUT
                      	
                      	cat "$TMP_OUTPUT" | /usr/bin/mail -s "$EMAIL_SUBJECT_PREFIX Updated and installed" -a "FROM: $FROM_NAME <$FROM_EMAIL_ADDRESS>" $TO_EMAIL_ADDRESS
                              wait
                      fi
                      
                      exit 0;
                      
                      
                      1 Reply Last reply Reply Quote 0
                      • M
                        mwebb
                        last edited by mwebb

                        Think my automated solution may help others. I have a preference to issue and renew only one certificate and reuse on multiple machines. I use ACME pkg to issue/renew a single "Let's Encrypt" certificate with multiple sites and wildcards with DNS api to namecheap. As part of the ACME renewal I automate the copy of the certificate to the XMLRPC primary on other pfsense clusters (that do not have ACME installed) and call the following custom script to update it there.

                        The method laid out below needs the certificates and script to be on the target machine, and assumes ACME pkg to be on the source machine. In my haste to get this working in my Lab I set up a root level trust between them (not good practice) would be better to set this up a user with limited access. To eliminate the need for the ssh trust, the certificates can rather be copied to another secure machine on the network and the script can be run once a week with cron by the individual target hosts. (ACME certificates are typically renewed every 60 days and are valid for 90.)

                        The custom script combines only the essential script code that I found in the ACME pkg libraries which calls code from built-in pfsense libraries to update the certificate. The good thing about custom is that it is compact, however, there is a small chance that a future pfsense update that changes the certificate store management could break it. A way around this is to install ACME pkg on all the target machines (to benefit from updates) but then the ACME certificate list must have the same certificate name in the ACME inventory but the item must NOT be active (i.e. configured but not requesting renewal), and then call /usr/local/pkg/acme/acme_command.sh directly.

                        #!/usr/local/bin/php -f
                        <?php
                        
                        
                        /* 
                        custom_cert_import.sh
                        
                        Script to copy and import a certificate from one pfsense machine to another.
                        
                        - ACME package install is optional, but recommended on source host. Works with certs with multi sites and wildcards.
                        - Intended to be part of system to automate the publishing of one certificate from one machine to many.
                        - If certificate <CERT_NAME> exists in in the store it is replaced
                        - The method assumes that the certificate <CERT_NAME> is already on in the target system certificate store and selected for use by Web Configurator and/or Packages (e.g. HAPROXY).
                        
                        Suggested use: 
                        1. For first use establish ssh trust between source and target host
                        > ssh-copy-id -i ~/.ssh/id_rsa.pub root@<REMOTE_HOST_IP1>
                        
                        2. For first use manually copy script to target that is an XMLRPC primary in another pfsense CARP cluster (e.g. non-ACME host)
                        > scp -i /root/.ssh/id_rsa custom_cert_import.sh root@<REMOTE_HOST_IP1>:/<PATH1>/ 
                        
                        3. Add the following lines to ACME post-renewal host commands on the source (ACME) host
                        > scp -i /root/.ssh/id_rsa /cf/conf/acme/<CERT_NAME>.* root@<REMOTE_HOST_IP1>:/<PATH1>/ 
                        > ssh root@<REMOTE_HOST_IP1> php /<PATH1>/pfsense_custom_cert_import.sh importcert <CERT_NAME> <DOMAIN> /<PATH2>/<CERT_NAME>.key /<PATH2>/<CERT_NAME>.crt /<PATH2>/<CERT_NAME>.ca /<PATH2>/<CERT_NAME>.fullchain
                        > ssh root@<REMOTE_HOST_IP1> /etc/rc.filter_synchronize  		<-------- refresh remote system firewall to start using updated certificate
                        > ssh root@<REMOTE_HOST_IP1> /usr/local/etc/rc.d/haproxy.sh restart	<-------- refresh remote system package e.g. HAPROXY 
                        > ssh root@<REMOTE_HOST_IP2> /usr/local/etc/rc.d/haproxy.sh restart
                        
                        <REMOTE_HOST_IP1>	target host 1 (XMLRPC primary in target cluster)
                        <REMOTE_HOST_IP2>	target host 2 (XMLRPC secondary in target cluster)
                        <PATH1>			path to script on remote host
                        <PATH2> 		path to certificates on remote host
                        <CERT_NAME>		the cert description that is used to identify the certificate in the pfsense certificate store
                        <DOMAIN>		the fqdn of the certificate DN
                         
                        The code for this script has been copied from the two files below from a system with ACME package installed.
                        The code calls functions that are already part of a standard pfsense deployment.
                        
                        /usr/local/pkg/acme/acme_command.sh
                        /usr/local/pkg/acme/acme.inc 
                        
                        */
                        
                        
                        // ******************************************************
                        // Code below is from /usr/local/pkg/acme/acme_command.sh
                        // ******************************************************
                        
                        require_once("functions.inc");
                        
                        $command = $argv[1];
                        
                        if ($command == "importcert") {
                        	$certificatename = $argv[2];
                        	$domain = $argv[3];
                        	$CERT_KEY_PATH = $argv[4];
                        	$CERT_PATH = $argv[5];
                        	$CA_CERT_PATH = $argv[6];
                        	$CERT_FULLCHAIN_PATH = $argv[7];
                        	echo "\nIMPORT CERT $certificatename, $CERT_KEY_PATH, $CERT_PATH";
                        	storeCertificateCer($certificatename, $CERT_KEY_PATH, $CERT_PATH, $CERT_FULLCHAIN_PATH);
                        	/*deleted code*/
                        	$changedesc = "Services: Acme: ";
                        	$changedesc .= "Storing signed certificate: " . $certificatename;
                        	write_config($changedesc);
                        	/*deleted code*/
                        	return;
                        }
                        
                        
                        // ***************************************************
                        // Code below is from /usr/local/pkg/acme/acme.inc
                        // ***************************************************
                        
                        function storeCertificateCer($certificatename, $keyfile, $cerfile, $fullchainfile) {
                        	global $config;
                        	$certupdated = false;
                        		
                        	$key = file_get_contents($keyfile);
                        	$crt = file_get_contents($cerfile);
                        	$fullchain = "";
                        	if(!empty($fullchainfile)) {
                        		$fullchain = file_get_contents($fullchainfile);
                        		preg_match_all("/-+BEGIN CERTIFICATE(.+?)END CERTIFICATE-+/s", $fullchain, $certificatematches);
                        		$first = true;
                        		foreach($certificatematches[0] as $cacert) {
                        			if ($first == true) {
                        				$first = false;
                        				continue;
                        			}
                        			saveCACertificateToStore($cacert);
                        		}
                        	}
                        	if (is_array($config['cert'])) {
                        		foreach ($config['cert'] as &$cert) {
                        			if ($cert['descr'] == $certificatename) {
                        				syslog(LOG_NOTICE, "Acme, storing new certificate: {$certificatename}");
                        				echo "\nupdate cert!";
                        				cert_import($cert, $crt, $key);
                        				$certupdated = true;
                        				break;
                        			}
                        		}
                        	}
                        		
                        	return $certupdated;
                        }
                        
                        function saveCACertificateToStore($crt) {
                        	global $config;
                        	$crt_enc = base64_encode($crt);
                        	if (!is_array($config['ca'])) {
                        		$config['ca'] = array();
                        	}
                        	$a_ca =& $config['ca'];
                        	foreach($a_ca as $ca) {
                        		if ($ca['crt'] == $crt_enc) {
                        			return;
                        		}
                        	}
                        	$subject = cert_get_subject($crt, false);
                        	$cert = array();
                        	$cert['refid'] = uniqid();
                        	$cert['descr'] = "Acmecert: {$subject}";
                        	ca_import($cert, $crt);
                        	$a_ca[] = $cert;
                        	syslog(LOG_NOTICE, "Acme, storing new CA: {$subject}");
                        }
                        
                        ?>
                        
                        
                        GertjanG 1 Reply Last reply Reply Quote 0
                        • GertjanG
                          Gertjan @mwebb
                          last edited by

                          @mwebb said in How to Install Certificates from PFsense to other servers?:

                          can be run once a week with cron by the individual target hosts. (ACME certificates are typically renewed every 60 days and are valid for 90.)

                          Use the "action list" :

                          7dfef72d-f6be-428b-93cc-405df42c72f5-image.png

                          ?

                          No "help me" PM's please. Use the forum, the community will thank you.
                          Edit : and where are the logs ??

                          M 1 Reply Last reply Reply Quote 0
                          • M
                            mwebb @Gertjan
                            last edited by

                            @Gertjan I presented 2 methods. The 1st method is simple and helps to understand the process. 2nd method is better practice but more work. Sorry can't figure out how to add screenshots. I don't use my cert on the webgui (so don't need and didn't show the webgui command). The point of my post was more to share the precious script that gives us a way to use built-in pfsense code to refresh certificates - the secret sauce of the whole thing. There are many different ways to use it.

                            First method suggests to use the ACME action list on the source server like you have shown but I caution that this method requires root access from source host to the target pfsense hosts to run the script. 2nd method is to use ACME global setting (general settings - write certificates) to copy the certificate to /cf/conf/acme (no other ACME actions needed) or to another machine (with ACME action needed), then install cron pkg on each of the targets and run the actions weekly on the target hosts which only need to be able to read the certificate from the source host or other machine.

                            1 Reply Last reply Reply Quote 0
                            • B
                              Bronko @victorlclopes
                              last edited by

                              @victorlclopes
                              Thanks for your how-to, used it since some month ago...

                              But I have an issue regarding to copy certificates to more then one server in Action list:
                              Screenshot from 2024-06-04 11-33-11.png

                              As to see I have tried both, an one liner or two separate commands (last temporary disabled for one liner test).

                              Both is working directly from pfsense CLI without interaction (based idea).

                              In case of renewal (last night) system log shows with then enabled command, but second server (10.0.0.103) never connected by ssh given by the logs there...

                              Does anyone have any experience or hints here?

                              GertjanG B 2 Replies Last reply Reply Quote 0
                              • GertjanG
                                Gertjan @Bronko
                                last edited by

                                @Bronko

                                If the first part of the third action worked : what about using a forth - the one you've disabled ?

                                Be aware : we don't know nothing about the shell session used to fire up the actions.
                                Do what the first and second action imply : instead of just 'scp', use the full path of the command scp. After all, whatever the environnement is, its not the CLI.

                                Of write a shell script, and then fire up a shell that executes the script for you.
                                With some nice log lines like "command 1 done", "command 2 done" etc

                                No "help me" PM's please. Use the forum, the community will thank you.
                                Edit : and where are the logs ??

                                B 2 Replies Last reply Reply Quote 0
                                • B
                                  Bronko @Gertjan
                                  last edited by Bronko

                                  @Gertjan said in How to Install Certificates from PFsense to other servers?:

                                  If the first part of the third action worked : what about using a forth - the one you've disabled ?

                                  This is what I have tried to describe. Two separate scp commands doesn't worked for the second (here the forth) one.

                                  Be aware : we don't know nothing about the shell session used to fire up the actions.
                                  Do what the first and second action imply : instead of just 'scp', use the full path of the command scp. After all, whatever the environnement is, its not the CLI.

                                  Of write a shell script, and then fire up a shell that executes the script for you.
                                  With some nice log lines like "command 1 done", "command 2 done" etc

                                  You are absolutely right, this is what I have to do...
                                  Will be back in two month.... SMILEY!

                                  1 Reply Last reply Reply Quote 0
                                  • B
                                    Bronko
                                    last edited by Bronko

                                    Still doesn't worked for the second copy in my script:

                                    Screenshot from 2024-08-04 12-03-36.png

                                    upcoming execution is logged:

                                    Aug 4 03:16:45 	php 	38555 	Acme, Running /home/USER/acme_post_scp.sh
                                    Aug 4 03:16:45 	php 	38555 	Acme, Running /usr/local/etc/rc.d/haproxy.sh restart
                                    Aug 4 03:16:45 	php 	38555 	Acme, Running /etc/rc.restart_webgui 
                                    

                                    the running itself:

                                    Aug 4 03:16:46 	php-cgi 	39623 	rc.restart_webgui: Creating rrd update script
                                    Aug 4 03:16:46 	php-cgi 	43383 	haproxy: started new pid:47385
                                    Aug 4 03:16:46 	php-cgi 	43383 	haproxy: reload old pid:80851 
                                    

                                    The simple echos in script doesn't find in no way into pfsense system logs, only in shell directly, but the first certificate copy to 10.0.0.100 was successful. Still no ssh connection at 10.0.0.103 sysloged there (as above).

                                    D 1 Reply Last reply Reply Quote 0
                                    • D
                                      darcey @Bronko
                                      last edited by darcey

                                      @Bronko said in How to Install Certificates from PFsense to other servers?:

                                      The simple echos in script doesn't find in no way into pfsense system logs, only in shell directly

                                      Use logger command. Does the second remote host log an ssh attempt?

                                      B 1 Reply Last reply Reply Quote 0
                                      • B
                                        Bronko @darcey
                                        last edited by

                                        @darcey said in How to Install Certificates from PFsense to other servers?:

                                        Use logger command. Does the second remote host log an ssh attempt?

                                        Thanks for logger. As mentioned above, second host never loged an ssh attempt.

                                        GertjanG 1 Reply Last reply Reply Quote 0
                                        • GertjanG
                                          Gertjan @Bronko
                                          last edited by

                                          @Bronko said in How to Install Certificates from PFsense to other servers?:

                                          As mentioned above, second host never loged an ssh attempt.

                                          You are not actually use the 'GUI' as shown above to create that shells script file, right ?

                                          No "help me" PM's please. Use the forum, the community will thank you.
                                          Edit : and where are the logs ??

                                          B 1 Reply Last reply Reply Quote 0
                                          • B
                                            Bronko @Gertjan
                                            last edited by

                                            @Gertjan said in How to Install Certificates from PFsense to other servers?:

                                            @Bronko said in How to Install Certificates from PFsense to other servers?:

                                            As mentioned above, second host never loged an ssh attempt.

                                            You are not actually use the 'GUI' as shown above to create that shells script file, right ?

                                            Nope, to be save regarding file handling installed Filer package for that...

                                            GertjanG 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Copyright 2025 Rubicon Communications LLC (Netgate). All rights reserved.