skip to Main Content

I have server in Ubuntu. On the server I have docker compose installed (v2.29.7). I created the script ssl-renew.sh to periodically renew certbot certs via crontab. Certbot is run through the docker the same way as my nginx, they are in the same docker-compose.yml

I DON’T have "docker-compose" because it gives me this error: DockerException: Error while fetching server API version: HTTPConnection.request(), and the fix is clearly stated here – just move to newest ‘docker compose’ without the dash

The problem is that "docker compose" version just does not work when I try to capture the output.

The failing part of the script:

#!/bin/bash

set -x

DOCKER_COMPOSE_FILE="/services/nginx/docker-compose.yml"

echo "starting renewal"

output=$(/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run --rm certbot renew --force-renewal 2>&1)

echo "docker script has run"

The output is always the same:

+ DOCKER_COMPOSE_FILE=/services/nginx/docker-compose.yml
+ echo 'starting renewal'
starting renewal
++ /usr/bin/docker compose -f /services/nginx/docker-compose.yml run --rm certbot renew --force-renewal

It never reaches echo "docker script has run". The command is not interactive, when I remove the line in script to this one:

#output=$(/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run --rm certbot renew --force-renewal 2>&1)
/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run --rm certbot renew --force-renewal

It is working:

+ DOCKER_COMPOSE_FILE=/services/nginx/docker-compose.yml
+ echo 'starting renewal'
starting renewal
+ /usr/bin/docker compose -f /services/nginx/docker-compose.yml run --rm certbot renew --force-renewal
WARN[0000] /services/nginx/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Renewing an existing certificate for example.com
Failed to renew certificate example.com with error: urn:ietf:params:acme:error:rateLimited :: There were too many requests of a given type :: Error creating new order :: too many certificates (5) already issued for this exact set of domains in the last 168 hours: example.com, retry after 2024-10-02T07:04:55Z: see https://letsencrypt.org/docs/duplicate-certificate-limit/

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
All renewals failed. The following certificates could not be renewed:
  /etc/letsencrypt/live/example.com/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
+ echo 'docker script has run'

Now it run the command and terminal didn’t freeze, but I want to capture the output and send it via API to logging provider. I tried everything in Google and GPT at the moment, nothing helped. Please, if you have any advices – I would appreciate.

2

Answers


  1. Chosen as BEST ANSWER

    The problem was simple I was missing -it argument:

    Not working one: output=$(/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run --rm certbot renew --force-renewal 2>&1)

    Working one: output=$(/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run -it --rm certbot renew --force-renewal 2>&1)


  2. there are few things to note.

    you are using command substitution as follows

    output=$(/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run --rm certbot renew --force-renewal 2>&1)
    

    Bash performs the expansion by executing command in a subshell environment and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.

    Command substitution reassigns the output of a command or even multiple commands; it literally plugs the command output into another context

    in your case, you are assigning the output of the command within $() to a variable name output. if you will print the value of the output variable (e.g. echo "$output"), you would see the output of the internal $() command, e.g. docker compose.

    when I remove the line in script to this one … It is working

    from the output your shared, it does not seem to be "working" since it still does not print

    + echo "docker script has run"
    

    which means that docker compose does not terminate and the script never reaches the echo "docker script has run" line.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search