I have a valid letsencrypt certificate that is used by apache server.

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName mydomain.com
        SSLCertificateFile /etc/letsencrypt/live/mydomain.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/mydomain.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf

This certificate is automatically renewed using certbot:

sudo ls /etc/letsencrypt/mydomain.com/live/ -al

lrwxrwxrwx 1 root root   41 Dec 31 08:46 fullchain.pem -> ../../archive/mydomain.com/fullchain8.pem
lrwxrwxrwx 1 root root   39 Dec 31 08:46 privkey.pem -> ../../archive/mydomain.com/privkey8.pem

Apache is running under www-data user account.

www-data  6452  0.0  0.4 472056 41852 ?        S    01:44   0:11 /usr/sbin/apache2 -k start

I also have a web socket server that needs to use this certificate. When I run the web socket server with www-data user I get following error:

RuntimeException: Connection from tcp:// failed during TLS handshake: Unable to complete TLS handshake: SSL_R_NO_SHARED_CIPHER: no suitable shared cipher could be used. This could be because the server is missing an SSL certificate (local_cert context option)...

Which basically means it cannot access the certificate. If I copy the fullchain8.pem and privkey8.pem files to another location where www-data has access the error changes (but that is another problem :) ).

I know it is a bad idea to copy a private key file to a place where www-data has access, and I definitely do not want the web socket server to run with root privileges. So my question is, how can I access the certificate? Apache seems to know its way around.

1 Answer 1


If you run ps auxw | grep httpd you'll see that while most of the apache webserver processes are owned by www-data, there is one process owned by root. This is the master process which (amongst other things) reads the certificate at startup.

Further, if you have a look in the directory /etc/letsencrypt/live you'll find one or more synlinks to where the files actually reside. This complexity is there for a reason. And you really don't want to change things around in there - you don't want to break certbot.

While you told us lots about the webserver, you didn't tell us anything about the web socket server. It may have some mechanism to avoid this issue.

You can add a deploy-hook script in the certbot config to copy the certificate and key from /etc/letsencrypt/live/mydomain.com/ to another location with different permissions (and restart the websocket certificate / signal it to reload the certificate). This can be specified on the certbot command line when first creating the certificate or it can be manually added to /etc/letsencrypt/renewal/mydomain.com.conf later.

I've not tried this myself, but I believe this would simply be something like....

deploy-hook = /usr/local/sbin/updatewebscoketserver

at the end of the file, under the [renewalparams] section.

(you get to write the script yourself).

Do you really need to run the websocket server as the same uid as the webserver?

  • Thank you for the explanation, it is very helpful to me. The web socket server is my own creation (and works fine with a self-signed certificate on my dev machine). I will look into certbot config.
    – geldek
    Feb 25, 2022 at 6:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .