Working setup for CentOS.

This commit is contained in:
Antoine Nguyen
2016-06-01 15:30:59 +02:00
parent 451c3b4695
commit 89cdc314ea
15 changed files with 129 additions and 25 deletions

View File

@@ -1,7 +1,3 @@
[general]
tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
[database]
# Select database engine : postgres or mysql
engine = postgres

View File

@@ -25,6 +25,12 @@ class Amavis(base.Installer):
return "/etc/amavisd"
return "/etc/amavis"
def get_daemon_name(self):
"""Return appropriate daemon name."""
if package.backend.FORMAT == "rpm":
return "amavisd"
return "amavis"
def get_config_files(self):
"""Return appropriate config files."""
if package.backend.FORMAT == "deb":

View File

@@ -12,7 +12,6 @@ class Clamav(base.Installer):
"""ClamAV installer."""
appname = "clamav"
daemon_name = "clamav-daemon"
packages = {
"deb": ["clamav-daemon"],
"rpm": [
@@ -55,17 +54,23 @@ class Clamav(base.Installer):
user = "clamupdate"
utils.exec_cmd(
"perl -pi -e 's/^Example/#Example/' /etc/freshclam.conf")
utils.exec_cmd(
"""cat <<EOM >> /usr/lib/systemd/system/clamd@.service
# Check if not present before
path = "/usr/lib/systemd/system/clamd@.service"
code, output = utils.exec_cmd(
"grep 'WantedBy=multi-user.target' {}".format(path))
if code:
utils.exec_cmd(
"""cat <<EOM >> {}
[Install]
WantedBy=multi-user.target
EOM
""")
""".format(path))
if utils.dist_name == "ubuntu":
if utils.dist_name() == "ubuntu":
# Stop freshclam daemon to allow manual download
utils.exec_cmd("service clamav-freshclam stop")
utils.exec_cmd("freshclam", sudo_user=user)
utils.exec_cmd("service clamav-freshclam start")
else:
utils.exec_cmd("freshclam", sudo_user=user)
utils.exec_cmd("freshclam", sudo_user=user, login=False)

View File

@@ -52,6 +52,14 @@ class Dovecot(base.Installer):
"""Additional variables."""
context = super(Dovecot, self).get_template_context()
pw = pwd.getpwnam(self.user)
if "centos" in utils.dist_name():
protocols = "protocols = imap lmtp sieve"
extra_protocols = self.config.get("dovecot", "extra_protocols")
if extra_protocols:
protocols += " {}".format(extra_protocols)
else:
# Protocols are automatically guessed on debian/ubuntu
protocols = ""
context.update({
"db_driver": self.db_driver,
"mailboxes_owner_uid": pw[2],
@@ -59,6 +67,7 @@ class Dovecot(base.Installer):
"modoboa_dbname": self.config.get("modoboa", "dbname"),
"modoboa_dbuser": self.config.get("modoboa", "dbuser"),
"modoboa_dbpassword": self.config.get("modoboa", "dbpassword"),
"protocols": protocols
})
return context

View File

@@ -18,6 +18,7 @@
# Enable installed protocols
!include_try /usr/share/dovecot/protocols.d/*.protocol
%protocols
# A comma separated list of IPs or hosts where to listen in for connections.
# "*" listens in all IPv4 interfaces, "::" listens in all IPv6 interfaces.

View File

@@ -6,8 +6,9 @@ home = %modoboa_venv_path
chdir = %modoboa_instance_path
module = instance.wsgi:application
master = true
harakiri = 60
processes = %nb_processes
vhost = true
no-default-app = true
socket = %uwsgi_socket_path
chmod-socket = 660
vacuum = true

View File

@@ -108,7 +108,7 @@ class Modoboa(base.Installer):
context.update({
"dovecot_mailboxes_owner": (
self.config.get("dovecot", "mailboxes_owner")),
"radicale_enabled": "#" if "modoboa-radicale" in extensions else ""
"radicale_enabled": "" if "modoboa-radicale" in extensions else "#"
})
return context
@@ -128,6 +128,9 @@ class Modoboa(base.Installer):
"modoboa_stats.RRD_ROOTDIR": rrd_root_dir,
"modoboa_pdfcredentials.STORAGE_DIR": pdf_storage_dir,
}
for path in ["/var/log/maillog", "/var/log/mail.log"]:
if os.path.exists(path):
settings["modoboa_stats.LOGFILE"] = path
for name, value in settings.items():
query = (

View File

@@ -44,11 +44,12 @@ class Nginx(base.Installer):
if os.path.exists(link):
return
os.symlink(dst, link)
group = "www-data"
group = self.config.get("modoboa", "user")
user = "www-data"
else:
dst = os.path.join(
self.config_dir, "conf.d", "{}.conf".format(hostname))
utils.copy_from_template(src, dst, context)
group = "nginx"
system.add_user_to_group(
group, self.config.get("modoboa", "user"))
group = "uwsgi"
user = "nginx"
system.add_user_to_group(user, group)

View File

@@ -1,5 +1,9 @@
"""Postfix related tools."""
try:
import configparser
except ImportError:
import ConfigParser as configparser
import os
from .. import package
@@ -29,6 +33,17 @@ class Postfix(base.Installer):
def install_packages(self):
"""Preconfigure postfix package installation."""
if "centos" in utils.dist_name():
config = configparser.SafeConfigParser()
with open("/etc/yum.repos.d/CentOS-Base.repo") as fp:
config.readfp(fp)
config.set("centosplus", "enabled", "1")
config.set("centosplus", "includepkgs", "postfix-*")
config.set("base", "exclude", "postfix-*")
config.set("updates", "exclude", "postfix-*")
with open("/etc/yum.repos.d/CentOS-Base.repo", "w") as fp:
config.write(fp)
package.backend.preconfigure(
"postfix", "main_mailer_type", "select", "No configuration")
super(Postfix, self).install_packages()
@@ -71,6 +86,16 @@ class Postfix(base.Installer):
" ".join(extensions), db_url, self.config_dir))
utils.exec_cmd(cmd)
# Check chroot directory
chroot_dir = "/var/spool/postfix/etc"
chroot_files = ["services", "resolv.conf"]
if not os.path.exists(chroot_dir):
os.mkdir(chroot_dir)
for f in chroot_files:
path = os.path.join(chroot_dir, f)
if not os.path.exists(path):
utils.copy_file(os.path.join("/etc", f), path)
# Generate EDH parameters
if not os.path.exists("{}/dh2048.pem".format(self.config_dir)):
cmd = "openssl dhparam -out dh2048.pem 2048"

View File

@@ -36,7 +36,7 @@ class Razor(base.Installer):
utils.copy_file(
os.path.join(path, "razor-agent.conf"), self.config_dir)
utils.exec_cmd("razor-admin -home {} -discover".format(path),
sudo_user=user)
sudo_user=user, login=False)
utils.exec_cmd("razor-admin -home {} -register".format(path),
sudo_user=user)
sudo_user=user, login=False)
# FIXME: move log file to /var/log ?

View File

@@ -55,5 +55,7 @@ class Spamassassin(base.Installer):
def post_run(self):
"""Additional tasks."""
utils.exec_cmd(
"pyzor discover", sudo_user=self.config.get("amavis", "user"))
"pyzor discover", sudo_user=self.config.get("amavis", "user"),
login=False
)
install("razor", self.config)

View File

@@ -34,7 +34,7 @@ class Uwsgi(base.Installer):
"modoboa_venv_path": self.config.get("modoboa", "venv_path"),
"modoboa_instance_path": (
self.config.get("modoboa", "instance_path")),
"uwsgi_socket_path": self.socket_path
"uwsgi_socket_path": self.socket_path,
})
return context
@@ -58,9 +58,11 @@ class Uwsgi(base.Installer):
os.symlink(dst, link)
else:
system.add_user_to_group(
"uwsgi", self.config.get("modoboa", "user"))
self.config.get("modoboa", "user"), "uwsgi")
utils.exec_cmd("chmod -R g+w {}/media".format(
self.config.get("modoboa", "instance_path")))
pattern = (
"s/emperor-tyrant = true/emperor-tyrant false/")
"s/emperor-tyrant = true/emperor-tyrant = false/")
utils.exec_cmd(
"perl -pi -e '{}' /etc/uwsgi.ini".format(pattern))

49
modoboa_installer/ssl.py Normal file
View File

@@ -0,0 +1,49 @@
"""SSL tools."""
import os
from . import utils
class CertificateBackend(object):
"""Base class."""
def __init__(self, config):
"""Set path to certificates."""
self.config = config
for base_dir in ["/etc/pki/tls", "/etc/ssl"]:
if os.path.exists(base_dir):
self.config.set(
"general", "tls_key_file",
"{}/private/%(hostname)s.key".format(base_dir))
self.config.set(
"general", "tls_cert_file",
"{}/certs/%(hostname)s.cert".format(base_dir))
return
raise RuntimeError("Cannot find a directory to store certificate")
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")):
answer = utils.user_input(
"Overwrite the existing SSL certificate? (y/N) ")
if not answer.lower().startswith("y"):
return
utils.printcolor(
"Generating new self-signed certificate", utils.YELLOW)
utils.exec_cmd(
"openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 "
"-subj '/CN={}' -keyout {} -out {}".format(
self.config.get("general", "hostname"),
self.config.get("general", "tls_key_file"),
self.config.get("general", "tls_cert_file"))
)
def get_backend(config):
"""Return the appropriate backend."""
return SelfSignedCertificate(config)

View File

@@ -33,7 +33,7 @@ def user_input(message):
return answer
def exec_cmd(cmd, sudo_user=None, pinput=None, **kwargs):
def exec_cmd(cmd, sudo_user=None, pinput=None, login=True, **kwargs):
"""Execute a shell command.
Run a command using the current user. Set :keyword:`sudo_user` if
you need different privileges.
@@ -45,7 +45,7 @@ def exec_cmd(cmd, sudo_user=None, pinput=None, **kwargs):
"""
sudo_user = ENV.get("sudo_user", sudo_user)
if sudo_user is not None:
cmd = "sudo -i -u %s %s" % (sudo_user, cmd)
cmd = "sudo {}-u {} {}".format("-i " if login else "", sudo_user, cmd)
if "shell" not in kwargs:
kwargs["shell"] = True
if pinput is not None:

4
run.py
View File

@@ -11,6 +11,7 @@ except ImportError:
from modoboa_installer import scripts
from modoboa_installer import utils
from modoboa_installer import package
from modoboa_installer import ssl
def main():
@@ -30,6 +31,8 @@ def main():
config = configparser.SafeConfigParser()
with open("installer.cfg") as fp:
config.readfp(fp)
if not config.has_section("general"):
config.add_section("general")
config.set("general", "hostname", args.hostname)
utils.printcolor(
"Your mail server {} will be installed with the following components:"
@@ -52,6 +55,7 @@ def main():
"and come back later ;)", utils.BLUE)
utils.printcolor("Starting...", utils.GREEN)
package.backend.install("sudo")
ssl.get_backend(config).create()
scripts.install("modoboa", config)
scripts.install("postfix", config)
scripts.install("amavis", config)