1
0
mirror of https://github.com/mail-in-a-box/mailinabox.git synced 2026-03-12 17:07:23 +01:00

Compare commits

...

26 Commits
v0.05 ... v0.06

Author SHA1 Message Date
Joshua Tauberer
0aa3941832 release v0.06 2015-01-04 15:18:13 -05:00
Joshua Tauberer
fea77e41df Owncloud doesnt't support CARDDAV_SUPPORTS_SYNC
partialy reverts 93a722f; closes #287
2015-01-04 16:04:32 +00:00
Joshua Tauberer
74ef9ab7c5 Merge pull request #288 from fjuan/srv_doc
explain how to add SRV records to DNS zonefile using the API
2015-01-04 09:19:24 -05:00
Francisco de Juan
6499c82d7f explain how to add SRV records to DNS zonefile using the API 2015-01-04 10:23:34 +01:00
Joshua Tauberer
80e97feee2 update CHANGELOG 2015-01-02 23:47:19 +00:00
Joshua Tauberer
fddab5d432 allow the dns api to set srv records
see https://discourse.mailinabox.email/t/create-srv-record-at-the-dns-server/225
2015-01-02 23:39:09 +00:00
Joshua Tauberer
c4e4805160 ensure postfix/postgrey agree on whether to communicate with ipv4 or ipv6
see https://discourse.mailinabox.email/t/postgrey-and-ipv6/227
2015-01-02 23:37:16 +00:00
Joshua Tauberer
c75950125d set dovecot default_process_limit and fs.inotify.max_user_instances to better defaults
See https://discourse.mailinabox.email/t/mailserver-limits/228.
2015-01-02 23:25:52 +00:00
Joshua Tauberer
f141af4b61 status checks: dont die if openssh-server isn't installed
see https://discourse.mailinabox.email/t/local-dns-is-not-working-was-unable-to-check-system-status/165/39
2015-01-02 22:59:29 +00:00
Joshua Tauberer
3d8ea0e6ed mail log scanner: dont assume lines are utf8 2015-01-02 22:49:25 +00:00
H8H
6efeff6fce [Z-Push] Owncloud doesnt't support CARDDAV_SUPPORTS_SYNC, so set it to false 2014-12-29 16:35:47 +01:00
Joshua Tauberer
399f9d9bdf in status checks, clear bind9 cache using rndc rather than restarting bind9 2014-12-26 13:22:14 +00:00
Joshua Tauberer
2b76fd299e admin: ensure multiple concurrent api calls dont confuse the ajax loading indicator (track number of open requets, stop fade animation when it is time to hide) 2014-12-21 22:47:11 +00:00
Joshua Tauberer
90592bb157 add a control panel for setting custom dns records so that we dont have to use the api manually 2014-12-21 11:31:24 -05:00
Joshua Tauberer
5cf38b950a bump ownCloud to 7.0.4; fixes #283 2014-12-12 01:00:35 +00:00
Joshua Tauberer
3bc5361491 Merge pull request #282 from m4rcs/master
Fix NS status check - should sort on both ends of the comparison
2014-12-09 11:17:30 -05:00
Marc Schiller
c3a7e3413b Fixed a small status check bug, where secondary dns server check fails misleadingly. 2014-12-09 12:40:32 +01:00
Joshua Tauberer
d390bfb215 indicate in the admin when a multi-domain or wildcard certificate is in use 2014-12-05 14:43:52 -05:00
Joshua Tauberer
ceba53f1c4 explain how to install a multi-domain or wildcard ssl cert; if one is installed, the Replace Cert button in the admin for non-primary domains should not replace the cert on the primary domain 2014-12-05 14:25:14 -05:00
Joshua Tauberer
be59bcd47d for .fund domains use RSASHA256 DNSSEC keys 2014-12-05 12:03:21 -05:00
Joshua Tauberer
cfe0fa912a add a 'redirects' feature in web/custom.yaml 2014-12-05 12:03:21 -05:00
Joshua Tauberer
31d6128a2b nginx: explicitly listen on both ipv4 and ipv6 (works even if ipv6 isn't present) 2014-11-30 14:41:30 +00:00
Joshua Tauberer
82cf5b72e4 simplify some output in the work-in-progress mail log scanner 2014-11-30 14:41:30 +00:00
Joshua Tauberer
8ec8c42441 Merge pull request #275 from grepwood/master
add `apt-get install sudo`
2014-11-25 10:39:13 -05:00
Michael Dec
7e36e1fd90 added sudo to the list
not all setups have it and the miab installer depends on it
2014-11-25 15:36:34 +00:00
Joshua Tauberer
a7710e9058 dns.resolver.query treats hostnames as relative names if they don't end in a period
Relative hostnames have a fall-back lookup with the machine's hostname appended, which makes no sense. Add a period, e.g. "my.hostname.com" => "my.hostname.com.", to prevent that.

This caused false positive Spamhaus checks. Fixes #185.
2014-11-21 15:16:59 +00:00
17 changed files with 298 additions and 33 deletions

View File

@@ -1,6 +1,32 @@
CHANGELOG
=========
v0.06 (January 4, 2015)
-----------------------
Mail:
* Set better default system limits to accommodate boxes handling mail for 20+ users.
Contacts/calendar:
* Update to ownCloud to 7.0.4.
* Contacts syncing via ActiveSync wasn't working.
Control panel:
* New control panel for setting custom DNS settings (without having to use the API).
* Status checks showed a false positive for Spamhause blacklists and for secondary DNS in some cases.
* Status checks would fail to load if openssh-sever was not pre-installed, but openssh-server is not required.
* The local DNS cache is cleared before running the status checks using 'rncd' now rather than restarting 'bind9', which should be faster and wont interrupt other services.
* Multi-domain and wildcard certificate can now be installed through the control panel.
* The DNS API now allows the setting of SRV records.
Misc:
* IPv6 configuration error in postgrey, nginx.
* Missing dependency on sudo.
v0.05 (November 18, 2014)
-------------------------

View File

@@ -13,6 +13,7 @@ server {
# The secure HTTPS server.
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name $HOSTNAME;

View File

@@ -14,7 +14,7 @@ define('CARDDAV_DEFAULT_PATH', '/carddav/addressbooks/%u/contacts/'); /* subdire
define('CARDDAV_GAL_PATH', ''); /* readonly, searchable, not syncd */
define('CARDDAV_GAL_MIN_LENGTH', 5);
define('CARDDAV_CONTACTS_FOLDER_NAME', '%u Addressbook');
define('CARDDAV_SUPPORTS_SYNC', true);
define('CARDDAV_SUPPORTS_SYNC', false);
// If the CardDAV server supports the FN attribute for searches
// DAViCal supports it, but SabreDav, Owncloud and SOGo don't

View File

@@ -172,6 +172,12 @@ def mail_domains():
# DNS
@app.route('/dns/zones')
@authorized_personnel_only
def dns_zones():
from dns_update import get_dns_zones
return json_response([z[0] for z in get_dns_zones(env)])
@app.route('/dns/update', methods=['POST'])
@authorized_personnel_only
def dns_update():
@@ -196,6 +202,17 @@ def dns_set_secondary_nameserver():
except ValueError as e:
return (str(e), 400)
@app.route('/dns/set')
@authorized_personnel_only
def dns_get_records():
from dns_update import get_custom_dns_config, get_custom_records
additional_records = get_custom_dns_config(env)
records = get_custom_records(None, additional_records, env)
return json_response([{
"qname": r[0],
"rtype": r[1],
"value": r[2],
} for r in records])
@app.route('/dns/set/<qname>', methods=['POST'])
@app.route('/dns/set/<qname>/<rtype>', methods=['POST'])

View File

@@ -254,10 +254,13 @@ def build_zone(domain, all_domains, additional_records, env, is_zone=True):
def get_custom_records(domain, additional_records, env):
for qname, value in additional_records.items():
# Is this record for the domain or one of its subdomains?
if qname != domain and not qname.endswith("." + domain): continue
# If `domain` is None, return records for all domains.
if domain is not None and qname != domain and not qname.endswith("." + domain): continue
# Turn the fully qualified domain name in the YAML file into
# our short form (None => domain, or a relative QNAME).
# our short form (None => domain, or a relative QNAME) if
# domain is not None.
if domain is not None:
if qname == domain:
qname = None
else:
@@ -490,7 +493,7 @@ zone:
# Get the IP address of the nameserver by resolving it.
hostname = additional_records.get("_secondary_nameserver")
resolver = dns.resolver.get_default_resolver()
response = dns.resolver.query(hostname, "A")
response = dns.resolver.query(hostname+'.', "A")
ipaddr = str(response[0])
nsdconf += """\tnotify: %s NOKEY
provide-xfr: %s NOKEY
@@ -511,8 +514,12 @@ zone:
########################################################################
def dnssec_choose_algo(domain, env):
if domain.endswith(".email") or domain.endswith(".guide"):
# At least at GoDaddy, this is the only algorithm supported.
if '.' in domain and domain.rsplit('.')[-1] in \
("email", "guide", "fund"):
# At GoDaddy, RSASHA256 is the only algorithm supported
# for .email and .guide.
# A variety of algorithms are supported for .fund. This
# is preferred.
return "RSASHA256"
# For any domain we were able to sign before, don't change the algorithm
@@ -662,7 +669,7 @@ def set_custom_dns_record(qname, rtype, value, env):
v = ipaddress.ip_address(value)
if rtype == "A" and not isinstance(v, ipaddress.IPv4Address): raise ValueError("That's an IPv6 address.")
if rtype == "AAAA" and not isinstance(v, ipaddress.IPv6Address): raise ValueError("That's an IPv4 address.")
elif rtype in ("CNAME", "TXT"):
elif rtype in ("CNAME", "TXT", "SRV"):
# anything goes
pass
else:

View File

@@ -18,8 +18,9 @@ def scan_mail_log(logger, env):
for fn in ('/var/log/mail.log.1', '/var/log/mail.log'):
if not os.path.exists(fn): continue
with open(fn) as log:
with open(fn, 'rb') as log:
for line in log:
line = line.decode("utf8", errors='replace')
scan_mail_log_line(line.strip(), collector)
if collector["imap-logins"]:
@@ -96,6 +97,21 @@ def scan_postfix_smtpd_line(date, log, collector):
message, sender, recipient = m.groups()
if recipient in collector["real_mail_addresses"]:
# only log mail to real recipients
# skip this, is reported in the greylisting report
if "Recipient address rejected: Greylisted" in message:
return
# simplify this one
m = re.search(r"Client host \[(.*?)\] blocked using zen.spamhaus.org; (.*)", message)
if m:
message = "ip blocked: " + m.group(2)
# simplify this one too
m = re.search(r"Sender address \[.*@(.*)\] blocked using dbl.spamhaus.org; (.*)", message)
if m:
message = "domain blocked: " + m.group(2)
collector["rejected-mail"].setdefault(recipient, []).append( (date, sender, message) )

View File

@@ -18,8 +18,8 @@ from mailconfig import get_mail_domains, get_mail_aliases
from utils import shell, sort_domains, load_env_vars_from_file
def run_checks(env, output):
# clear the DNS cache so our DNS checks are most up to date
shell('check_call', ["/usr/sbin/service", "bind9", "restart"])
# clear bind9's DNS cache so our DNS checks are up to date
shell('check_call', ["/usr/sbin/rndc", "flush"])
# perform checks
env["out"] = output
@@ -29,8 +29,17 @@ def run_checks(env, output):
def run_system_checks(env):
env["out"].add_heading("System")
check_ssh_password(env)
check_software_updates(env)
check_system_aliases(env)
check_free_disk_space(env)
# Check that SSH login with password is disabled.
def check_ssh_password(env):
# Check that SSH login with password is disabled. The openssh-server
# package may not be installed so check that before trying to access
# the configuration file.
if not os.path.exists("/etc/ssh/sshd_config"):
return
sshd = open("/etc/ssh/sshd_config").read()
if re.search("\nPasswordAuthentication\s+yes", sshd) \
or not re.search("\nPasswordAuthentication\s+no", sshd):
@@ -41,6 +50,7 @@ def run_system_checks(env):
else:
env['out'].print_ok("SSH disallows password-based login.")
def check_software_updates(env):
# Check for any software package updates.
pkgs = list_apt_updates(apt_update=False)
if os.path.exists("/var/run/reboot-required"):
@@ -52,10 +62,12 @@ def run_system_checks(env):
for p in pkgs:
env['out'].print_line("%s (%s)" % (p["package"], p["version"]))
def check_system_aliases(env):
# Check that the administrator alias exists since that's where all
# admin email is automatically directed.
check_alias_exists("administrator@" + env['PRIMARY_HOSTNAME'], env)
def check_free_disk_space(env):
# Check free disk space.
st = os.statvfs(env['STORAGE_ROOT'])
bytes_total = st.f_blocks * st.f_frsize
@@ -207,10 +219,10 @@ def check_dns_zone(domain, env, dns_zonefiles):
# to do a DNS trace.
custom_dns = get_custom_dns_config(env)
existing_ns = query_dns(domain, "NS")
correct_ns = "; ".join([
correct_ns = "; ".join(sorted([
"ns1." + env['PRIMARY_HOSTNAME'],
custom_dns.get("_secondary_nameserver", "ns2." + env['PRIMARY_HOSTNAME']),
])
]))
if existing_ns.lower() == correct_ns.lower():
env['out'].print_ok("Nameservers are set correctly at registrar. [%s]" % correct_ns)
else:
@@ -347,7 +359,15 @@ def check_web_domain(domain, env):
check_ssl_cert(domain, env)
def query_dns(qname, rtype, nxdomain='[Not Set]'):
resolver = dns.resolver.get_default_resolver()
# Make the qname absolute by appending a period. Without this, dns.resolver.query
# will fall back a failed lookup to a second query with this machine's hostname
# appended. This has been causing some false-positive Spamhaus reports. The
# reverse DNS lookup will pass a dns.name.Name instance which is already
# absolute so we should not modify that.
if isinstance(qname, str):
qname += "."
# Do the query.
try:
response = dns.resolver.query(qname, rtype)
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
@@ -514,7 +534,7 @@ def check_certificate(domain, ssl_certificate, ssl_private_key):
return ("SELF-SIGNED", None)
elif retcode != 0:
if "unable to get local issuer certificate" in verifyoutput:
return ("The certificate is missing an intermediate chain or the intermediate chain is incorrect or incomplete.", None)
return ("The certificate is missing an intermediate chain or the intermediate chain is incorrect or incomplete. (%s)" % verifyoutput, None)
# There is some unknown problem. Return the `openssl verify` raw output.
return ("There is a problem with the SSL certificate.", verifyoutput.strip())

View File

@@ -1,4 +1,7 @@
<style>
#custom-dns-current td.long {
word-break: break-all;
}
</style>
<h2>Custom DNS</h2>
@@ -7,6 +10,60 @@
<p>It is possible to set custom DNS records on domains hosted here.</p>
<h3>Set Custom DNS Records</h3>
<p>You can set additional DNS records, such as if you have a website running on another server, to add DKIM records for external mail providers, or for various confirmation-of-ownership tests.</p>
<form class="form-horizontal" role="form" onsubmit="do_set_custom_dns(); return false;">
<div class="form-group">
<label for="customdnsQname" class="col-sm-1 control-label">Name</label>
<div class="col-sm-10">
<table style="max-width: 400px">
<tr><td>
<input type="text" class="form-control" id="customdnsQname" placeholder="subdomain">
</td><td style="padding: 0 1em; font-weight: bold;">.</td><td>
<select id="customdnsZone" class="form-control"> </select>
</td></tr></table>
<div class="text-info" style="margin-top: .5em">Leave the left field blank to set a record on the chosen domain name, or enter a subdomain.</div>
</div>
</div>
<div class="form-group">
<label for="customdnsType" class="col-sm-1 control-label">Type</label>
<div class="col-sm-10">
<select id="customdnsType" class="form-control" style="max-width: 400px" onchange="show_customdns_rtype_hint()">
<option value="A" data-hint="Enter an IPv4 address (i.e. a dotted quad, such as 123.456.789.012).">A (IPv4 address)</option>
<option value="AAAA" data-hint="Enter an IPv6 address.">AAAA (IPv6 address)</option>
<option value="CNAME" data-hint="Enter another domain name followed by a period at the end (e.g. mypage.github.io.).">CNAME (DNS forwarding)</option>
<option value="TXT" data-hint="Enter arbitrary text.">TXT (text record)</option>
</select>
</div>
</div>
<div class="form-group">
<label for="customdnsValue" class="col-sm-1 control-label">Value</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="customdnsValue" placeholder="">
<div id="customdnsTypeHint" class="text-info" style="margin-top: .5em"></div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-1 col-sm-11">
<button type="submit" class="btn btn-primary">Set Record</button>
</div>
</div>
</form>
<table id="custom-dns-current" class="table" style="width: auto; display: none">
<thead>
<th>Domain Name</th>
<th>Record Type</th>
<th>Value</th>
<th></th>
</thead>
<tbody>
<tr><td colspan="4">Loading...</td></tr>
</tbody>
</table>
<h3>Using a Secondary Nameserver</h3>
<p>If your TLD requires you to have two separate nameservers, you can either set up a secondary (aka &ldquo;slave&rdquo;) nameserver or, alternatively, set up <a href="#" onclick="return show_panel('external_dns')">external DNS</a> and ignore the DNS server on this box. If you choose to use a seconday/slave nameserver, you must find a seconday/slave nameserver service provider. Your domain name registrar or virtual cloud provider may provide this service for you. Once you set up the seconday/slave nameserver service, enter the hostname of <em>their</em> secondary nameserver:</p>
@@ -30,6 +87,7 @@
</div>
</form>
<h3>Custom DNS API</h3>
<p>Use your box&rsquo;s DNS API to set custom DNS records on domains hosted here. For instance, you can create your own dynamic DNS service.</p>
@@ -66,6 +124,12 @@ curl -d "" --user me@mydomain.com:###### https://{{hostname}}/admin/dns/set/bar.
# sets a TXT record using the alternate value syntax
curl -d "value=something%20here" --user me@mydomain.com:###### https://{{hostname}}/admin/dns/set/foo.mydomain.com/txt
# sets a <a href="http://en.wikipedia.org/wiki/SRV_record">SRV record</a> for the "service" and "protocol" hosted on "target" server
curl -d "" --user me@mydomain.com:###### https://{{hostname}}/admin/dns/set/_service._protocol.{{hostname}}/srv/"priority weight port target"
# sets a SRV record using the value syntax
curl -d "value=priority weight port target" --user me@mydomain.com:###### https://{{hostname}}/admin/dns/set/_service._protocol.host/srv
</pre>
<script>
@@ -78,6 +142,52 @@ function show_custom_dns() {
$('#secondarydnsHostname').val(data.hostname ? data.hostname : '');
$('#secondarydns-clear-instructions').toggle(data.hostname != null);
});
api(
"/dns/zones",
"GET",
{ },
function(data) {
$('#customdnsZone').text('');
for (var i = 0; i < data.length; i++) {
$('#customdnsZone').append($('<option/>').text(data[i]));
}
});
show_current_custom_dns();
show_customdns_rtype_hint();
}
function show_current_custom_dns() {
api(
"/dns/set",
"GET",
{ },
function(data) {
if (data.length > 0)
$('#custom-dns-current').fadeIn();
else
$('#custom-dns-current').fadeOut();
$('#custom-dns-current').find("tbody").text('');
for (var i = 0; i < data.length; i++) {
var tr = $("<tr/>");
$('#custom-dns-current').find("tbody").append(tr);
tr.attr('data-qname', data[i].qname);
tr.attr('data-rtype', data[i].rtype);
tr.append($('<td class="long"/>').text(data[i].qname));
tr.append($('<td/>').text(data[i].rtype));
tr.append($('<td class="long"/>').text(data[i].value));
tr.append($('<td>[<a href="#" onclick="return delete_custom_dns_record(this)">delete</a>]</td>'));
}
});
}
function delete_custom_dns_record(elem) {
var qname = $(elem).parents('tr').attr('data-qname');
var rtype = $(elem).parents('tr').attr('data-rtype');
do_set_custom_dns(qname, rtype, "__delete__");
return false;
}
function do_set_secondary_dns() {
@@ -96,4 +206,34 @@ function do_set_secondary_dns() {
show_modal_error("Secondary DNS", $("<pre/>").text(err));
});
}
function do_set_custom_dns(qname, rtype, value) {
if (!qname) {
if ($('#customdnsQname').val() != '')
qname = $('#customdnsQname').val() + '.' + $('#customdnsZone').val();
else
qname = $('#customdnsZone').val();
rtype = $('#customdnsType').val();
value = $('#customdnsValue').val();
}
api(
"/dns/set/" + qname + "/" + rtype,
"POST",
{
value: value
},
function(data) {
if (data == "") return; // nothing updated
show_modal_error("Custom DNS", $("<pre/>").text(data));
show_current_custom_dns();
},
function(err) {
show_modal_error("Custom DNS", $("<pre/>").text(err));
});
}
function show_customdns_rtype_hint() {
$('#customdnsTypeHint').text($("#customdnsType").find('option:selected').attr('data-hint'));
}
</script>

View File

@@ -100,7 +100,7 @@
<li><a href="#ssl" onclick="return show_panel(this);">SSL Certificates</a></li>
<li><a href="#system_backup" onclick="return show_panel(this);">Backup Status</a></li>
<li class="divider"></li>
<li class="dropdown-header">Super Advanced Options</li>
<li class="dropdown-header">Advanced Options</li>
<li><a href="#custom_dns" onclick="return show_panel(this);">Custom DNS</a></li>
<li><a href="#external_dns" onclick="return show_panel(this);">External DNS</a></li>
</ul>
@@ -264,12 +264,13 @@ function show_modal_confirm(title, question, verb, yes_callback, cancel_callback
$('#global_modal').modal({});
}
var is_ajax_loading = false;
var ajax_num_executing_requests = 0;
function ajax(options) {
setTimeout("if (is_ajax_loading) $('#ajax_loading_indicator').fadeIn()", 100);
setTimeout("if (ajax_num_executing_requests > 0) $('#ajax_loading_indicator').fadeIn()", 100);
function hide_loading_indicator() {
is_ajax_loading = false;
$('#ajax_loading_indicator').hide();
ajax_num_executing_requests--;
if (ajax_num_executing_requests == 0)
$('#ajax_loading_indicator').stop().hide(); // stop() prevents an ongoing fade from causing the thing to be shown again after this call
}
var old_success = options.success;
var old_error = options.error;
@@ -287,7 +288,7 @@ function ajax(options) {
else
old_error(jqxhr.responseText, jqxhr);
};
is_ajax_loading = true;
ajax_num_executing_requests++;
$.ajax(options);
}

View File

@@ -18,6 +18,8 @@
</tbody>
</table>
<p>Advanced:<br>Install a multi-domain or wildcard certificate for the <code>{{hostname}}</code> domain to have it automatically applied to any domains it is valid for.</p>
<h3 id="ssl_install_header">Install SSL Certificate</h3>
<p>There are many places where you can get a free or cheap SSL certificate. We recommend <a href="https://www.namecheap.com/security/ssl-certificates/domain-validation.aspx">Namecheap&rsquo;s $9 certificate</a> or <a href="https://www.startssl.com/">StartSSL&rsquo;s free express lane</a>.</p>

View File

@@ -115,6 +115,8 @@ def make_domain_config(domain, template, template_for_primaryhost, env):
yaml = yaml[domain]
for path, url in yaml.get("proxies", {}).items():
nginx_conf += "\tlocation %s {\n\t\tproxy_pass %s;\n\t}\n" % (path, url)
for path, url in yaml.get("redirects", {}).items():
nginx_conf += "\trewrite %s %s permanent;\n" % (path, url)
# Add in any user customizations in the includes/ folder.
nginx_conf_custom_include = os.path.join(env["STORAGE_ROOT"], "www", safe_domain_name(domain) + ".conf")
@@ -133,7 +135,7 @@ def get_web_root(domain, env, test_exists=True):
if os.path.exists(root) or not test_exists: break
return root
def get_domain_ssl_files(domain, env):
def get_domain_ssl_files(domain, env, allow_shared_cert=True):
# What SSL private key will we use? Allow the user to override this, but
# in many cases using the same private key for all domains would be fine.
# Don't allow the user to override the key for PRIMARY_HOSTNAME because
@@ -157,7 +159,7 @@ def get_domain_ssl_files(domain, env):
# But we can be smart and reuse the main SSL certificate if is has
# a Subject Alternative Name matching this domain. Don't do this if
# the user has uploaded a different private key for this domain.
if not ssl_key_is_alt:
if not ssl_key_is_alt and allow_shared_cert:
from status_checks import check_certificate
if check_certificate(domain, ssl_certificate_primary, None)[0] == "OK":
ssl_certificate = ssl_certificate_primary
@@ -223,7 +225,7 @@ def install_cert(domain, ssl_cert, ssl_chain, env):
# Do validation on the certificate before installing it.
from status_checks import check_certificate
ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env)
ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env, allow_shared_cert=False)
cert_status, cert_status_details = check_certificate(domain, fn, ssl_key)
if cert_status != "OK":
if cert_status == "SELF-SIGNED":
@@ -261,7 +263,11 @@ def get_web_domains_info(env):
return ("danger", "No Certificate Installed")
cert_status, cert_status_details = check_certificate(domain, ssl_certificate, ssl_key)
if cert_status == "OK":
if domain == env['PRIMARY_HOSTNAME'] or ssl_certificate != get_domain_ssl_files(env['PRIMARY_HOSTNAME'], env)[1]:
return ("success", "Signed & valid. " + cert_status_details)
else:
# This is an alternate domain but using the same cert as the primary domain.
return ("success", "Signed & valid. Using multi/wildcard certificate of %s." % env['PRIMARY_HOSTNAME'])
elif cert_status == "SELF-SIGNED":
return ("warning", "Self-signed. Get a signed certificate to stop warnings.")
else:

View File

@@ -7,7 +7,7 @@
#########################################################
if [ -z "$TAG" ]; then
TAG=v0.05
TAG=v0.06
fi
# Are we running as root?

View File

@@ -52,6 +52,10 @@ mkdir -p "$STORAGE_ROOT/dns/dnssec";
#
# * .email
# * .guide
#
# Supports `RSASHA256` (and defaulting to this)
#
# * .fund
FIRST=1 #NODOC
for algo in RSASHA1-NSEC3-SHA1 RSASHA256; do

View File

@@ -26,6 +26,23 @@ apt_install \
# The `dovecot-imapd` and `dovecot-lmtpd` packages automatically enable IMAP and LMTP protocols.
# Set basic daemon options.
# The `default_process_limit` is 100, which constrains the total number
# of active IMAP connections (at, say, 5 open connections per user that
# would be 20 users). Set it to 250 times the number of cores this
# machine has, so on a two-core machine that's 500 processes/100 users).
tools/editconf.py /etc/dovecot/conf.d/10-master.conf \
default_process_limit=$(echo "`nproc` * 250" | bc)
# The inotify `max_user_instances` default is 128, which constrains
# the total number of watched (IMAP IDLE push) folders by open connections.
# See http://www.dovecot.org/pipermail/dovecot/2013-March/088834.html.
# A reboot is required for this to take effect (which we don't do as
# as a part of setup). Test with `cat /proc/sys/fs/inotify/max_user_instances`.
tools/editconf.py /etc/sysctl.conf \
fs.inotify.max_user_instances=1024
# Set the location where we'll store user mailboxes. '%d' is the domain name and '%n' is the
# username part of the user's email address. We'll ensure that no bad domains or email addresses
# are created within the management daemon.

View File

@@ -160,6 +160,11 @@ tools/editconf.py /etc/postfix/main.cf \
smtpd_sender_restrictions="reject_non_fqdn_sender,reject_unknown_sender_domain,reject_rhsbl_sender dbl.spamhaus.org" \
smtpd_recipient_restrictions=permit_sasl_authenticated,permit_mynetworks,"reject_rbl_client zen.spamhaus.org",reject_unlisted_recipient,"check_policy_service inet:127.0.0.1:10023"
# Postfix connects to Postgrey on the 127.0.0.1 interface specifically. Ensure that
# Postgrey listens on the same interface (and not IPv6, for instance).
tools/editconf.py /etc/default/postgrey \
POSTGREY_OPTS=\"--inet=127.0.0.1:10023\"
# Increase the message size limit from 10MB to 128MB.
# The same limit is specified in nginx.conf for mail submitted via webmail and Z-Push.
tools/editconf.py /etc/postfix/main.cf \

View File

@@ -15,7 +15,7 @@ apt_install \
apt-get purge -qq -y owncloud*
# Install ownCloud from source of this version:
owncloud_ver=7.0.3
owncloud_ver=7.0.4
# Check if ownCloud dir exist, and check if version matches owncloud_ver (if either doesn't - install/upgrade)
if [ ! -d /usr/local/lib/owncloud/ ] \

View File

@@ -19,9 +19,12 @@ hide_output apt-get -y upgrade
# * unattended-upgrades: Apt tool to install security updates automatically.
# * ntp: keeps the system time correct
# * fail2ban: scans log files for repeated failed login attempts and blocks the remote IP at the firewall
# * sudo: allows privileged users to execute commands as root without being root
# * coreutils: includes `nproc` tool to report number of processors
# * bc: allows us to do math to compute sane defaults
apt_install python3 python3-dev python3-pip \
wget curl \
wget curl sudo coreutils bc \
haveged unattended-upgrades ntp fail2ban
# Allow apt to install system updates automatically every day.