diff --git a/Vagrantfile b/Vagrantfile
index 757c2ec9..2ab2f405 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -8,7 +8,7 @@ Vagrant.configure("2") do |config|
# to the public web. However, we currently don't want to expose SSH since
# the machine's box will let anyone log into it. So instead we'll put the
# machine on a private network.
- config.vm.hostname = "mailinabox.lan"
+ config.vm.hostname = "box.mailinabox.lan"
config.vm.network "private_network", ip: "192.168.56.4"
config.vm.provision :shell, :inline => <<-SH
@@ -18,7 +18,7 @@ Vagrant.configure("2") do |config|
export NONINTERACTIVE=1
export PUBLIC_IP=auto
export PUBLIC_IPV6=auto
- export PRIMARY_HOSTNAME=auto
+ export BOX_HOSTNAME=auto
#export SKIP_NETWORK_CHECKS=1
# Start the setup script.
diff --git a/conf/ios-profile.xml b/conf/ios-profile.xml
index 273c0bf6..b0513535 100644
--- a/conf/ios-profile.xml
+++ b/conf/ios-profile.xml
@@ -13,19 +13,19 @@
{html.escape(content)}'
diff --git a/management/mailconfig.py b/management/mailconfig.py
index e623eace..92f56f76 100755
--- a/management/mailconfig.py
+++ b/management/mailconfig.py
@@ -517,7 +517,7 @@ def add_auto_aliases(aliases, env):
conn.commit()
def get_system_administrator(env):
- return "administrator@" + env['PRIMARY_HOSTNAME']
+ return "administrator@" + env['BOX_HOSTNAME']
def get_required_aliases(env):
# These are the aliases that must exist.
@@ -527,7 +527,7 @@ def get_required_aliases(env):
aliases.add(get_system_administrator(env))
# The hostmaster alias is exposed in the DNS SOA for each zone.
- aliases.add("hostmaster@" + env['PRIMARY_HOSTNAME'])
+ aliases.add("hostmaster@" + env['BOX_HOSTNAME'])
# Get a list of domains we serve mail for, except ones for which the only
# email on that domain are the required aliases or a catch-all/domain-forwarder.
diff --git a/management/mfa.py b/management/mfa.py
index 6b56ad86..ec0ffd04 100644
--- a/management/mfa.py
+++ b/management/mfa.py
@@ -83,7 +83,7 @@ def provision_totp(email, env):
# Make a URI that we encode within a QR code.
uri = pyotp.TOTP(secret).provisioning_uri(
name=email,
- issuer_name=env["PRIMARY_HOSTNAME"] + " Mail-in-a-Box Control Panel"
+ issuer_name=env["BOX_HOSTNAME"] + " Mail-in-a-Box Control Panel"
)
# Generate a QR code as a base64-encode PNG image.
diff --git a/management/ssl_certificates.py b/management/ssl_certificates.py
index 8c1b841e..59cde277 100755
--- a/management/ssl_certificates.py
+++ b/management/ssl_certificates.py
@@ -28,7 +28,7 @@ def get_ssl_certificates(env):
if fn == 'ssl_certificate.pem':
# This is always a symbolic link
# to the certificate to use for
- # PRIMARY_HOSTNAME. Don't let it
+ # BOX_HOSTNAME. Don't let it
# be eligible for use because we
# could end up creating a symlink
# to itself --- we want to find
@@ -73,8 +73,8 @@ def get_ssl_certificates(env):
domains = { }
for cert in certificates:
# What domains is this certificate good for?
- cert_domains, primary_domain = get_certificate_domains(cert["cert"])
- cert["primary_domain"] = primary_domain
+ cert_domains, common_name = get_certificate_domains(cert["cert"])
+ cert["common_name"] = common_name
# Is there a private key file for this certificate?
private_key = private_keys.get(cert["cert"].public_key().public_numbers())
@@ -84,9 +84,9 @@ def get_ssl_certificates(env):
# Add this cert to the list of certs usable for the domains.
for domain in cert_domains:
- # The primary hostname can only use a certificate mapped
+ # The box hostname can only use a certificate mapped
# to the system private key.
- if domain == env['PRIMARY_HOSTNAME'] and cert["private_key"]["filename"] != os.path.join(env['STORAGE_ROOT'], 'ssl', 'ssl_private_key.pem'):
+ if domain == env['BOX_HOSTNAME'] and cert["private_key"]["filename"] != os.path.join(env['STORAGE_ROOT'], 'ssl', 'ssl_private_key.pem'):
continue
domains.setdefault(domain, []).append(cert)
@@ -134,7 +134,7 @@ def get_ssl_certificates(env):
ret[domain] = {
"private-key": cert["private_key"]["filename"],
"certificate": cert["filename"],
- "primary-domain": cert["primary_domain"],
+ "common-name": cert["common_name"],
"certificate_object": cert["cert"],
}
@@ -148,12 +148,12 @@ def get_domain_ssl_files(domain, ssl_certificates, env, allow_missing_cert=False
system_certificate = {
"private-key": ssl_private_key,
"certificate": ssl_certificate,
- "primary-domain": env['PRIMARY_HOSTNAME'],
+ "common-name": env['BOX_HOSTNAME'],
"certificate_object": load_pem(load_cert_chain(ssl_certificate)[0]),
}
- if use_main_cert and domain == env['PRIMARY_HOSTNAME']:
- # The primary domain must use the server certificate because
+ if use_main_cert and domain == env['BOX_HOSTNAME']:
+ # The box domain must use the server certificate because
# it is hard-coded in some service configuration files.
return system_certificate
@@ -263,7 +263,7 @@ def provision_certificates(env, limit_domains):
# we'll create a list of lists of domains where the inner lists have
# at most 100 items. By sorting we also get the DNS zone domain as the first
# entry in each list (unless we overflow beyond 100) which ends up as the
- # primary domain listed in each certificate.
+ # first domain listed in each certificate.
from dns_update import get_dns_zones
certs = { }
for zone, _zonefile in get_dns_zones(env):
@@ -467,21 +467,21 @@ def install_cert_copy_file(fn, env):
def post_install_func(env):
ret = []
- # Get the certificate to use for PRIMARY_HOSTNAME.
+ # Get the certificate to use for BOX_HOSTNAME.
ssl_certificates = get_ssl_certificates(env)
- cert = get_domain_ssl_files(env['PRIMARY_HOSTNAME'], ssl_certificates, env, use_main_cert=False)
+ cert = get_domain_ssl_files(env['BOX_HOSTNAME'], ssl_certificates, env, use_main_cert=False)
if not cert:
# Ruh-row, we don't have any certificate usable
- # for the primary hostname.
- ret.append("there is no valid certificate for " + env['PRIMARY_HOSTNAME'])
+ # for the box hostname.
+ ret.append("there is no valid certificate for " + env['BOX_HOSTNAME'])
- # Symlink the best cert for PRIMARY_HOSTNAME to the system
+ # Symlink the best cert for BOX_HOSTNAME to the system
# certificate path, which is hard-coded for various purposes, and then
# restart postfix and dovecot.
system_ssl_certificate = os.path.join(os.path.join(env["STORAGE_ROOT"], 'ssl', 'ssl_certificate.pem'))
if cert and os.readlink(system_ssl_certificate) != cert['certificate']:
# Update symlink.
- ret.append("updating primary certificate")
+ ret.append("updating box certificate")
ssl_certificate = cert['certificate']
os.unlink(system_ssl_certificate)
os.symlink(ssl_certificate, system_ssl_certificate)
@@ -523,7 +523,7 @@ def check_certificate(domain, ssl_certificate, ssl_private_key, warn_if_expiring
# First check that the domain name is one of the names allowed by
# the certificate.
if domain is not None:
- certificate_names, _cert_primary_name = get_certificate_domains(cert)
+ certificate_names, _cn = get_certificate_domains(cert)
# Check that the domain appears among the acceptable names, or a wildcard
# form of the domain name (which is a stricter check than the specs but
@@ -558,9 +558,9 @@ def check_certificate(domain, ssl_certificate, ssl_private_key, warn_if_expiring
if cert.issuer == cert.subject:
return ("SELF-SIGNED", None)
- # When selecting which certificate to use for non-primary domains, we check if the primary
- # certificate or a www-parent-domain certificate is good for the domain. There's no need
- # to run extra checks beyond this point.
+ # When selecting which certificate to use for non-registrable domains, we check if the
+ # registrable domain certificate or a www-parent-domain certificate is good for the domain.
+ # There's no need to run extra checks beyond this point.
if just_check_domain:
return ("OK", None)
diff --git a/management/status_checks.py b/management/status_checks.py
index 67aaaeb4..dd621df6 100755
--- a/management/status_checks.py
+++ b/management/status_checks.py
@@ -216,7 +216,7 @@ def check_software_updates(env, output):
def check_system_aliases(env, output):
# Check that the administrator alias exists since that's where all
# admin email is automatically directed.
- check_alias_exists("System administrator address", "administrator@" + env['PRIMARY_HOSTNAME'], env, output)
+ check_alias_exists("System administrator address", "administrator@" + env['BOX_HOSTNAME'], env, output)
def check_free_disk_space(rounded_values, env, output):
# Check free disk space.
@@ -382,8 +382,8 @@ def run_domain_checks_on_domain(domain, rounded_time, env, dns_domains, dns_zone
output.add_heading(domain)
output.print_error("Domain name is invalid: " + str(e))
- if domain == env["PRIMARY_HOSTNAME"]:
- check_primary_hostname_dns(domain, env, output, dns_domains, dns_zonefiles)
+ if domain == env["BOX_HOSTNAME"]:
+ check_box_hostname_dns(domain, env, output, dns_domains, dns_zonefiles)
if domain in dns_domains:
check_dns_zone(domain, env, output, dns_zonefiles)
@@ -419,13 +419,13 @@ def run_domain_checks_on_domain(domain, rounded_time, env, dns_domains, dns_zone
return (domain, output)
-def check_primary_hostname_dns(domain, env, output, dns_domains, dns_zonefiles):
+def check_box_hostname_dns(domain, env, output, dns_domains, dns_zonefiles):
# If a DS record is set on the zone containing this domain, check DNSSEC now.
has_dnssec = False
for zone in dns_domains:
if (zone == domain or domain.endswith("." + zone)) and query_dns(zone, "DS", nxdomain=None) is not None:
has_dnssec = True
- check_dnssec(zone, env, output, dns_zonefiles, is_checking_primary=True)
+ check_dnssec(zone, env, output, dns_zonefiles, is_checking_box_domain=True)
ip = query_dns(domain, "A")
ns_ips = query_dns("ns1." + domain, "A") + '/' + query_dns("ns2." + domain, "A")
@@ -437,35 +437,35 @@ def check_primary_hostname_dns(domain, env, output, dns_domains, dns_zonefiles):
# the nameserver, are reporting the right info --- but if the glue is incorrect this
# will probably fail.
if ns_ips == env['PUBLIC_IP'] + '/' + env['PUBLIC_IP']:
- output.print_ok("Nameserver glue records are correct at registrar. [ns1/ns2.{} ↦ {}]".format(env['PRIMARY_HOSTNAME'], env['PUBLIC_IP']))
+ output.print_ok("Nameserver glue records are correct at registrar. [ns1/ns2.{} ↦ {}]".format(env['BOX_HOSTNAME'], env['PUBLIC_IP']))
elif ip == env['PUBLIC_IP']:
# The NS records are not what we expect, but the domain resolves correctly, so
# the user may have set up external DNS. List this discrepancy as a warning.
output.print_warning("""Nameserver glue records (ns1.{} and ns2.{}) should be configured at your domain name
- registrar as having the IP address of this box ({}). They currently report addresses of {}. If you have set up External DNS, this may be OK.""".format(env['PRIMARY_HOSTNAME'], env['PRIMARY_HOSTNAME'], env['PUBLIC_IP'], ns_ips))
+ registrar as having the IP address of this box ({}). They currently report addresses of {}. If you have set up External DNS, this may be OK.""".format(env['BOX_HOSTNAME'], env['BOX_HOSTNAME'], env['PUBLIC_IP'], ns_ips))
else:
output.print_error("""Nameserver glue records are incorrect. The ns1.{} and ns2.{} nameservers must be configured at your domain name
registrar as having the IP address {}. They currently report addresses of {}. It may take several hours for
- public DNS to update after a change.""".format(env['PRIMARY_HOSTNAME'], env['PRIMARY_HOSTNAME'], env['PUBLIC_IP'], ns_ips))
+ public DNS to update after a change.""".format(env['BOX_HOSTNAME'], env['BOX_HOSTNAME'], env['PUBLIC_IP'], ns_ips))
- # Check that PRIMARY_HOSTNAME resolves to PUBLIC_IP[V6] in public DNS.
+ # Check that BOX_HOSTNAME resolves to PUBLIC_IP[V6] in public DNS.
ipv6 = query_dns(domain, "AAAA") if env.get("PUBLIC_IPV6") else None
if ip == env['PUBLIC_IP'] and not (ipv6 and env['PUBLIC_IPV6'] and ipv6 != normalize_ip(env['PUBLIC_IPV6'])):
- output.print_ok("Domain resolves to box's IP address. [{} ↦ {}]".format(env['PRIMARY_HOSTNAME'], my_ips))
+ output.print_ok("Domain resolves to box's IP address. [{} ↦ {}]".format(env['BOX_HOSTNAME'], my_ips))
else:
output.print_error("""This domain must resolve to this box's IP address ({}) in public DNS but it currently resolves
to {}. It may take several hours for public DNS to update after a change. This problem may result from other
issues listed above.""".format(my_ips, ip + ((" / " + ipv6) if ipv6 is not None else "")))
- # Check reverse DNS matches the PRIMARY_HOSTNAME. Note that it might not be
+ # Check reverse DNS matches the BOX_HOSTNAME. Note that it might not be
# a DNS zone if it is a subdomain of another domain we have a zone for.
existing_rdns_v4 = query_dns(dns.reversename.from_address(env['PUBLIC_IP']), "PTR")
existing_rdns_v6 = query_dns(dns.reversename.from_address(env['PUBLIC_IPV6']), "PTR") if env.get("PUBLIC_IPV6") else None
if existing_rdns_v4 == domain and existing_rdns_v6 in {None, domain}:
- output.print_ok("Reverse DNS is set correctly at ISP. [{} ↦ {}]".format(my_ips, env['PRIMARY_HOSTNAME']))
+ output.print_ok("Reverse DNS is set correctly at ISP. [{} ↦ {}]".format(my_ips, env['BOX_HOSTNAME']))
elif existing_rdns_v4 == existing_rdns_v6 or existing_rdns_v6 is None:
output.print_error(f"""This box's reverse DNS is currently {existing_rdns_v4}, but it should be {domain}. Your ISP or cloud provider will have instructions
on setting up reverse DNS for this box.""" )
@@ -518,10 +518,10 @@ def check_dns_zone(domain, env, output, dns_zonefiles):
custom_dns_records = list(get_custom_dns_config(env)) # generator => list so we can reuse it
correct_ip = "; ".join(sorted(get_custom_dns_records(custom_dns_records, domain, "A"))) or env['PUBLIC_IP']
custom_secondary_ns = get_secondary_dns(custom_dns_records, mode="NS")
- secondary_ns = custom_secondary_ns or ["ns2." + env['PRIMARY_HOSTNAME']]
+ secondary_ns = custom_secondary_ns or ["ns2." + env['BOX_HOSTNAME']]
existing_ns = query_dns(domain, "NS")
- correct_ns = "; ".join(sorted(["ns1." + env["PRIMARY_HOSTNAME"], *secondary_ns]))
+ correct_ns = "; ".join(sorted(["ns1." + env["BOX_HOSTNAME"], *secondary_ns]))
ip = query_dns(domain, "A")
probably_external_dns = False
@@ -595,7 +595,7 @@ def check_dns_zone_suggestions(domain, env, output, dns_zonefiles, domains_with_
check_dnssec(domain, env, output, dns_zonefiles)
-def check_dnssec(domain, env, output, dns_zonefiles, is_checking_primary=False):
+def check_dnssec(domain, env, output, dns_zonefiles, is_checking_box_domain=False):
# See if the domain has a DS record set at the registrar. The DS record must
# match one of the keys that we've used to sign the zone. It may use one of
# several hashing algorithms. We've pre-generated all possible valid DS
@@ -661,7 +661,7 @@ def check_dnssec(domain, env, output, dns_zonefiles, is_checking_primary=False):
IMPORTANT: Do not delete existing DNSSEC 'DS' records for this domain until confirmation that the new DNSSEC 'DS' record
for this domain is valid.""")
else:
- if is_checking_primary:
+ if is_checking_box_domain:
output.print_error("""The DNSSEC 'DS' record for %s is incorrect. See further details below.""" % domain)
return
output.print_error("""This domain's DNSSEC DS record is incorrect. The chain of trust is broken between the public DNS system
@@ -702,7 +702,7 @@ def check_dnssec(domain, env, output, dns_zonefiles, is_checking_primary=False):
def check_mail_domain(domain, env, output):
# Check the MX record.
- recommended_mx = "10 " + env['PRIMARY_HOSTNAME']
+ recommended_mx = "10 " + env['BOX_HOSTNAME']
mx = query_dns(domain, "MX", nxdomain=None)
if mx is None or mx == "[timeout]":
@@ -713,26 +713,26 @@ def check_mail_domain(domain, env, output):
mxhost = mx.split('; ')[0].split(' ')[1]
if mxhost is None:
- # A missing MX record is okay on the primary hostname because
- # the primary hostname's A record (the MX fallback) is... itself,
+ # A missing MX record is okay on the box hostname because
+ # the box hostname's A record (the MX fallback) is... itself,
# which is what we want the MX to be.
- if domain == env['PRIMARY_HOSTNAME']:
+ if domain == env['BOX_HOSTNAME']:
output.print_ok(f"Domain's email is directed to this domain. [{domain} has no MX record, which is ok]")
# And a missing MX record is okay on other domains if the A record
- # matches the A record of the PRIMARY_HOSTNAME. Actually this will
+ # matches the A record of the BOX_HOSTNAME. Actually this will
# probably confuse DANE TLSA, but we'll let that slide for now.
else:
domain_a = query_dns(domain, "A", nxdomain=None)
- primary_a = query_dns(env['PRIMARY_HOSTNAME'], "A", nxdomain=None)
- if domain_a is not None and domain_a == primary_a:
+ box_a = query_dns(env['BOX_HOSTNAME'], "A", nxdomain=None)
+ if domain_a is not None and domain_a == box_a:
output.print_ok(f"Domain's email is directed to this domain. [{domain} has no MX record but its A record is OK]")
else:
output.print_error(f"""This domain's DNS MX record is not set. It should be '{recommended_mx}'. Mail will not
be delivered to this box. It may take several hours for public DNS to update after a
change. This problem may result from other issues listed here.""")
- elif mxhost == env['PRIMARY_HOSTNAME']:
+ elif mxhost == env['BOX_HOSTNAME']:
good_news = f"Domain's email is directed to this domain. [{domain} ↦ {mx}]"
if mx != recommended_mx:
good_news += f" This configuration is non-standard. The recommended configuration is '{recommended_mx}'."
@@ -743,7 +743,7 @@ def check_mail_domain(domain, env, output):
sts_resolver = postfix_mta_sts_resolver.resolver.STSResolver(loop=loop)
valid, policy = loop.run_until_complete(sts_resolver.resolve(domain))
if valid == postfix_mta_sts_resolver.resolver.STSFetchResult.VALID:
- if policy[1].get("mx") == [env['PRIMARY_HOSTNAME']] and policy[1].get("mode") == "enforce": # policy[0] is the policyid
+ if policy[1].get("mx") == [env['BOX_HOSTNAME']] and policy[1].get("mode") == "enforce": # policy[0] is the policyid
output.print_ok("MTA-STS policy is present.")
else:
output.print_error(f"MTA-STS policy is present but has unexpected settings. [{policy[1]}]")
@@ -763,7 +763,7 @@ def check_mail_domain(domain, env, output):
# Stop if the domain is listed in the Spamhaus Domain Block List.
# The user might have chosen a domain that was previously in use by a spammer
# and will not be able to reliably send mail.
-
+
# See https://www.spamhaus.org/news/article/807/using-our-public-mirrors-check-your-return-codes-now. for
# information on spamhaus return codes
dbl = query_dns(domain+'.dbl.spamhaus.org', "A", nxdomain=None)
@@ -786,9 +786,9 @@ def check_mail_domain(domain, env, output):
def check_web_domain(domain, rounded_time, ssl_certificates, env, output):
# See if the domain's A record resolves to our PUBLIC_IP. This is already checked
- # for PRIMARY_HOSTNAME, for which it is required for mail specifically. For it and
+ # for BOX_HOSTNAME, for which it is required for mail specifically. For it and
# other domains, it is required to access its website.
- if domain != env['PRIMARY_HOSTNAME']:
+ if domain != env['BOX_HOSTNAME']:
ok_values = []
for (rtype, expected) in (("A", env['PUBLIC_IP']), ("AAAA", env.get('PUBLIC_IPV6'))):
if not expected: continue # IPv6 is not configured
@@ -805,7 +805,7 @@ def check_web_domain(domain, rounded_time, ssl_certificates, env, output):
output.print_ok("Domain resolves to this box's IP address. [{} ↦ {}]".format(domain, '; '.join(ok_values)))
- # We need a TLS certificate for PRIMARY_HOSTNAME because that's where the
+ # We need a TLS certificate for BOX_HOSTNAME because that's where the
# user will log in with IMAP or webmail. Any other domain we serve a
# website for also needs a signed certificate.
check_ssl_cert(domain, rounded_time, ssl_certificates, env, output)
@@ -886,7 +886,7 @@ def check_ssl_cert(domain, rounded_time, ssl_certificates, env, output):
elif cert_status == "SELF-SIGNED":
# Offer instructions for purchasing a signed certificate.
- if domain == env['PRIMARY_HOSTNAME']:
+ if domain == env['BOX_HOSTNAME']:
output.print_error("""The TLS (SSL) certificate for this domain is currently self-signed. You will get a security
warning when you check or send email and when visiting this domain in a web browser (for webmail or
static site hosting).""")
@@ -1140,9 +1140,9 @@ if __name__ == "__main__":
with multiprocessing.pool.Pool(processes=10) as pool:
run_and_output_changes(env, pool)
- elif sys.argv[1] == "--check-primary-hostname":
- # See if the primary hostname appears resolvable and has a signed certificate.
- domain = env['PRIMARY_HOSTNAME']
+ elif sys.argv[1] == "--check-box-hostname":
+ # See if the box hostname appears resolvable and has a signed certificate.
+ domain = env['BOX_HOSTNAME']
if query_dns(domain, "A") != env['PUBLIC_IP']:
sys.exit(1)
ssl_certificates = get_ssl_certificates(env)
diff --git a/management/utils.py b/management/utils.py
index 1dbbeb7e..bf1fbebd 100644
--- a/management/utils.py
+++ b/management/utils.py
@@ -73,8 +73,8 @@ def sort_domains(domain_names, env):
# Sort the zones.
zone_domains = sorted(zones.values(),
key = lambda d : (
- # PRIMARY_HOSTNAME or the zone that contains it is always first.
- not (d == env['PRIMARY_HOSTNAME'] or env['PRIMARY_HOSTNAME'].endswith("." + d)),
+ # BOX_HOSTNAME or the zone that contains it is always first.
+ not (d == env['BOX_HOSTNAME'] or env['BOX_HOSTNAME'].endswith("." + d)),
# Then just dumb lexicographically.
d,
@@ -86,11 +86,11 @@ def sort_domains(domain_names, env):
# First by zone.
zone_domains.index(zones[d]),
- # PRIMARY_HOSTNAME is always first within the zone that contains it.
- d != env['PRIMARY_HOSTNAME'],
+ # BOX_HOSTNAME is always first within the zone that contains it.
+ d != env['BOX_HOSTNAME'],
# Followed by any of its subdomains.
- not d.endswith("." + env['PRIMARY_HOSTNAME']),
+ not d.endswith("." + env['BOX_HOSTNAME']),
# Then in right-to-left lexicographic order of the .-separated parts of the name.
list(reversed(d.split("."))),
diff --git a/management/web_update.py b/management/web_update.py
index c31fe8fc..2197641a 100644
--- a/management/web_update.py
+++ b/management/web_update.py
@@ -39,10 +39,10 @@ def get_web_domains(env, include_www_redirects=True, include_auto=True, exclude_
# IP address than this box. Remove those domains from our list.
domains -= get_domains_with_a_records(env)
- # Ensure the PRIMARY_HOSTNAME is in the list so we can serve webmail
+ # Ensure the BOX_HOSTNAME is in the list so we can serve webmail
# as well as Z-Push for Exchange ActiveSync. This can't be removed
# by a custom A/AAAA record and is never a 'www.' redirect.
- domains.add(env['PRIMARY_HOSTNAME'])
+ domains.add(env['BOX_HOSTNAME'])
# Sort the list so the nginx conf gets written in a stable order.
return sort_domains(domains, env)
@@ -86,18 +86,18 @@ def do_web_update(env):
# Load the templates.
template0 = read_conf("nginx.conf")
template1 = read_conf("nginx-alldomains.conf")
- template2 = read_conf("nginx-primaryonly.conf")
+ template2 = read_conf("nginx-boxonly.conf")
template3 = "\trewrite ^(.*) https://$REDIRECT_DOMAIN$1 permanent;\n"
- # Add the PRIMARY_HOST configuration first so it becomes nginx's default server.
- nginx_conf += make_domain_config(env['PRIMARY_HOSTNAME'], [template0, template1, template2], ssl_certificates, env)
+ # Add the BOX_HOSTNAME configuration first so it becomes nginx's default server.
+ nginx_conf += make_domain_config(env['BOX_HOSTNAME'], [template0, template1, template2], ssl_certificates, env)
# Add configuration all other web domains.
has_root_proxy_or_redirect = get_web_domains_with_root_overrides(env)
web_domains_not_redirect = get_web_domains(env, include_www_redirects=False)
for domain in get_web_domains(env):
- if domain == env['PRIMARY_HOSTNAME']:
- # PRIMARY_HOSTNAME is handled above.
+ if domain == env['BOX_HOSTNAME']:
+ # BOX_HOSTNAME is handled above.
continue
if domain in web_domains_not_redirect:
# This is a regular domain.
@@ -250,7 +250,7 @@ def get_web_domains_info(env):
def check_cert(domain):
try:
tls_cert = get_domain_ssl_files(domain, ssl_certificates, env, allow_missing_cert=True)
- except OSError: # PRIMARY_HOSTNAME cert is missing
+ except OSError: # BOX_HOSTNAME cert is missing
tls_cert = None
if tls_cert is None: return ("danger", "No certificate installed.")
cert_status, cert_status_details = check_certificate(domain, tls_cert["certificate"], tls_cert["private-key"])
diff --git a/setup/firstuser.sh b/setup/firstuser.sh
index b6b1b3c8..71ce0c0e 100644
--- a/setup/firstuser.sh
+++ b/setup/firstuser.sh
@@ -34,8 +34,8 @@ if [ -z "$(management/cli.py user)" ]; then
# But in a non-interactive shell, just make something up.
# This is normally for testing.
else
- # Use me@PRIMARY_HOSTNAME
- EMAIL_ADDR=me@$PRIMARY_HOSTNAME
+ # Use me@BOX_HOSTNAME
+ EMAIL_ADDR=me@$BOX_HOSTNAME
EMAIL_PW=12345678
echo
echo "Creating a new administrative mail account for $EMAIL_ADDR with password $EMAIL_PW."
@@ -54,5 +54,5 @@ if [ -z "$(management/cli.py user)" ]; then
hide_output management/cli.py user make-admin "$EMAIL_ADDR"
# Create an alias to which we'll direct all automatically-created administrative aliases.
- management/cli.py alias add "administrator@$PRIMARY_HOSTNAME" "$EMAIL_ADDR" > /dev/null
+ management/cli.py alias add "administrator@$BOX_HOSTNAME" "$EMAIL_ADDR" > /dev/null
fi
diff --git a/setup/mail-dovecot.sh b/setup/mail-dovecot.sh
index b146e44a..158e449d 100755
--- a/setup/mail-dovecot.sh
+++ b/setup/mail-dovecot.sh
@@ -152,7 +152,7 @@ EOF
# Setting a `postmaster_address` is required or LMTP won't start. An alias
# will be created automatically by our management daemon.
tools/editconf.py /etc/dovecot/conf.d/15-lda.conf \
- "postmaster_address=postmaster@$PRIMARY_HOSTNAME"
+ "postmaster_address=postmaster@$BOX_HOSTNAME"
# ### Sieve
diff --git a/setup/mail-postfix.sh b/setup/mail-postfix.sh
index 7b642a2a..88822afa 100755
--- a/setup/mail-postfix.sh
+++ b/setup/mail-postfix.sh
@@ -57,7 +57,7 @@ tools/editconf.py /etc/postfix/main.cf \
inet_interfaces=all \
smtp_bind_address="$PRIVATE_IP" \
smtp_bind_address6="$PRIVATE_IPV6" \
- myhostname="$PRIMARY_HOSTNAME"\
+ myhostname="$BOX_HOSTNAME"\
smtpd_banner="\$myhostname ESMTP Hi, I'm a Mail-in-a-Box (Ubuntu/Postfix; see https://mailinabox.email/)" \
mydestination=localhost
@@ -121,7 +121,7 @@ cp conf/postfix_outgoing_mail_header_filters /etc/postfix/outgoing_mail_header_f
# Modify the `outgoing_mail_header_filters` file to use the local machine name and ip
# on the first received header line. This may help reduce the spam score of email by
# removing the 127.0.0.1 reference.
-sed -i "s/PRIMARY_HOSTNAME/$PRIMARY_HOSTNAME/" /etc/postfix/outgoing_mail_header_filters
+sed -i "s/BOX_HOSTNAME/$BOX_HOSTNAME/" /etc/postfix/outgoing_mail_header_filters
sed -i "s/PUBLIC_IP/$PUBLIC_IP/" /etc/postfix/outgoing_mail_header_filters
# Enable TLS on incoming connections. It is not required on port 25, allowing for opportunistic
diff --git a/setup/migrate.py b/setup/migrate.py
index 94bea923..a0aec342 100755
--- a/setup/migrate.py
+++ b/setup/migrate.py
@@ -149,36 +149,36 @@ def migration_11(env):
def migration_12(env):
# Upgrading to Carddav Roundcube plugin to version 3+, it requires the carddav_*
- # tables to be dropped.
- # Checking that the roundcube database already exists.
- if os.path.exists(os.path.join(env["STORAGE_ROOT"], "mail/roundcube/roundcube.sqlite")):
- import sqlite3
- conn = sqlite3.connect(os.path.join(env["STORAGE_ROOT"], "mail/roundcube/roundcube.sqlite"))
- c = conn.cursor()
- # Get a list of all the tables that begin with 'carddav_'
- c.execute("SELECT name FROM sqlite_master WHERE type = ? AND name LIKE ?", ('table', 'carddav_%'))
- carddav_tables = c.fetchall()
- # If there were tables that begin with 'carddav_', drop them
- if carddav_tables:
- for table in carddav_tables:
- try:
- table = table[0]
- c = conn.cursor()
- dropcmd = "DROP TABLE %s" % table
- c.execute(dropcmd)
- except:
- print("Failed to drop table", table)
- # Save.
- conn.commit()
- conn.close()
+ # tables to be dropped.
+ # Checking that the roundcube database already exists.
+ if os.path.exists(os.path.join(env["STORAGE_ROOT"], "mail/roundcube/roundcube.sqlite")):
+ import sqlite3
+ conn = sqlite3.connect(os.path.join(env["STORAGE_ROOT"], "mail/roundcube/roundcube.sqlite"))
+ c = conn.cursor()
+ # Get a list of all the tables that begin with 'carddav_'
+ c.execute("SELECT name FROM sqlite_master WHERE type = ? AND name LIKE ?", ('table', 'carddav_%'))
+ carddav_tables = c.fetchall()
+ # If there were tables that begin with 'carddav_', drop them
+ if carddav_tables:
+ for table in carddav_tables:
+ try:
+ table = table[0]
+ c = conn.cursor()
+ dropcmd = "DROP TABLE %s" % table
+ c.execute(dropcmd)
+ except:
+ print("Failed to drop table", table)
+ # Save.
+ conn.commit()
+ conn.close()
- # Delete all sessions, requiring users to login again to recreate carddav_*
- # databases
- conn = sqlite3.connect(os.path.join(env["STORAGE_ROOT"], "mail/roundcube/roundcube.sqlite"))
- c = conn.cursor()
- c.execute("delete from session;")
- conn.commit()
- conn.close()
+ # Delete all sessions, requiring users to login again to recreate carddav_*
+ # databases
+ conn = sqlite3.connect(os.path.join(env["STORAGE_ROOT"], "mail/roundcube/roundcube.sqlite"))
+ c = conn.cursor()
+ c.execute("delete from session;")
+ conn.commit()
+ conn.close()
def migration_13(env):
# Add the "mfa" table for configuring MFA for login to the control panel.
@@ -190,6 +190,13 @@ def migration_14(env):
db = os.path.join(env["STORAGE_ROOT"], 'mail/users.sqlite')
shell("check_call", ["sqlite3", db, "CREATE TABLE auto_aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, source TEXT NOT NULL UNIQUE, destination TEXT NOT NULL, permitted_senders TEXT);"])
+def migration_15(env):
+ # Replace PRIMARY_HOSTNAME with BOX_HOSTNAME in mailinabox.conf
+ shell("check_call", ["sed", "-i", "s/PRIMARY_HOSTNAME/BOX_HOSTNAME/g", "/etc/mailinabox.conf"])
+ env["BOX_HOSTNAME"] = env.get("PRIMARY_HOSTNAME", env.get("BOX_HOSTNAME"))
+ env["PRIMARY_HOSTNAME"] = None
+ del env["PRIMARY_HOSTNAME"]
+
###########################################################
def get_current_migration():
diff --git a/setup/munin.sh b/setup/munin.sh
index 017862de..15c988e4 100755
--- a/setup/munin.sh
+++ b/setup/munin.sh
@@ -24,12 +24,12 @@ includedir /etc/munin/munin-conf.d
cgiurl_graph /admin/munin/cgi-graph
# a simple host tree
-[$PRIMARY_HOSTNAME]
+[$BOX_HOSTNAME]
address 127.0.0.1
# send alerts to the following address
contacts admin
-contact.admin.command mail -s "Munin notification \${var:host}" administrator@$PRIMARY_HOSTNAME
+contact.admin.command mail -s "Munin notification \${var:host}" administrator@$BOX_HOSTNAME
contact.admin.always_send warning critical
EOF
@@ -40,7 +40,7 @@ chown munin /var/log/munin/munin-cgi-graph.log
# ensure munin-node knows the name of this machine
# and reduce logging level to warning
tools/editconf.py /etc/munin/munin-node.conf -s \
- host_name="$PRIMARY_HOSTNAME" \
+ host_name="$BOX_HOSTNAME" \
log_level=1
# Update the activated plugins through munin's autoconfiguration.
diff --git a/setup/network-checks.sh b/setup/network-checks.sh
index 16b9a175..ed694b97 100644
--- a/setup/network-checks.sh
+++ b/setup/network-checks.sh
@@ -3,15 +3,15 @@
# the rest of the system setup so we may not yet have things installed.
apt_get_quiet install bind9-host sed netcat-openbsd
-# Stop if the PRIMARY_HOSTNAME is listed in the Spamhaus Domain Block List.
+# Stop if the BOX_HOSTNAME is listed in the Spamhaus Domain Block List.
# The user might have chosen a name that was previously in use by a spammer
# and will not be able to reliably send mail. Do this after any automatic
# choices made above.
-if host "$PRIMARY_HOSTNAME.dbl.spamhaus.org" > /dev/null; then
+if host "$BOX_HOSTNAME.dbl.spamhaus.org" > /dev/null; then
echo
- echo "The hostname you chose '$PRIMARY_HOSTNAME' is listed in the"
+ echo "The hostname you chose '$BOX_HOSTNAME' is listed in the"
echo "Spamhaus Domain Block List. See http://www.spamhaus.org/dbl/"
- echo "and http://www.spamhaus.org/query/domain/$PRIMARY_HOSTNAME."
+ echo "and http://www.spamhaus.org/query/domain/$BOX_HOSTNAME."
echo
echo "You will not be able to send mail using this domain name, so"
echo "setup cannot continue."
diff --git a/setup/nextcloud.sh b/setup/nextcloud.sh
index 496ca0c0..9a750283 100755
--- a/setup/nextcloud.sh
+++ b/setup/nextcloud.sh
@@ -253,7 +253,7 @@ if [ ! -f "$STORAGE_ROOT/owncloud/owncloud.db" ]; then
mkdir -p "$STORAGE_ROOT/owncloud"
# Create an initial configuration file.
- instanceid=oc$(echo "$PRIMARY_HOSTNAME" | sha1sum | fold -w 10 | head -n 1)
+ instanceid=oc$(echo "$BOX_HOSTNAME" | sha1sum | fold -w 10 | head -n 1)
cat > "$STORAGE_ROOT/owncloud/config.php" <", "")
v = re.sub("([\w\W]*?)
", lambda m : "" + strip_indent(m.group(1)) + "
", v)
- v = re.sub(r"(\$?)PRIMARY_HOSTNAME", r"box.yourdomain.com", v)
+ v = re.sub(r"(\$?)BOX_HOSTNAME", r"box.yourdomain.com", v)
v = re.sub(r"\$STORAGE_ROOT", r"$STORE", v)
v = v.replace("`pwd`", "/path/to/mailinabox")