As Let’s Encrypt doesn’t support wildcard certificates (yet) you may have to share your certificate between hosts. One such scenario could be if you run a Nginx Reverse Proxy and need a certificate for a domain on both the proxy host and the backend. One example is when running ZNC. In a normal situation you would buy a wildcard certificate and place the cert on both hosts. But with a Reverse Proxy in front, and only one public IP that would be impossible when using Let’s Encrypt as it would only allow you to generate certs on the proxy host.

To solve this you can create a share between the Nginx Reverse Proxy and the backend host over NFS, then update the cert on the backend (if needed) via a cronjob. In our case we needed a .pem file of all the Let’s Encrypt .pem files togheter to be able to host ZNC over SSL. In this guide “Nginx” is the reverse proxy server, and ZNC is the backend where we placed the ZNC server. Here is how it’s done.

  1. Install NFS Server on the Proxy frontend, Nginx.
    $~: sudo apt install nfs-kernel-server -y
  2. Setup an exports file
    $~: sudo nano /etc/exports

    and place the folder that you want to share in that file

    # /etc/exports: the access control list for filesystems which may be exported
    # to NFS clients. See exports(5).
    #
    # Example for NFSv2 and NFSv3:
    # /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
    #
    # Example for NFSv4:
    # /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
    # /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
    #
    /etc/letsencrypt 192.168.6.178(ro,async,no_root_squash,no_wdelay,no_subtree_check)
  3. Set up which hosts that are allowed access, could be several
    # /etc/hosts.allow: list of hosts that are allowed to access the system.
    # See the manual pages hosts_access(5) and hosts_options(5).
    #
    # Example: ALL: LOCAL @some_netgroup
    # ALL: .foobar.edu EXCEPT terminalserver.foobar.edu
    #
    # If you're going to protect the portmapper use the name "rpcbind" for the
    # daemon name. See rpcbind(8) and rpc.mountd(8) for further information.
    #
    
    portmap: 192.168.6.178 , 192.168.10.111
    lockd: 192.168.6.178 , 192.168.10.111
    rquotad: 192.168.6.178 , 192.168.10.111
    mountd: 192.168.6.178 , 192.168.10.111
    statd: 192.168.6.178 , 192.168.10.111

    192.168.10.111 is just an extra host in our configuration which also have access to the Let’s Encrypt certs

  4. Don’t forget to deny everything else
    # /etc/hosts.deny: list of hosts that are _not_ allowed to access the system.
    # See the manual pages hosts_access(5) and hosts_options(5).
    #
    # Example: ALL: some.host.name, .some.domain
    # ALL EXCEPT in.fingerd: other.host.name, .other.domain
    #
    # If you're going to protect the portmapper use the name "rpcbind" for the
    # daemon name. See rpcbind(8) and rpc.mountd(8) for further information.
    #
    # The PARANOID wildcard matches any host whose name does not match its
    # address.
    #
    # You may wish to enable this to ensure any programs that don't
    # validate looked up hostnames still leave understandable logs. In past
    # versions of Debian this has been the default.
    ALL: PARANOID
    
  5. Now restart NFS
    $~: service nfs-kernel-server restart
  6. Now go to the backend (ZNC) and add this in /etc/fstab
    # NFS
    192.168.16.201:/etc/letsencrypt/ /mnt/letsencrypt nfs auto 0 0
  7. Create the mount dir on the backend
    $~: sudo mkdir /mnt/letsencrypt
  8. Install NFS on the backend
    $~: sudo apt install nfs-common -y
  9. Now mount the folder
    $~: sudo mount -a
  10. Check that it’s working
    $~: sudo ll /mnt/letsencrypt

    If the dir is listed and you can see all the certs that exists on the Nginx server then everything is OK.

    Now we have to be sure that the certs are updated correctly so that they don’t become invalid in case they get updated. To do this we add a simple cronjob that checks if the parent file is older than the one in the mounted Let’s Encrypt dir. This isn’t needed on all setups, but ZNC especially demands a certain .pem file which contains all the Let’s Encrypt .pem files.

  11. Before we create the script we have to generate the file
    $~: cat /mnt/letsencrypt/live/irc.domain.se/{privkey,cert,chain}.pem > /home/user/.znc/znc.pem
  12. Then start generating the script
    $~: sudo nano /var/scripts/zncssl.sh
    #!/bin/bash
    
    if [[ "/home/user/.znc/znc.pem" -ot "/mnt/letsencrypt/live/irc.domain.se/fullchain.pem" ]]
    then
     cat /mnt/letsencrypt/live/irc.domain.se/{privkey,cert,chain}.pem > /home/user/.znc/znc.pem
    fi
  13. Make the file executable and add it as a cronjob that runs after the renew script for Let’s Encrypt is run (preferably)
    $~: sudo chmod +x /var/scripts/zncssl.sh && crontab -e
  14. Add this line to the crontab
    42 18 * * * /var/scripts/zncssl.sh > /dev/null
  15. Now use the znc.pem that we created as the SSLCertFile in ZNC
    $~: sudo nano /home/techuser/.znc/configs/znc.conf
  16. And add this line to your config
    SSLCertFile = /home/user/.znc/znc.pem
  17. Now everything is done, congrats you now have a free SSL from Let’s Encrypt on two hosts

If you later want to add more backends to access the Let’s Encrypt certs just add them to the /etc/hosts.allow file like we did in this guide.

Feel free to comment, and let us know if you find any errors in this guide.