Error while installing cert with Certbot (Broken pipe)

I have a problem installing certificates with Certbot. I run a shell script (.sh) in ubuntu that automatically installs Certbot and later the certificate.

The process had always worked correctly but it seems that on June 1, version 1.16 of Certbot came out and since then the process has failed. I get a Broken pipe error. Specifically:

2021-06-03 12:37:09,024:DEBUG:certbot.display.util:Notifying user:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/mydomain.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/mydomain.com/privkey.pem
This certificate expires on 2021-09-01.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

2021-06-03 12:37:09,025:DEBUG:certbot._internal.log:Exiting abnormally:
Traceback (most recent call last):
File "/snap/certbot/1201/bin/certbot", line 8, in
sys.exit(main())
File "/snap/certbot/1201/lib/python3.8/site-packages/certbot/main.py", line 15, in main
return internal_main.main(cli_args)
File "/snap/certbot/1201/lib/python3.8/site-packages/certbot/_internal/main.py", line 1552, in main
return config.func(config, plugins)
File "/snap/certbot/1201/lib/python3.8/site-packages/certbot/_internal/main.py", line 1276, in run
_report_new_cert(config, cert_path, fullchain_path, key_path)
File "/snap/certbot/1201/lib/python3.8/site-packages/certbot/_internal/main.py", line 559, in _report_new_cert
display_util.notify(
File "/snap/certbot/1201/lib/python3.8/site-packages/certbot/display/util.py", line 107, in notify
zope.component.getUtility(interfaces.IDisplay).notification(
File "/snap/certbot/1201/lib/python3.8/site-packages/certbot/display/util.py", line 517, in notification
self.outfile.flush()
BrokenPipeError: [Errno 32] Broken pipe
2021-06-03 12:37:09,030:ERROR:certbot._internal.log:An unexpected error occurred:
2021-06-03 12:37:09,038:ERROR:certbot._internal.log:BrokenPipeError: [Errno 32] Broken pipe

If I run the call to install the certificate manually, instead of including it in the script, it works fine:

certbot --non-interactive --agree-tos --email "email@mydomain.com" --apache -d "sub.mydomain.com" -d "mydomain.com" -d "mydomain.com"

Does anyone know why Certbot, since 1.16 version appeared, gives "Broken Pipe" error when run from a bash script?

For reference, please show the bash script used.

2 Likes

Here you have the bash script:

#!/bin/sh
#script that runs as root
(
set -e
domain=$(echo "$1" | tr '[:upper:]' '[:lower:]')
subdomain=$(echo "$2" | tr '[:upper:]' '[:lower:]')
email=$3

#Check if running as root
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi

export DEBIAN_FRONTEND=noninteractive
echo "DebianFrontend to noninteractive"

cp -f /var/www/html/vhosts-base.conf /etc/apache2/sites-available/vhosts.conf
sed -i "s/sub.dominio/${subdomain}/g" /etc/apache2/sites-available/vhosts.conf
sed -i "s/dominio/${domain}/g" /etc/apache2/sites-available/vhosts.conf
echo "Vhosts.conf updated"

rm -f /etc/apache2/sites-enabled/vhosts.conf
ln -s /etc/apache2/sites-available/vhosts.conf /etc/apache2/sites-enabled/

apt-get install git -y
echo "Git installed"

snap install --classic certbot
ln -sf /snap/bin/certbot /usr/bin/certbot
echo "Certbot installed"

certbot --non-interactive --agree-tos --email "$email" --apache -d "$subdomain" -d "$domain" -d "$domain"
echo "Certificate installed"
)
errorCode=$?
if [ $errorCode -ne 0 ]; then
echo "RES:ERROR - $errorCode"
else
echo "RES:OK"
exit $errorCode
fi

Hi,

Thanks for the report, that looks like an unintentional breakage. Give me some time to check it out.

Edit: I'm having a little trouble reproducing the issue. How is the script being invoked? In a terminal, or some headless process?

1 Like

It is invoked using a PHP script. Something like this:

exec("sudo /bin/bash /domainconfigprocess.sh " . $domain . " " . $domain . " " . $subdomain . " " . $email . " 2>&1 &", $output);

OK thanks, I managed to reproduce it by killing PHP while Certbot was still running.

What I think is is happening, is that the Certbot process is outliving the PHP process. The PHP request is getting cancelled in the browser or CLI or whatever, but Certbot keeps running in the background.

This is a problem because the domainconfigprocess.sh's Certbot process is getting its stdout and stderr handles from the PHP process (i.e. the 1 in 2>&1 is PHP's stdout)

If the PHP process dies, then that file descriptor becomes invalid.

As soon as Certbot tries to flush some output to stdout (such as when it reports a new certificate), the result will be the 'Broken Pipe' IO error.

In Certbot 1.16.0, the new certificate reporting does (indirectly) try to flush to stdout, whereas it might not have in 1.15.0.

In my opinion this is a problem with the way the script redirects output, though I will check how the other developers feel about it. You have my apologies anyway.

In the meantime I recommend redirecting the output to a file, rather than to PHP's stdout. That way, even if PHP dies before Certbot does, you won't hit this problem.

4 Likes

The enclosed code [within "("&")"] seems to contain almost the entire script.
Perhaps reducing that to just the line where certbot is being called might help.

What do you mean? To divide the sh script into parts and just one part for the certbot call?

I guess I mean:
Do you really need the "(" & ")" ?
[can you do without them?]

If so, can you reduce the amount of things done within them?

I have finally solved the issue redirecting the output to a file:

exec("sudo /bin/bash /domainconfigprocess.sh " . $domain . " " . $domain . " " . $subdomain . " " . $email . " > /domain.log");

Thanks for your help @_az and @rg305

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.