Repository: certbot/certbot

Issue:
apache install - Unable to finalize checkpoint
after generating the certificates I was unable to make them operational, first by entering the paths in the apache-config files.

running `./letsencrypt-auto install --apache --cert-path /etc/letsencrypt/live/www.eiserneketten.de/cert.pem --key-path /etc/letsencrypt/live/www.eiserneketten.de/privkey.pem` results in the error 
more extensive excerpt from the log, can't paste it here in full

> Unable to finalize checkpoint 
> 2015-10-30 23:26:49,074:DEBUG:letsencrypt.error_handler:Encountered exception:
> Traceback (most recent call last):
> File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/client.py", line 330, in deploy_certificate
>    self.installer.save("Deployed Let's Encrypt Certificate")
> File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt_apache/augeas_configurator.py", line 125, in save
>    raise errors.PluginError(str(err))
> PluginError: Unable to add title
> 
> 2015-10-30 23:26:49,074:DEBUG:letsencrypt.error_handler:Calling registered functions
> 2015-10-30 23:26:49,179:DEBUG:letsencrypt.cli:Exiting abnormally:
> Traceback (most recent call last):
> File "/home/server/.local/share/letsencrypt/bin/letsencrypt", line 11, in <module>
>     sys.exit(main())
> File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/cli.py", line 1131, in main
>  return args.func(args, config, plugins)
> File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/cli.py", line 507, in install
>    args.fullchain_pa2015-10-30 23:26:49,074:DEBUG:letsencrypt.error_handler:Encountered exception:
> Traceback (most recent call last):
> File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt /client.py", line 330, in deploy_certificate
>    self.installer.save("Deployed Let's Encrypt Certificate")
>  File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt_apache /augeas_configurator.py", line 125, in save
>    raise errors.PluginError(str(err))
> PluginError: Unable to add title
> 
> 2015-10-30 23:26:49,074:DEBUG:letsencrypt.error_handler:Calling registered functions
> 2015-10-30 23:26:49,179:DEBUG:letsencrypt.cli:Exiting abnormally:
> Traceback (most recent call last):
>  File "/home/server/.local/share/letsencrypt/bin/letsencrypt", line 11, in <module>
>     sys.exit(main())
>  File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/cli.py",  line 1131, in main
>    return args.func(args, config, plugins)
>  File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/cli.py", line 507, in install
>   args.fullchain_path)
> File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt /client.py", line 330, in deploy_certificate
>    self.installer.save("Deployed Let's Encrypt Certificate")
>  File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt_apache/augeas_configurator.py", line 125, in save
>    raise errors.PluginError(str(err)th)
>  File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/client.py", line 330, in deploy_certificate
>    self.installer.save("Deployed Let's Encrypt Certificate")
> File "/home/server/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt_apache/augeas_configurator.py", line 125, in save
>   raise errors.PluginError(str(err)
> adding title



Discussion:
@charlesay is there any chance you could send us a copy of your apache configuration?

sure, via what channel would be convenient?

actually, just get the apache.conf here https://userpage.fu-berlin.de/danielro/apache.conf.txt and the site-available/...conf here https://userpage.fu-berlin.de/danielro/site.conf.txt

Planning to try to reproduce this.

@charlesay a few questions:
- What OS and version do you have, and what version of augeas is installed?
- Did the resulting Apache config nonetheless work and serve HTTPS correctly (it seems to me probably not, but I'm unsure)
- It looks like the configuration files you sent were from after the run; can you send the ones from before?  You should be able to restore them with `./letsencrypt-auto rollback --agree-dev-preview` (though if you've made manual edits since reporting the bug, I'd save your /etc/apache2 before running the rollback command).

Sorry this command is better:

`./letsencrypt-auto rollback --agree-dev-preview --checkpoints 1000`

(that way it should undo changes from up to 1000 runs of the client)

running the rollback command had this result

> Let's Encrypt hasn't modified your configuration, so rollback isn't available.

the system I am using is a vserver with:

> uname -a 
> Linux Debian-81-jessie-64-minimal 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt11-1+deb8u4 >(2015-09-19) x86_64 GNU/Linux

I am not sure exactly which packages your asking about augeas would refer to on Debian, what I see to be installed are:

> libaugeas0/stable,stable,now 1.2.0-0.2 amd64 [installed]
>  Augeas configuration editing library and API
> 
> augeas-lenses/stable,stable,now 1.2.0-0.2 all [installed,automatic]
>  Set of lenses needed by libaugeas0 to parse config files

I never got it to serve the site over https.

I have exactly the same issue as reported on the [support forum](https://community.letsencrypt.org/t/pluginerror-unable-to-add-title/7110).
I'm running an Ubuntu 14.04 (`Linux e 3.2.65-xenU-19-0e6777a-x86_64 #2 SMP Mon Dec 15 10:33:55 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux`).
The thing is, I got this error on renewal only (worked well on first certificate creation), and for some domains only, it works for the others. Finally, the certificates have been generated, and are perfectly working on the live server.

I got this too, on Ubuntu 14.04 LTS after freshly installing letsencrypt via letsencrypt-auto:

```
root@debesis: ~/letsencrypt [git:master=] # ~mgedmin/.local/share/letsencrypt/bin/letsencrypt --apache --text --noninteractive \
> -m marius@gedmin.as --agree-tos \
> -d debesis.gedmin.as -d projects.gedmin.as -d jenkins.gedmin.as \
> --redirect --keep
2016-01-29 07:11:53,545:ERROR:letsencrypt.reverter:Unable to finalize checkpoint - adding title
Unable to add title

IMPORTANT NOTES:
 - If you lose your account credentials, you can recover through
   e-mails sent to marius@gedmin.as.
 - We were unable to set up enhancement redirect for your server,
   however, we successfully installed your certificate.
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/debesis.gedmin.as/fullchain.pem. Your cert
   will expire on 2016-04-28. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
 - Your account credentials have been saved in your Let's Encrypt
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Let's
   Encrypt so making regular backups of this folder is ideal.

[15s, exited with 1]
```

Despite that error, the certificate was generated and the Apache configuration was changed successfully (all three SSL directives in each of the three vhost config files).  Apache was reloaded and is now serving the new certificates.

```
root@debesis: /etc [git:master>] # ~mgedmin/.local/share/letsencrypt/bin/letsencrypt --version
letsencrypt 0.3.0
```

Do you need any additional information?

Here's an excerpt from /var/log/letsencrypt/letsencrypt.log:

```
2016-01-29 07:11:52,405:INFO:letsencrypt.reporter:Reporting to user: Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/debesis.gedmin.as/fullchain.pem. Your cert will expire on 2016-04-28. To obtain a new version of the certificate in the future, simply run Let's Encrypt again.
2016-01-29 07:11:52,535:INFO:letsencrypt_apache.configurator:Deploying Certificate to VirtualHost /etc/apache2/sites-available/debesis.gedmin.as.conf
2016-01-29 07:11:52,535:DEBUG:letsencrypt_apache.configurator:Apache version is 2.4.7
2016-01-29 07:11:52,563:DEBUG:letsencrypt.reverter:Creating backup of /etc/apache2/sites-available/debesis.gedmin.as.conf
2016-01-29 07:11:52,712:INFO:letsencrypt_apache.configurator:Deploying Certificate to VirtualHost /etc/apache2/sites-available/projects.gedmin.as.conf
2016-01-29 07:11:52,712:DEBUG:letsencrypt_apache.configurator:Apache version is 2.4.7
2016-01-29 07:11:52,725:DEBUG:letsencrypt.reverter:Creating backup of /etc/apache2/sites-available/projects.gedmin.as.conf
2016-01-29 07:11:52,923:INFO:letsencrypt_apache.configurator:Deploying Certificate to VirtualHost /etc/apache2/sites-available/jenkins.gedmin.as.conf
2016-01-29 07:11:52,924:DEBUG:letsencrypt_apache.configurator:Apache version is 2.4.7
2016-01-29 07:11:52,940:DEBUG:letsencrypt.reverter:Creating backup of /etc/apache2/sites-available/jenkins.gedmin.as.conf
2016-01-29 07:11:53,072:DEBUG:letsencrypt_apache.configurator:Fri Jan 29 07:11:52 2016
-- Deployed Let's Encrypt Certificate --
Changed vhost at /etc/apache2/sites-available/debesis.gedmin.as.conf with addresses of *:443
        SSLCertificateFile /etc/letsencrypt/live/debesis.gedmin.as/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/debesis.gedmin.as/privkey.pem
        SSLCertificateChainFile /etc/letsencrypt/live/debesis.gedmin.as/chain.pem
Changed vhost at /etc/apache2/sites-available/projects.gedmin.as.conf with addresses of *:443
        SSLCertificateFile /etc/letsencrypt/live/debesis.gedmin.as/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/debesis.gedmin.as/privkey.pem
        SSLCertificateChainFile /etc/letsencrypt/live/debesis.gedmin.as/chain.pem
Changed vhost at /etc/apache2/sites-available/jenkins.gedmin.as.conf with addresses of *:443
        SSLCertificateFile /etc/letsencrypt/live/debesis.gedmin.as/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/debesis.gedmin.as/privkey.pem
        SSLCertificateChainFile /etc/letsencrypt/live/debesis.gedmin.as/chain.pem

Affected files:
  /etc/apache2/sites-available/debesis.gedmin.as.conf
  /etc/apache2/sites-available/projects.gedmin.as.conf
  /etc/apache2/sites-available/jenkins.gedmin.as.conf


2016-01-29 07:11:53,243:DEBUG:letsencrypt_apache.configurator:Did not find http version of ssl virtual host attempting to create
2016-01-29 07:11:53,333:INFO:letsencrypt_apache.configurator:Created redirect file: le-redirect-debesis.gedmin.as.conf
2016-01-29 07:11:53,353:DEBUG:letsencrypt_apache.configurator:Did not find http version of ssl virtual host attempting to create
2016-01-29 07:11:53,436:INFO:letsencrypt_apache.configurator:Created redirect file: le-redirect-projects.gedmin.as.conf
2016-01-29 07:11:53,449:DEBUG:letsencrypt_apache.configurator:Did not find http version of ssl virtual host attempting to create
2016-01-29 07:11:53,529:INFO:letsencrypt_apache.configurator:Created redirect file: le-redirect-jenkins.gedmin.as.conf
2016-01-29 07:11:53,545:ERROR:letsencrypt.reverter:Unable to finalize checkpoint - adding title
2016-01-29 07:11:53,546:DEBUG:letsencrypt.error_handler:Encountered exception:
Traceback (most recent call last):
  File "/home/mgedmin/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/client.py", line 466, in apply_enhancement
    self.installer.save("Add enhancement %s" % (enhancement))
  File "/home/mgedmin/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt_apache/augeas_configurator.py", line 136, in save
    raise errors.PluginError(str(err))
PluginError: Unable to add title

2016-01-29 07:11:53,546:DEBUG:letsencrypt.error_handler:Calling registered functions
2016-01-29 07:11:53,548:INFO:letsencrypt.reporter:Reporting to user: We were unable to set up enhancement redirect for your server, however, we successfully installed your certificate.
2016-01-29 07:11:53,549:DEBUG:letsencrypt.cli:Exiting abnormally:
Traceback (most recent call last):
  File "/home/mgedmin/.local/share/letsencrypt/bin/letsencrypt", line 11, in <module>
    sys.exit(main())
  File "/home/mgedmin/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/cli.py", line 1454, in main
    return args.func(args, config, plugins)
  File "/home/mgedmin/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/cli.py", line 604, in run
    le_client.enhance_config(domains, config)
  File "/home/mgedmin/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/client.py", line 419, in enhance_config
    self.apply_enhancement(domains, "redirect")
  File "/home/mgedmin/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt/client.py", line 466, in apply_enhancement
    self.installer.save("Add enhancement %s" % (enhancement))
  File "/home/mgedmin/.local/share/letsencrypt/local/lib/python2.7/site-packages/letsencrypt_apache/augeas_configurator.py", line 136, in save
    raise errors.PluginError(str(err))
PluginError: Unable to add title
```

Note:
- it says it created a bunch of le-redirect-_subdomain_.gedmin.as.conf files, but they're nowhere to be seen in /etc
- it says it was "unable to set up enhancement redirect"
- it fails while trying to save configuration changes for "add enhancement %s" ("redirect", I suppose)

So perhaps it fails because there were no changes made that could be saved?

Maybe [`Reverter.finalize_checkpoint`](https://github.com/letsencrypt/letsencrypt/blob/14af8dad5aa9ef72742590950491889362950088/letsencrypt/reverter.py#L471) needs a check like this:

``` python
if not os.path.exists(changes_since_path):
    return
```

BTW I'm not sure why it was unable to add the redirect enhancement.  Here's my /etc/apache2/sites-available/projects.gedmin.as, maybe it'll help reproduce this:

``` apache
<VirtualHost *:80>
  ServerName projects.gedmin.as
  ServerAdmin marius@gedmin.as

  DocumentRoot /var/www/projects.gedmin.as
  ErrorLog /var/log/apache2/projects.gedmin.as/error.log
  CustomLog /var/log/apache2/projects.gedmin.as/access.log combined

  RewriteEngine on

  # Redirect everything to HTTPS, I'll uncomment when something secret/important shows up
##RewriteRule ^/(.*)$ https://projects.gedmin.as/$1 [R=301,L]
</VirtualHost>

<VirtualHost *:443>
  ServerName projects.gedmin.as
  ServerAdmin marius@gedmin.as

  DocumentRoot /var/www/projects.gedmin.as
  ErrorLog /var/log/apache2/projects.gedmin.as/error.log
  CustomLog /var/log/apache2/projects.gedmin.as/access.log combined

  SSLEngine on
  RewriteEngine on

  SSLCertificateFile /etc/letsencrypt/live/debesis.gedmin.as/cert.pem
  SSLCertificateChainFile /etc/letsencrypt/live/debesis.gedmin.as/chain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/debesis.gedmin.as/privkey.pem

</VirtualHost>
```

Possibly related: https://community.letsencrypt.org/t/standard-force-http-to-https-isnt-working/10625


Resolving patch:
diff --git a/letsencrypt/reverter.py b/letsencrypt/reverter.py
--- a/letsencrypt/reverter.py
+++ b/letsencrypt/reverter.py
@@ -481,30 +481,32 @@ def finalize_checkpoint(self, title):
             checkpoint is not able to be finalized.
 
         """
-        # Adds title to self.config.in_progress_dir CHANGES_SINCE
-        # Move self.config.in_progress_dir to Backups directory and
-        # rename the directory as a timestamp
         # Check to make sure an "in progress" directory exists
         if not os.path.isdir(self.config.in_progress_dir):
             return
 
-        changes_since_path = os.path.join(
-            self.config.in_progress_dir, "CHANGES_SINCE")
+        changes_since_path = os.path.join(self.config.in_progress_dir, "CHANGES_SINCE")
+        changes_since_tmp_path = os.path.join(self.config.in_progress_dir, "CHANGES_SINCE.tmp")
 
-        changes_since_tmp_path = os.path.join(
-            self.config.in_progress_dir, "CHANGES_SINCE.tmp")
+        if not os.path.exists(changes_since_path):
+            logger.info("Rollback checkpoint is empty (no changes made?)")
+            with open(self.config.changes_since_path) as f:
+                f.write("No changes\n")
 
+        # Add title to self.config.in_progress_dir CHANGES_SINCE
         try:
             with open(changes_since_tmp_path, "w") as changes_tmp:
                 changes_tmp.write("-- %s --\n" % title)
                 with open(changes_since_path, "r") as changes_orig:
                     changes_tmp.write(changes_orig.read())
 
+        # Move self.config.in_progress_dir to Backups directory
             shutil.move(changes_since_tmp_path, changes_since_path)
         except (IOError, OSError):
             logger.error("Unable to finalize checkpoint - adding title")
             raise errors.ReverterError("Unable to add title")
 
+        # rename the directory as a timestamp
         self._timestamp_progress_dir()
 
     def _timestamp_progress_dir(self):


Test patch: