diff --git a/certbot-apache/certbot_apache/augeas_lens/httpd.aug b/certbot-apache/certbot_apache/augeas_lens/httpd.aug
index 697d5de89..7a5129b56 100644
--- a/certbot-apache/certbot_apache/augeas_lens/httpd.aug
+++ b/certbot-apache/certbot_apache/augeas_lens/httpd.aug
@@ -45,8 +45,8 @@ autoload xfm
let dels (s:string) = del s s
(* deal with continuation lines *)
-let sep_spc = del /([ \t]+|[ \t]*\\\\\r?\n[ \t]*)/ " "
-let sep_osp = del /([ \t]*|[ \t]*\\\\\r?\n[ \t]*)/ ""
+let sep_spc = del /([ \t]+|[ \t]*\\\\\r?\n[ \t]*)+/ " "
+let sep_osp = del /([ \t]*|[ \t]*\\\\\r?\n[ \t]*)*/ ""
let sep_eq = del /[ \t]*=[ \t]*/ "="
let nmtoken = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/
@@ -58,8 +58,8 @@ let empty = Util.empty_dos
let indent = Util.indent
(* borrowed from shellvars.aug *)
-let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ \t\r\n])|\\\\"|\\\\'/
-let char_arg_sec = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'/
+let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ \t\r\n])|\\\\"|\\\\'|\\\\ /
+let char_arg_sec = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'|\\\\ /
let char_arg_wl = /([^\\ '"},\t\r\n]|[^ '"},\t\r\n]+[^\\ '"},\t\r\n])/
let cdot = /\\\\./
diff --git a/certbot-apache/certbot_apache/tests/apache-conf-files/passing/escaped-space-arguments-2735.conf b/certbot-apache/certbot_apache/tests/apache-conf-files/passing/escaped-space-arguments-2735.conf
new file mode 100644
index 000000000..1ea53dfab
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/apache-conf-files/passing/escaped-space-arguments-2735.conf
@@ -0,0 +1,2 @@
+RewriteCond %{HTTP:Content-Disposition} \.php [NC]
+RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTTP/ [NC]
diff --git a/certbot-apache/certbot_apache/tests/apache-conf-files/passing/section-empty-continuations-2731.conf b/certbot-apache/certbot_apache/tests/apache-conf-files/passing/section-empty-continuations-2731.conf
new file mode 100644
index 000000000..3f2f96965
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/apache-conf-files/passing/section-empty-continuations-2731.conf
@@ -0,0 +1,247 @@
+#ATTENTION!
+#
+#DO NOT MODIFY THIS FILE BECAUSE IT WAS GENERATED AUTOMATICALLY,
+#SO ALL YOUR CHANGES WILL BE LOST THE NEXT TIME THE FILE IS GENERATED.
+
+NameVirtualHost 192.168.100.218:80
+NameVirtualHost 10.128.178.192:80
+
+NameVirtualHost 192.168.100.218:443
+NameVirtualHost 10.128.178.192:443
+
+
+ServerName "254020-web1.example.com"
+ServerAdmin "name@example.com"
+
+DocumentRoot "/tmp"
+
+
+ LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" plesklog
+
+
+ LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" plesklog
+
+
+ TraceEnable off
+
+ServerTokens ProductOnly
+
+
+ AllowOverride "All"
+ Options SymLinksIfOwnerMatch
+ Order allow,deny
+ Allow from all
+
+
+php_admin_flag engine off
+
+
+
+php_admin_flag engine off
+
+
+
+
+
+ AllowOverride All
+ Options SymLinksIfOwnerMatch
+ Order allow,deny
+ Allow from all
+
+ php_admin_flag engine off
+
+
+ php_admin_flag engine off
+
+
+
+
+ Header add X-Powered-By PleskLin
+
+
+
+ JkWorkersFile "/etc/httpd/conf/workers.properties"
+ JkLogFile /var/log/httpd/mod_jk.log
+ JkLogLevel info
+
+
+#Include "/etc/httpd/conf/plesk.conf.d/ip_default/*.conf"
+
+
+
+ ServerName "default"
+ UseCanonicalName Off
+ DocumentRoot "/tmp"
+ ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin"
+
+
+
+ SSLEngine off
+
+
+
+ AllowOverride None
+ Options None
+ Order allow,deny
+ Allow from all
+
+
+
+
+
+php_admin_flag engine on
+
+
+
+php_admin_flag engine on
+
+
+
+
+
+
+
+
+
+ ServerName "default-192_168_100_218"
+ UseCanonicalName Off
+ DocumentRoot "/tmp"
+ ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin"
+
+
+ SSLEngine on
+ SSLVerifyClient none
+ #SSLCertificateFile "/usr/local/psa/var/certificates/cert-9MgutN"
+
+ #SSLCACertificateFile "/usr/local/psa/var/certificates/cert-s6Wx3P"
+
+
+ AllowOverride None
+ Options None
+ Order allow,deny
+ Allow from all
+
+
+
+
+
+php_admin_flag engine on
+
+
+
+php_admin_flag engine on
+
+
+
+
+
+
+ ServerName "default-10_128_178_192"
+ UseCanonicalName Off
+ DocumentRoot "/tmp"
+ ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin"
+
+
+ SSLEngine on
+ SSLVerifyClient none
+ #SSLCertificateFile "/usr/local/psa/var/certificates/certxfb6025"
+
+
+
+ AllowOverride None
+ Options None
+ Order allow,deny
+ Allow from all
+
+
+
+
+
+php_admin_flag engine on
+
+
+
+php_admin_flag engine on
+
+
+
+
+
+
+
+
+
+
+ DocumentRoot "/tmp"
+ ServerName lists
+ ServerAlias lists.*
+ UseCanonicalName Off
+
+ ScriptAlias "/mailman/" "/usr/lib/mailman/cgi-bin/"
+
+ Alias "/icons/" "/var/www/icons/"
+ Alias "/pipermail/" "/var/lib/mailman/archives/public/"
+
+
+ SSLEngine off
+
+
+
+
+ Options FollowSymLinks
+ Order allow,deny
+ Allow from all
+
+
+
+
+
+
+ DocumentRoot "/tmp"
+ ServerName lists
+ ServerAlias lists.*
+ UseCanonicalName Off
+
+ ScriptAlias "/mailman/" "/usr/lib/mailman/cgi-bin/"
+
+ Alias "/icons/" "/var/www/icons/"
+ Alias "/pipermail/" "/var/lib/mailman/archives/public/"
+
+ SSLEngine on
+ SSLVerifyClient none
+ #SSLCertificateFile "/usr/local/psa/var/certificates/certxfb6025"
+
+
+
+ Options FollowSymLinks
+ Order allow,deny
+ Allow from all
+
+
+
+
+
+
+ RPAFproxy_ips 192.168.100.218 10.128.178.192
+
+
+ RPAFproxy_ips 192.168.100.218 10.128.178.192
+
diff --git a/certbot-apache/certbot_apache/tests/tls_sni_01_test.py b/certbot-apache/certbot_apache/tests/tls_sni_01_test.py
index 17ef92004..aa6a2a09c 100644
--- a/certbot-apache/certbot_apache/tests/tls_sni_01_test.py
+++ b/certbot-apache/certbot_apache/tests/tls_sni_01_test.py
@@ -4,6 +4,7 @@ import shutil
import mock
+from certbot import errors
from certbot.plugins import common_test
from certbot_apache import obj
@@ -137,6 +138,16 @@ class TlsSniPerformTest(util.ApacheTest):
set([obj.Addr.fromstring("*:443")]),
self.sni._get_addrs(self.achalls[0]))
+ def test_get_addrs_no_vhost_found(self):
+ self.sni.configurator.choose_vhost = mock.Mock(
+ side_effect=errors.MissingCommandlineFlag(
+ "Failed to run Apache plugin non-interactively"))
+
+ # pylint: disable=protected-access
+ self.assertEqual(
+ set([obj.Addr.fromstring("*:443")]),
+ self.sni._get_addrs(self.achalls[0]))
+
if __name__ == "__main__":
unittest.main() # pragma: no cover
diff --git a/certbot-apache/certbot_apache/tls_sni_01.py b/certbot-apache/certbot_apache/tls_sni_01.py
index 1236c2eb9..f14f7be0f 100644
--- a/certbot-apache/certbot_apache/tls_sni_01.py
+++ b/certbot-apache/certbot_apache/tls_sni_01.py
@@ -4,6 +4,7 @@ import os
import logging
from certbot.plugins import common
+from certbot.errors import PluginError, MissingCommandlineFlag
from certbot_apache import obj
from certbot_apache import parser
@@ -116,12 +117,21 @@ class ApacheTlsSni01(common.TLSSNI01):
def _get_addrs(self, achall):
"""Return the Apache addresses needed for TLS-SNI-01."""
- vhost = self.configurator.choose_vhost(achall.domain, temp=True)
# TODO: Checkout _default_ rules.
addrs = set()
default_addr = obj.Addr(("*", str(
self.configurator.config.tls_sni_01_port)))
+ try:
+ vhost = self.configurator.choose_vhost(achall.domain, temp=True)
+ except (PluginError, MissingCommandlineFlag):
+ # We couldn't find the virtualhost for this domain, possibly
+ # because it's a new vhost that's not configured yet (GH #677),
+ # or perhaps because there were multiple sections
+ # in the config file (GH #1042). See also GH #2600.
+ addrs.add(default_addr)
+ return addrs
+
for addr in vhost.addrs:
if "_default_" == addr.get_addr():
addrs.add(default_addr)
diff --git a/certbot/plugins/standalone.py b/certbot/plugins/standalone.py
index a3bb1d8f0..8e1cb72a4 100644
--- a/certbot/plugins/standalone.py
+++ b/certbot/plugins/standalone.py
@@ -120,6 +120,14 @@ def supported_challenges_validator(data):
"""
challs = data.split(",")
+
+ # tls-sni-01 was dvsni during private beta
+ if "dvsni" in challs:
+ logger.info("Updating legacy standalone_supported_challenges value")
+ challs = [challenges.TLSSNI01.typ if chall == "dvsni" else chall
+ for chall in challs]
+ data = ",".join(challs)
+
unrecognized = [name for name in challs
if name not in challenges.Challenge.TYPES]
if unrecognized:
diff --git a/certbot/plugins/standalone_test.py b/certbot/plugins/standalone_test.py
index 9f5b14591..eb6631732 100644
--- a/certbot/plugins/standalone_test.py
+++ b/certbot/plugins/standalone_test.py
@@ -85,6 +85,11 @@ class SupportedChallengesValidatorTest(unittest.TestCase):
def test_not_subset(self):
self.assertRaises(argparse.ArgumentTypeError, self._call, "dns")
+ def test_dvsni(self):
+ self.assertEqual("tls-sni-01", self._call("dvsni"))
+ self.assertEqual("http-01,tls-sni-01", self._call("http-01,dvsni"))
+ self.assertEqual("tls-sni-01,http-01", self._call("dvsni,http-01"))
+
class AuthenticatorTest(unittest.TestCase):
"""Tests for certbot.plugins.standalone.Authenticator."""
diff --git a/docs/using.rst b/docs/using.rst
index f215b335b..997134de5 100644
--- a/docs/using.rst
+++ b/docs/using.rst
@@ -215,12 +215,25 @@ expire in less than 30 days. The same plugin and options that were used
at the time the certificate was originally issued will be used for the
renewal attempt, unless you specify other plugins or options.
+You can also specify hooks to be run before or after a certificate is
+renewed. For example, if you want to use the standalone_ plugin to renew
+your certificates, you may want to use a command like
+
+``certbot renew --standalone --pre-hook "service nginx stop" --post-hook "service nginx start"``
+
+This will stop Nginx so standalone can bind to the necessary ports and
+then restart Nginx after the plugin is finished. The hooks will only be
+run if a certificate is due for renewal, so you can run this command
+frequently without unnecessarily stopping your webserver. More
+information about renewal hooks can be found by running
+``certbot --help renew``.
+
If you're sure that this command executes successfully without human
intervention, you can add the command to ``crontab`` (since certificates
are only renewed when they're determined to be near expiry, the command
-can run on a regular basis, like every week or every day); note that
-the current version provides detailed output describing either renewal
-success or failure.
+can run on a regular basis, like every week or every day). In that case,
+you are likely to want to use the ``-q`` or ``--quiet`` quiet flag to
+silence all output except errors.
The ``--force-renew`` flag may be helpful for automating renewal;
it causes the expiration time of the certificate(s) to be ignored when
@@ -241,9 +254,11 @@ renewals of that certificate.
An alternative form that provides for more fine-grained control over the
renewal process (while renewing specified certificates one at a time),
is ``certbot certonly`` with the complete set of subject domains of
-a specific certificate specified via `-d` flags, like
+a specific certificate specified via `-d` flags. You may also want to
+include the ``-n`` or ``--noninteractive`` flag to prevent blocking on
+user input (which is useful when running the command from cron).
-``certbot certonly -d example.com -d www.example.com``
+``certbot certonly -n -d example.com -d www.example.com``
(All of the domains covered by the certificate must be specified in
this case in order to renew and replace the old certificate rather
@@ -437,7 +452,7 @@ Operating System Packages
**Debian**
-If you run Debian Stretch or Debian Sid, you can install letsencrypt packages.
+If you run Debian Stretch or Debian Sid, you can install certbot packages.
.. code-block:: shell
diff --git a/tests/travis-integration.sh b/tests/travis-integration.sh
index 1b51f0980..159a2ef80 100755
--- a/tests/travis-integration.sh
+++ b/tests/travis-integration.sh
@@ -6,14 +6,14 @@ set -o errexit
source .tox/$TOXENV/bin/activate
-export LETSENCRYPT_PATH=`pwd`
+export CERTBOT_PATH=`pwd`
cd $GOPATH/src/github.com/letsencrypt/boulder/
# boulder's integration-test.py has code that knows to start and wait for the
# boulder processes to start reliably and then will run the certbot
-# boulder-interation.sh on its own. The --letsencrypt flag says to run only the
+# boulder-interation.sh on its own. The --certbot flag says to run only the
# certbot tests (instead of any other client tests it might run). We're
# going to want to define a more robust interaction point between the boulder
# and certbot tests, but that will be better built off of this.
-python test/integration-test.py --letsencrypt
+python test/integration-test.py --certbot