Can't renew certs with multiple vhosts

I just tried to renew the certs for my sites and I can getting the following error " We were unable to find a vhost with a ServerName…" This used to work just fine.

I do have several vhosts in 000-default-le-ssl.conf and I’ve renewed before. I have several sites running on the sever, all with the same base name.

site1.example.com
site2.example.com
site3.example.com

certbot-auto certonly --apache --renew-by-default
-d example.com -d www.example.com
-d site1.example.com
-d site2.example.com
-d site3.example.com

I had one certificate that included all these, but this no longer seems to work. All these sites need to run on the same server.

If letsencrypt no longer works using multi vhosts, how am I supposed to do this? It was simple to set up and work perfectly for 6 months (and 1 renew), so I’m not sure why this isn’t supported. Do I need different certs for each site? If so, how do I set that up in apache?

Thanks

The apache plugin does not support multiple vhosts in the same file. However, following a “one vhost per file” structure will work.

If you currently have 000-default-le-ssl.conf with three <VirtualHost> tags, I would recommend creating one file per domain, i.e. something like site1.example.com-le-ssl.conf, site2.example.com-le-ssl.conf and site3.example.com-le-ssl.conf. If you also have a file with vhosts listening on port 80, you’ll have to do the same for those.

I would recommend looking into the new certbot renew command as opposed to renewing via --renew-by-default. The documentation can be found here. That being said, it might still be a good idea to use the certonly command once for your current renewal just in case anything in the renewal configuration is going to conflict with the changes you’re going to make to your vhost structure.

Worth mentioning: Your apache configuration looks like it might have been set up with the apache installer previously (i.e. SSL was configured automatically in apache, at least judging by the ...-le-ssl.conf file name), while your current command uses certonly, which does not do that. If you’re adding new domains, that means you’ll be in charge of configuring new vhosts for SSL, reloading apache after renewal, etc.

With regards to renewal working previously, my only possible explanation would be that you were previously using a version that did not include this commit which landed on January 10th, 2015. I’m not quite sure about this, but my understanding is that multiple vhosts per file was never supported by the installer part of the apache plugin (the bit that automatically configures your apache for SSL), but it was initially supported by the apache authenticator (responsible for solving the domain ownership challenge).

This worked perfectly, thank you so much!

I had this issue as well. Creating a separate vhost for each site isn’t a good option. I have several sites, with several subdomains each, which would cause multiplicative growth of vhost files. For example, 5 sites with 5 subdomains each would lead to 25 separate configurations, making things unmanageable. Furthermore, I use defines and macros, so one simple vhost file handles everything. Breaking this structure is a deal-breaker. Further-furthermore, I had set letsencrypt to generate certonly, so I don’t understand why it’s searching through the vhost files at all. Doesn’t it have all the information it needs from the existing certificates and renewal files?

As a work-around, I created a new vhost 999-dummy.conf containing the following:

# Dummy for letsencrypt
<VirtualHost *:999>
        ServerName dummy.com
        ServerAlias *
</VirtualHost>

My server isn’t actually listening in on port 999, but this seems to be sufficient to let letsencrypt pass its vhost search and actually renew the certificates.

Just to be clear: this is not a permanent design decision, assuming one file == one vhost kept things a bit simpler for the first implementation, but that's not a permanent limitation (and it's actually been worked on quite recently - not sure if it'll be ready in time for the next release, but there's some progress).

I don't either, that shouldn't happen, unless you use certonly with --authenticator apache or something like that, in which case the plugin might need to understand the config to work properly - not sure. Mind providing the full command you ran, and maybe log files from /var/log/letsencrypt if you still have those?

certonly is for adding new certificates (or replacing existing ones) based on the arguments you provide. It doesn't use any of the information from old certificates or renewal config files (other than to decide whether it ought to overwrite an existing file or create a new directory in /live). Renewal configuration would only be relevant for the renew subcommand.

I'm on Ubuntu 16.04, using the cerbot packages. To generate the certificates, I used:

$ sudo letsencrypt certonly -d mydomain.ca -d www.mydomain.ca -d mail.mydomain.ca

It asks me to select my vhost file from a list (but why? It doesn't seem to matter which I choose). I select template.inc which has some templated code. Everything then proceeds successfully. To test the renewal, I force:

$ sudo letsencrypt renew --force-renewal

The error message I get when trying to renew:

2016-07-28 17:37:39,182:WARNING:letsencrypt.cli:Attempting to renew cert from /etc/letsencrypt/renewal/mydomain.ca.conf produced an unexpected error: Failed to run Apache plugin non-interactively
Missing command line flag or config entry for this setting:
We were unable to find a vhost with a ServerName or Address of www.mydomain.com.
Which virtual host would you like to choose?
Choices: ['001-otherdomain.conf              | otherdomain              |       | Enabled', '000-anotherdomain.conf             | anotherdomain             |       | Enabled', 'template.inc                   | Multiple Names        | HTTPS |        ']
(The best solution is to add ServerName or ServerAlias entries to the VirtualHost directives of your apache configuration files.). Skipping.

I don't have the original log files, but the process is repeatable. Unfortunately this site won't let me upload anything because I'm a "new user". Trying again for a single domain, the stack traces are

2016-07-29 06:47:00,535:INFO:letsencrypt.auth_handler:Performing the following challenges:
2016-07-29 06:47:00,535:INFO:letsencrypt.auth_handler:tls-sni-01 challenge for www.mydomain.ca
2016-07-29 06:47:00,763:DEBUG:letsencrypt.error_handler:Encountered exception:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/letsencrypt/auth_handler.py", line 115, in _solve_challenges
    dv_resp = self.dv_auth.perform(self.dv_c)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/configurator.py", line 1549, in perform
    sni_response = chall_doer.perform()
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/tls_sni_01.py", line 78, in perform
    addrs = self._mod_config()
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/tls_sni_01.py", line 100, in _mod_config
    achall_addrs = self._get_addrs(achall)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/tls_sni_01.py", line 119, in _get_addrs
    vhost = self.configurator.choose_vhost(achall.domain, temp=True)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/configurator.py", line 314, in choose_vhost
    return self._choose_vhost_from_list(target_name, temp)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/configurator.py", line 318, in _choose_vhost_from_list
    vhost = display_ops.select_vhost(target_name, self.vhosts)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/display_ops.py", line 29, in select_vhost
    code, tag = _vhost_menu(domain, vhosts)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/display_ops.py", line 93, in _vhost_menu
    raise errors.MissingCommandlineFlag(msg)
MissingCommandlineFlag: Failed to run Apache plugin non-interactively
Missing command line flag or config entry for this setting:
We were unable to find a vhost with a ServerName or Address of www.mydomain.ca.
Which virtual host would you like to choose?
Choices: ['001-mycomputer.conf              | mycomputer              |       | Enabled', '000-localhost.conf             | localhost             |       | Enabled', 'template.inc                   | Multiple Names        | HTTPS |        ']
(The best solution is to add ServerName or ServerAlias entries to the VirtualHost directives of your apache configuration files.)

2016-07-29 06:47:00,763:DEBUG:letsencrypt.error_handler:Calling registered functions
2016-07-29 06:47:00,764:INFO:letsencrypt.auth_handler:Cleaning up challenges
2016-07-29 06:47:00,973:WARNING:letsencrypt.cli:Attempting to renew cert from /etc/letsencrypt/renewal/www.mydomain.ca.conf produced an unexpected error: Failed to run Apache plugin non-interactively
Missing command line flag or config entry for this setting:
We were unable to find a vhost with a ServerName or Address of www.mydomain.ca.
Which virtual host would you like to choose?
Choices: ['001-mycomputer.conf              | mycomputer              |       | Enabled', '000-localhost.conf             | localhost             |       | Enabled', 'template.inc                   | Multiple Names        | HTTPS |        ']
(The best solution is to add ServerName or ServerAlias entries to the VirtualHost directives of your apache configuration files.). Skipping.
2016-07-29 06:47:00,973:DEBUG:letsencrypt.cli:Traceback was:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/letsencrypt/cli.py", line 1017, in renew
    obtain_cert(lineage_config, plugins, renewal_candidate)
  File "/usr/lib/python2.7/dist-packages/letsencrypt/cli.py", line 706, in obtain_cert
    _, action = _auth_from_domains(le_client, config, domains, lineage)
  File "/usr/lib/python2.7/dist-packages/letsencrypt/cli.py", line 457, in _auth_from_domains
    new_certr, new_chain, new_key, _ = le_client.obtain_certificate(domains)
  File "/usr/lib/python2.7/dist-packages/letsencrypt/client.py", line 252, in obtain_certificate
    return self.obtain_certificate_from_csr(domains, csr) + (key, csr)
  File "/usr/lib/python2.7/dist-packages/letsencrypt/client.py", line 225, in obtain_certificate_from_csr
    authzr = self.auth_handler.get_authorizations(domains)
  File "/usr/lib/python2.7/dist-packages/letsencrypt/auth_handler.py", line 80, in get_authorizations
    cont_resp, dv_resp = self._solve_challenges()
  File "/usr/lib/python2.7/dist-packages/letsencrypt/auth_handler.py", line 115, in _solve_challenges
    dv_resp = self.dv_auth.perform(self.dv_c)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/configurator.py", line 1549, in perform
    sni_response = chall_doer.perform()
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/tls_sni_01.py", line 78, in perform
    addrs = self._mod_config()
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/tls_sni_01.py", line 100, in _mod_config
    achall_addrs = self._get_addrs(achall)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/tls_sni_01.py", line 119, in _get_addrs
    vhost = self.configurator.choose_vhost(achall.domain, temp=True)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/configurator.py", line 314, in choose_vhost
    return self._choose_vhost_from_list(target_name, temp)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/configurator.py", line 318, in _choose_vhost_from_list
    vhost = display_ops.select_vhost(target_name, self.vhosts)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/display_ops.py", line 29, in select_vhost
    code, tag = _vhost_menu(domain, vhosts)
  File "/usr/lib/python2.7/dist-packages/letsencrypt_apache/display_ops.py", line 93, in _vhost_menu
    raise errors.MissingCommandlineFlag(msg)
MissingCommandlineFlag: Failed to run Apache plugin non-interactively
Missing command line flag or config entry for this setting:
We were unable to find a vhost with a ServerName or Address of www.mydomain.ca.
Which virtual host would you like to choose?
Choices: ['001-mycomputer.conf              | mycomputer              |       | Enabled', '000-localhost.conf             | localhost             |       | Enabled', 'template.inc                   | Multiple Names        | HTTPS |        ']
(The best solution is to add ServerName or ServerAlias entries to the VirtualHost directives of your apache configuration files.)

2016-07-29 06:47:00,974:DEBUG:letsencrypt.cli:Exiting abnormally:
Traceback (most recent call last):
  File "/usr/bin/letsencrypt", line 9, in <module>
    load_entry_point('letsencrypt==0.4.1', 'console_scripts', 'letsencrypt')()
  File "/usr/lib/python2.7/dist-packages/letsencrypt/cli.py", line 1986, in main
    return config.func(config, plugins)
  File "/usr/lib/python2.7/dist-packages/letsencrypt/cli.py", line 1034, in renew
    len(renew_failures), len(parse_failures)))
Error: 1 renew failure(s), 0 parse failure(s)

If you want the full content, I can send that too.

Yes, I'm only talking about the renew command here. For the original certificate generation, it's a bit of an inconvenience to have to select an arbitrary vhost, but otherwise it works. This is something we only have to deal with once. For the renewal, however, the command just fails and exits, unless I enable my "dummy" catch-all vhost above.

Do you happen to have a /etc/letsencrypt/cli.ini file that maybe includes something telling the client to use the apache plugin?

Can you try explicitly providing the plugin you want to use? Something like:

sudo letsencrypt certonly --webroot -w /var/www/html -d mydomain.ca -d www.mydomain.ca -d mail.mydomain.ca

If you want to use the webroot plugin.

I do not have a cli.ini file, but when running for the first time, letsencrypt asked what I wanted to use to verify the domains, and I selected apache, so in the end it did use the apache plugin. It must have stored those settings somewhere, because when I try it again with a new domain, it defaults to apache right away without asking.

There’s no way my previously mentioned “dummy” vhost helped the apache plugin do anything useful. All it did was let it pass the virtual-host lookup. The letsencrypt scripts were then happy to continue on their merry way. I’m not sure how it verifies my identity, but I’m pretty sure it never found my DocumentRoot folders for each of the domains, since the dummy vhost doesn’t supply any. If it did actually find the correct DocumentRoot folders, then the dummy host shouldn’t have been necessary in the first place, and letsencrypt would always work correctly with multiple vhosts in a single file. Either way, there is something buggy going on.

Everything does work fine if I use the --webroot plugin. It was a bit of a hassle to get to work, since I have a set of mod_rewrite rules, and had to add exceptions so it wouldn’t redirect .well-known/acme-challenge/.*. I also had to explicitly grant access to the folder, or else I got 403 errors.

The validation method used by the apache plugin works a bit differently than the webroot plugin - it basically adds another temporary vhost with a “fake” SNI domain with a specially-crafted (temporary) certificate to validate ownership, so it would not need to determine the correct DocumentRoot to work.

You’re probably right that the apache plugin when used as an authenticator plugin (i.e. with certonly) probably (though I might be forgetting about some aspect) wouldn’t need to parse your vhosts, that would only be necessary for the installer plugin - this might just be another case of an implementation shortcut. Anyway, probably not worth fixing separately given that multi-vhost-per-file is being worked on and would fix this as well.

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