Nginx: [emerg] "ssl_certificate" directive is duplicate

Hello.

First of all I use debian 8 with nginx. Also if I run:

# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

So everything looks fine. But if I run:

# certbot certonly --cert-name mydomain.example.org
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for mydomain.example.org
[... some more challenges ...]
Generating key (1024 bits): /var/lib/letsencrypt/snakeoil/0086_key.pem
/usr/lib/python2.7/dist-packages/OpenSSL/rand.py:58: UserWarning: implicit cast from 'char *' to a different pointer type: will be forbidden in the future (check that the types are as you expect; use an explicit ffi.cast() if they are correct)
  result_code = _lib.RAND_bytes(result_buffer, num_bytes)
Cleaning up challenges
nginx restart failed:

nginx: [emerg] "ssl_certificate" directive is duplicate in /etc/nginx/sites-enabled/mydomain:25

This is a bit strange, because the server runs just fine.

Here is my /etc/letsencrypt/cli.ini:

rsa-key-size = 4096
email = mail@example.org
agree-tos = True
domains = mydomain.example.org
renew-by-default = False
authenticator = nginx

And here is my /etc/nginx/sites-enabled/mydomain. I have deleted some comments so the line number does not fit, but it does not make sens anyway. The included file includes/ssl_tls contains ssl_certificate but only once.

upstream mydomain_server {
    server unix:/home/ceres/website/sockets/mydomain.sock fail_timeout=10s;
}
server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    include includes/ssl_tls;
    server_name www.mydomain.example.org;
    return 301 https://mydomain.example.org$request_uri;
}
server {
    listen 80;
    listen [::]:80;
    server_name mydomain.example.org;
    return 301 https://mydomain.example.org$request_uri;
}

# SSL/TLS
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name mydomain.example.org;
    include includes/ssl_tls;
    include includes/legacy_redirects;
    location / {
        include proxy_params;
        proxy_pass http://mydomain_server;
        break;
    }
}

So let’s recap the problem:

  • nginx says the config is fine.
  • but somehow certbot does not like it.

What can I do?

Hi @mogoh,

What version of Certbot are you using?

$ certbot --version
certbot 0.10.2

@erica, do you know of any bugs as of 0.10.2 that might produce this particular error in nginx?

@mogoh, would you be willing to try a more recent version via the certbot-auto autodownloader, outside of your OS package manager?

Sure, thanks for your suggestion. I’ll try that tomorrow. (In my timezone it’s 11 pm)

Edit: I have tried the same with certbot-auto and I got the same result. :frowning:

As a guess, I suspect that it’s the include includes/ssl_tls;. Presumably you have an ssl_certificate directive already in that file?

Normally, if you have an ssl_certificate directive directly in a server block, Certbot will detect that and work around it appropriately. However, I wouldn’t be surprised if Certbot fails to properly detect ssl_certificate when it’s nested in an include.

To test this, you could copy the contents of includes/ssl_tls directly into your Nginx config, and remove the include includes/ssl_tls directive, reload Nginx to check that the config parses correctly, then run Certbot again.

2 Likes

OK, I found the problem and a solution, but I still do not understand why it did not worked before. So one mistake is, that I cut out something of my config because I did not thought it was relevant. But it was. Sorry for that. So here is the wrong config with the error included:

upstream mydomain_server {
    server unix:/home/ceres/website/sockets/mydomain.sock fail_timeout=10s;
}
server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    include includes/ssl_tls;
    server_name www.mydomain.example.org;
    return 301 https://mydomain.example.org$request_uri;
}
server {
    listen 80;
    listen [::]:80;
    include includes/ssl_tls;
    server_name www.mydomain.example2.org;
    return 301 https://mydomain.example.org$request_uri;
}
server {
    listen 80;
    listen [::]:80;
    server_name mydomain.example.org;
    return 301 https://mydomain.example.org$request_uri;
}

# SSL/TLS
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name mydomain.example.org;
    include includes/ssl_tls;
    include includes/legacy_redirects;
    location / {
        include proxy_params;
        proxy_pass http://mydomain_server;
        break;
    }
}

Note that there is a part where the server listens only on port 80 but includes the tls config. Certbot did not liked that and of curse it makes no sens. But it is still a bit strange, that nginx can work with it and the certbot can not.

So sorry again for cutting out useful information and thank you for your help! :slight_smile:

Yes, @jsha’s answer is about right. We do detect directives in includes, but we don’t modify them because they’re often shared among server blocks.

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