23
README.rst
23
README.rst
@@ -39,3 +39,26 @@ By default, the following components are installed:
|
||||
|
||||
If you want more information about the installation process, add the
|
||||
``--debug`` option to your command line.
|
||||
|
||||
Let's Encrypt certificate
|
||||
-------------------------
|
||||
|
||||
.. warning::
|
||||
|
||||
Please note this option requires the hostname you're using to be
|
||||
valid (ie. it can be resolved with a DNS query) and to match the
|
||||
server you're installing Modoboa on.
|
||||
|
||||
If you want to generate a valid certificate using `Let's Encrypt
|
||||
<https://letsencrypt.org/>`_, edit the ``installer.cfg`` file and
|
||||
modify the following settings::
|
||||
|
||||
[certificate]
|
||||
generate = true
|
||||
type = letsencrypt
|
||||
|
||||
[letsencrypt]
|
||||
email = admin@example.com
|
||||
|
||||
Change the ``email`` setting to a valid value since it will be used
|
||||
for account recovery.
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
[certificate]
|
||||
generate = true
|
||||
# Choose between self-signed or letsencrypt
|
||||
type = letsencrypt
|
||||
|
||||
[letsencrypt]
|
||||
email = admin@example.com
|
||||
|
||||
[database]
|
||||
# Select database engine : postgres or mysql
|
||||
engine = postgres
|
||||
|
||||
@@ -11,7 +11,27 @@ class CertificateBackend(object):
|
||||
def __init__(self, config):
|
||||
"""Set path to certificates."""
|
||||
self.config = config
|
||||
if not config.has_option("general", "tls_key_file"):
|
||||
|
||||
def overwrite_existing_certificate(self):
|
||||
"""Check if certificate already exists."""
|
||||
if os.path.exists(self.config.get("general", "tls_key_file")):
|
||||
if not self.config.getboolean("general", "force"):
|
||||
answer = utils.user_input(
|
||||
"Overwrite the existing SSL certificate? (y/N) ")
|
||||
if not answer.lower().startswith("y"):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class SelfSignedCertificate(CertificateBackend):
|
||||
"""Create a self signed certificate."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Sanity checks."""
|
||||
super(SelfSignedCertificate, self).__init__(*args, **kwargs)
|
||||
if self.config.has_option("general", "tls_key_file"):
|
||||
# Compatibility
|
||||
return
|
||||
for base_dir in ["/etc/pki/tls", "/etc/ssl"]:
|
||||
if os.path.exists(base_dir):
|
||||
self.config.set(
|
||||
@@ -22,20 +42,10 @@ class CertificateBackend(object):
|
||||
"{}/certs/%(hostname)s.cert".format(base_dir))
|
||||
return
|
||||
raise RuntimeError("Cannot find a directory to store certificate")
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
class SelfSignedCertificate(CertificateBackend):
|
||||
"""Create a self signed certificate."""
|
||||
|
||||
def create(self):
|
||||
"""Create a certificate."""
|
||||
if os.path.exists(self.config.get("general", "tls_key_file")):
|
||||
if not self.config.getboolean("general", "force"):
|
||||
answer = utils.user_input(
|
||||
"Overwrite the existing SSL certificate? (y/N) ")
|
||||
if not answer.lower().startswith("y"):
|
||||
if not self.overwrite_existing_certificate():
|
||||
return
|
||||
utils.printcolor(
|
||||
"Generating new self-signed certificate", utils.YELLOW)
|
||||
@@ -48,6 +58,40 @@ class SelfSignedCertificate(CertificateBackend):
|
||||
)
|
||||
|
||||
|
||||
class LetsEncryptCertificate(CertificateBackend):
|
||||
"""Create a certificate using letsencrypt."""
|
||||
|
||||
def create(self):
|
||||
"""Create a certificate."""
|
||||
utils.printcolor(
|
||||
"Generating new certificate using letsencrypt", utils.YELLOW)
|
||||
hostname = self.config.get("general", "hostname")
|
||||
utils.exec_cmd(
|
||||
"wget https://dl.eff.org/certbot-auto; chmod a+x certbot-auto",
|
||||
cwd="/opt")
|
||||
webroot = os.path.join(
|
||||
self.config.get("modoboa", "instance_path"),
|
||||
"sitestatic/.well-known")
|
||||
utils.exec_cmd(
|
||||
"/opt/certbot-auto certonly -n --standalone -d {} "
|
||||
"-m {} --agree-tos".format(
|
||||
webroot, hostname, self.config.get("letsencrypt", "email")))
|
||||
self.config.set("general", "tls_cert_file", (
|
||||
"/etc/letsencrypt/live/{}/fullchain.pem".format(hostname)))
|
||||
self.config.set("general", "tls_key_file", (
|
||||
"/etc/letsencrypt/live/{}/privkey.pem".format(hostname)))
|
||||
with open("/etc/cron.d/letsencrypt", "w") as fp:
|
||||
fp.write("0 */12 * * * root /opt/certbot-auto renew "
|
||||
"--quiet --no-self-upgrade && "
|
||||
"service nginx reload && "
|
||||
"service postfix reload && "
|
||||
"service dovecot reload")
|
||||
|
||||
|
||||
def get_backend(config):
|
||||
"""Return the appropriate backend."""
|
||||
if not config.getboolean("certificate", "generate"):
|
||||
return None
|
||||
if config.get("certificate", "type") == "letsencrypt":
|
||||
return LetsEncryptCertificate(config)
|
||||
return SelfSignedCertificate(config)
|
||||
|
||||
7
run.py
7
run.py
@@ -39,7 +39,8 @@ def main():
|
||||
.format(args.hostname), utils.BLUE)
|
||||
components = []
|
||||
for section in config.sections():
|
||||
if section in ["general", "database", "mysql", "postgres"]:
|
||||
if section in ["general", "database", "mysql", "postgres",
|
||||
"certificate", "letsencrypt"]:
|
||||
continue
|
||||
if (config.has_option(section, "enabled") and
|
||||
not config.getboolean(section, "enabled")):
|
||||
@@ -56,7 +57,9 @@ def main():
|
||||
"and come back later ;)", utils.BLUE)
|
||||
utils.printcolor("Starting...", utils.GREEN)
|
||||
package.backend.install("sudo")
|
||||
ssl.get_backend(config).create()
|
||||
ssl_backend = ssl.get_backend(config)
|
||||
if ssl_backend:
|
||||
ssl_backend.create()
|
||||
scripts.install("modoboa", config)
|
||||
scripts.install("postfix", config)
|
||||
scripts.install("amavis", config)
|
||||
|
||||
Reference in New Issue
Block a user