job "email" { # Should not run on the same site as email-android7.hcl (port conflict in diplonat) datacenters = ["scorpio"] type = "service" priority = 65 group "dovecot" { count = 1 network { port "zauthentication_port" { static = 1337 to = 1337 } port "imaps_port" { static = 993 to = 993 } port "imap_port" { static = 143 to = 143 } port "lmtp_port" { static = 24 to = 24 } } task "server" { driver = "docker" constraint { attribute = "${attr.unique.hostname}" operator = "=" value = "ananas" } config { image = "superboum/amd64_dovecot:v6" readonly_rootfs = false network_mode = "host" ports = [ "zauthentication_port", "imaps_port", "imap_port", "lmtp_port" ] command = "dovecot" args = [ "-F" ] volumes = [ "secrets/ssl/certs:/etc/ssl/certs", "secrets/ssl/private:/etc/ssl/private", "secrets/conf/:/etc/dovecot/", "/mnt/ssd/mail:/var/mail/", ] } env { TLSINFO = "/C=FR/ST=Bretagne/L=Rennes/O=Deuxfleurs/CN=imap.deuxfleurs.fr" } resources { cpu = 100 memory = 200 } service { name = "dovecot-imap" port = "imap_port" tags = [ "dovecot", ] check { type = "tcp" port = "imap_port" interval = "60s" timeout = "5s" check_restart { limit = 3 grace = "90s" ignore_warnings = false } } } service { name = "dovecot-imaps" port = "imaps_port" tags = [ "dovecot", "(diplonat (tcp_port 993))", "d53-a imap.deuxfleurs.fr", "d53-aaaa imap.deuxfleurs.fr", ] check { type = "tcp" port = "imaps_port" interval = "60s" timeout = "5s" check_restart { limit = 3 grace = "90s" ignore_warnings = false } } } service { name = "dovecot-lmtp" port = "lmtp_port" tags = [ "dovecot", ] check { type = "tcp" port = "lmtp_port" interval = "60s" timeout = "5s" check_restart { limit = 3 grace = "90s" ignore_warnings = false } } } service { name = "dovecot-auth" port = "zauthentication_port" tags = [ "dovecot", ] check { type = "tcp" port = "zauthentication_port" interval = "60s" timeout = "5s" check_restart { limit = 3 grace = "90s" ignore_warnings = false } } } template { data = file("../config/dovecot/dovecot-ldap.conf.tpl") destination = "secrets/conf/dovecot-ldap.conf" perms = "400" } template { data = file("../config/dovecot/dovecot.conf") destination = "secrets/conf/dovecot.conf" perms = "400" } # ----- secrets ------ template { data = "{{ with $d := key \"tricot/certs/imap.deuxfleurs.fr\" | parseJSON }}{{ $d.cert_pem }}{{ end }}" destination = "secrets/ssl/certs/dovecot.crt" perms = "400" } template { data = "{{ with $d := key \"tricot/certs/imap.deuxfleurs.fr\" | parseJSON }}{{ $d.key_pem }}{{ end }}" destination = "secrets/ssl/private/dovecot.key" perms = "400" } } } group "opendkim" { count = 1 network { port "dkim_port" { static = 8999 to = 8999 } } task "server" { driver = "docker" config { image = "superboum/amd64_opendkim:v6" readonly_rootfs = false ports = [ "dkim_port" ] volumes = [ "/dev/log:/dev/log", "secrets/dkim:/etc/dkim", ] } resources { cpu = 100 memory = 50 } service { name = "opendkim" port = "dkim_port" address_mode = "host" tags = [ "opendkim", ] check { type = "tcp" port = "dkim_port" interval = "60s" timeout = "5s" check_restart { limit = 3 grace = "90s" ignore_warnings = false } } } template { data = file("../config/dkim/keytable") destination = "secrets/dkim/keytable" } template { data = file("../config/dkim/signingtable") destination = "secrets/dkim/signingtable" } template { data = file("../config/dkim/trusted") destination = "secrets/dkim/trusted" } # --- secrets --- template { data = "{{ key \"secrets/email/dkim/smtp.private\" }}" destination = "secrets/dkim/smtp.private" } } } group "postfix" { count = 1 network { port "smtp_port" { static = 25 to = 25 } port "smtps_port" { static = 465 to = 465 } port "submission_port" { static = 587 to = 587 } } task "server" { driver = "docker" config { image = "superboum/amd64_postfix:v4" readonly_rootfs = false network_mode = "host" ports = [ "smtp_port", "smtps_port", "submission_port" ] command = "postfix" args = [ "start-fg" ] volumes = [ "secrets/ssl:/etc/ssl", "secrets/postfix:/etc/postfix-conf", "/dev/log:/dev/log" ] } env { TLSINFO = "/C=FR/ST=Bretagne/L=Rennes/O=Deuxfleurs/CN=smtp.deuxfleurs.fr" MAILNAME = "smtp.deuxfleurs.fr" } resources { cpu = 100 memory = 200 } service { name = "postfix-smtp" port = "smtp_port" address_mode = "host" tags = [ "postfix", "(diplonat (tcp_port 25 465 587))", "d53-a smtp.deuxfleurs.fr", "d53-aaaa smtp.deuxfleurs.fr" ] check { type = "tcp" port = "smtp_port" interval = "60s" timeout = "5s" check_restart { limit = 3 grace = "90s" ignore_warnings = false } } } service { name = "postfix-smtps" port = "smtps_port" address_mode = "host" tags = [ "postfix", ] check { type = "tcp" port = "smtps_port" interval = "60s" timeout = "5s" check_restart { limit = 3 grace = "90s" ignore_warnings = false } } } service { name = "postfix-submission" port = "submission_port" address_mode = "host" tags = [ "postfix", ] check { type = "tcp" port = "submission_port" interval = "60s" timeout = "5s" check_restart { limit = 3 grace = "90s" ignore_warnings = false } } } template { data = file("../config/postfix/ldap-account.cf.tpl") destination = "secrets/postfix/ldap-account.cf" } template { data = file("../config/postfix/ldap-alias.cf.tpl") destination = "secrets/postfix/ldap-alias.cf" } template { data = file("../config/postfix/ldap-virtual-domains.cf.tpl") destination = "secrets/postfix/ldap-virtual-domains.cf" } template { data = file("../config/postfix/dynamicmaps.cf") destination = "secrets/postfix/dynamicmaps.cf" } template { data = file("../config/postfix/header_checks") destination = "secrets/postfix/header_checks" } template { data = file("../config/postfix/main.cf") destination = "secrets/postfix/main.cf" } template { data = file("../config/postfix/master.cf") destination = "secrets/postfix/master.cf" } template { data = file("../config/postfix/transport") destination = "secrets/postfix/transport" } template { # Collect machine IPs from the cluster. # We use intermediate maps to ensure we get a sorted list with no duplicates, # so that it is robust wrt. changes in the order of the output of ls or # addition of new machines in an existing site. # (scratch.MapValues returns the list of *values* in the map, sorted by *key*) data = <