Merge pull request #681 from usrpro/feat-unbound-dns
Unbound DNS as optional service
This commit is contained in:
18
services/unbound/Dockerfile
Normal file
18
services/unbound/Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
||||
FROM python:3-alpine
|
||||
|
||||
RUN apk add --no-cache unbound curl bind-tools \
|
||||
&& pip3 install jinja2 \
|
||||
&& curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.cache \
|
||||
&& chown root:unbound /etc/unbound \
|
||||
&& chmod 775 /etc/unbound \
|
||||
&& apk del --no-cache curl \
|
||||
&& /usr/sbin/unbound-anchor -a /etc/unbound/trusted-key.key | true
|
||||
|
||||
COPY start.py /start.py
|
||||
COPY unbound.conf /unbound.conf
|
||||
|
||||
EXPOSE 53/udp 53/tcp
|
||||
|
||||
CMD /start.py
|
||||
|
||||
HEALTHCHECK CMD dig @127.0.0.1 || exit 1
|
||||
9
services/unbound/start.py
Executable file
9
services/unbound/start.py
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/local/bin/python3
|
||||
|
||||
import jinja2
|
||||
import os
|
||||
|
||||
convert = lambda src, dst: open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ))
|
||||
convert("/unbound.conf", "/etc/unbound/unbound.conf")
|
||||
|
||||
os.execv("/usr/sbin/unbound", ["-c /etc/unbound/unbound.conf"])
|
||||
19
services/unbound/unbound.conf
Normal file
19
services/unbound/unbound.conf
Normal file
@@ -0,0 +1,19 @@
|
||||
server:
|
||||
verbosity: 1
|
||||
interface: 0.0.0.0
|
||||
interface: ::0
|
||||
logfile: /dev/stdout
|
||||
do-ip4: yes
|
||||
do-ip6: yes
|
||||
do-udp: yes
|
||||
do-tcp: yes
|
||||
do-daemonize: no
|
||||
access-control: {{ SUBNET }} allow
|
||||
directory: "/etc/unbound"
|
||||
username: root
|
||||
auto-trust-anchor-file: trusted-key.key
|
||||
root-hints: "/etc/unbound/root.hints"
|
||||
hide-identity: yes
|
||||
hide-version: yes
|
||||
max-udp-size: 4096
|
||||
msg-buffer-size: 65552
|
||||
@@ -29,6 +29,16 @@ services:
|
||||
volumes:
|
||||
- "{{ root }}/certs:/certs"
|
||||
|
||||
{% if resolver_enabled %}
|
||||
resolver:
|
||||
image: mailu/unbound:{{ version }}
|
||||
env_file: {{ env }}
|
||||
restart: always
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: {{ dns }}
|
||||
{% endif %}
|
||||
|
||||
admin:
|
||||
image: mailu/admin:{{ version }}
|
||||
env_file: {{ env }}
|
||||
@@ -58,6 +68,11 @@ services:
|
||||
- "{{ root }}/overrides:/overrides"
|
||||
depends_on:
|
||||
- front
|
||||
{% if resolver_enabled %}
|
||||
- resolver
|
||||
dns:
|
||||
- {{ dns }}
|
||||
{% endif %}
|
||||
|
||||
# Optional services
|
||||
{% if antispam_enabled %}
|
||||
@@ -70,6 +85,11 @@ services:
|
||||
- "{{ root }}/overrides/rspamd:/etc/rspamd/override.d"
|
||||
depends_on:
|
||||
- front
|
||||
{% if resolver_enabled %}
|
||||
- resolver
|
||||
dns:
|
||||
- {{ dns }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if antivirus_enabled %}
|
||||
@@ -78,6 +98,12 @@ services:
|
||||
env_file: {{ env }}
|
||||
volumes:
|
||||
- "{{ root }}/filter:/data"
|
||||
{% if resolver_enabled %}
|
||||
depends_on:
|
||||
- resolver
|
||||
dns:
|
||||
- {{ dns }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if webdav_enabled %}
|
||||
@@ -92,6 +118,12 @@ services:
|
||||
fetchmail:
|
||||
image: mailu/fetchmail:{{ version }}
|
||||
env_file: {{ env }}
|
||||
{% if resolver_enabled %}
|
||||
depends_on:
|
||||
- resolver
|
||||
dns:
|
||||
- {{ dns }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# Webmail
|
||||
@@ -104,3 +136,13 @@ services:
|
||||
depends_on:
|
||||
- imap
|
||||
{% endif %}
|
||||
|
||||
{% if resolver_enabled %}
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: {{ subnet }}
|
||||
{% endif %}
|
||||
|
||||
@@ -25,6 +25,9 @@ SECRET_KEY={{ secret(16) }}
|
||||
# PUBLIC_IPV4= {{ bind4 }} (default: 127.0.0.1)
|
||||
# PUBLIC_IPV6= {{ bind6 }} (default: ::1)
|
||||
|
||||
# Subnet
|
||||
SUBNET={{ subnet }}
|
||||
|
||||
# Main mail domain
|
||||
DOMAIN={{ domain }}
|
||||
|
||||
|
||||
@@ -29,6 +29,15 @@ services:
|
||||
deploy:
|
||||
replicas: 1
|
||||
|
||||
{% if resolver_enabled %}
|
||||
resolver:
|
||||
image: mailu/unbound:{{ version }}
|
||||
env_file: {{ env }}
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: {{ dns }}
|
||||
{% endif %}
|
||||
|
||||
admin:
|
||||
image: mailu/admin:{{ version }}
|
||||
env_file: {{ env }}
|
||||
@@ -63,6 +72,10 @@ services:
|
||||
- "{{ root }}/overrides:/overrides"
|
||||
deploy:
|
||||
replicas: 1
|
||||
{% if resolver_enabled %}
|
||||
dns:
|
||||
- {{ dns }}
|
||||
{% endif %}
|
||||
|
||||
# Optional services
|
||||
{% if antispam_enabled %}
|
||||
@@ -77,6 +90,10 @@ services:
|
||||
- "{{ root }}/overrides/rspamd:/etc/rspamd/override.d"
|
||||
deploy:
|
||||
replicas: 1
|
||||
{% if resolver_enabled %}
|
||||
dns:
|
||||
- {{ dns }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if antivirus_enabled %}
|
||||
@@ -87,6 +104,10 @@ services:
|
||||
- "{{ root }}/filter:/data"
|
||||
deploy:
|
||||
replicas: 1
|
||||
{% if resolver_enabled %}
|
||||
dns:
|
||||
- {{ dns }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if webdav_enabled %}
|
||||
@@ -107,6 +128,10 @@ services:
|
||||
- "{{ root }}/data:/data"
|
||||
deploy:
|
||||
replicas: 1
|
||||
{% if resolver_enabled %}
|
||||
dns:
|
||||
- {{ dns }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if webmail_type != 'none' %}
|
||||
|
||||
@@ -7,6 +7,7 @@ import jinja2
|
||||
import uuid
|
||||
import string
|
||||
import random
|
||||
import ipaddress
|
||||
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
@@ -75,6 +76,7 @@ def build_app(path):
|
||||
def submit():
|
||||
data = flask.request.form.copy()
|
||||
data['uid'] = str(uuid.uuid4())
|
||||
data['dns'] = str(ipaddress.IPv4Network(data['subnet'])[-2])
|
||||
db.set(data['uid'], json.dumps(data))
|
||||
return flask.redirect(flask.url_for('.setup', uid=data['uid']))
|
||||
|
||||
|
||||
@@ -26,6 +26,19 @@ avoid generic all-interfaces addresses like <code>0.0.0.0</code> or <code>::</co
|
||||
pattern="^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$">
|
||||
</div>
|
||||
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" name="resolver_enabled" value="true">
|
||||
Enable unbound resolver
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Subnet</label>
|
||||
<input class="form-control" type="text" name="subnet" required pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))$"
|
||||
value="192.168.0.0/24">
|
||||
</div>
|
||||
|
||||
<p>You server will be available under a main hostname but may expose multiple public
|
||||
hostnames. Every e-mail domain that points to this server must have one of the
|
||||
hostnames in its <code>MX</code> record. Hostnames must be coma-separated.</p>
|
||||
|
||||
@@ -3,9 +3,17 @@
|
||||
and let users access their mailboxes. Mailu has some flexibility in the way
|
||||
you expose it to the world.</p>
|
||||
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" name="resolver_enabled" value="true">
|
||||
Enable unbound resolver
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Subnet</label>
|
||||
<input class="form-control" type="text" name="subnet" required pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))$">
|
||||
<input class="form-control" type="text" name="subnet" required pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))$"
|
||||
value="192.168.0.0/24">
|
||||
</div>
|
||||
|
||||
<p>You server will be available under a main hostname but may expose multiple public
|
||||
|
||||
@@ -6,6 +6,10 @@ services:
|
||||
image: ${DOCKER_ORG:-mailu}/nginx:${VERSION:-local}
|
||||
build: ../core/nginx
|
||||
|
||||
resolver:
|
||||
image: ${DOCKER_ORG:-mailu}/unbound:${VERSION:-local}
|
||||
build: ../services/unbound
|
||||
|
||||
imap:
|
||||
image: ${DOCKER_ORG:-mailu}/dovecot:${VERSION:-local}
|
||||
build: ../core/dovecot
|
||||
|
||||
Reference in New Issue
Block a user