tl;dr - Setting up Mailu on Kubernetes was pretty simple, once TLS and Ingress are all set up. It’s just a matter of configuring the ingress controller, adding the right ingress resources, and making the right resource configuration for Mailu. I encounter some (mostly self-inflicted) issues along the way, but you can find the resource config that worked for me at the end.
Mailu has a new kubernetes setup stuff and accompanying documentation, check it out! It looks like there's still a PR out for finalizing the documentation (markdown -> RST it looks like) but I think that will be the best bet going forward (as I'm not actively maintaining this blog post... except for updates like this).
Up until now on every VPS that I’ve purchased/used, I’ve manually set up Postfix and Dovecot and all the related services on the machine, navigating documentation, setting up additional users, adding virutal mailboxes, etc. While I valued the experience (though most of it was reading thorugh documentation/guides), it felt kind of dirty. Why did it take so much finangling to get to a mail set up that wasn’t bad? Why wasn’t there some easy-to-use interface to configure Postfix with some intelligble and clear settings names? I don’t fault the Postfix project for being what it is (it’s a tremendous piece of software that’s been offered to me completely for free), but I often longed for a higher level wrapper around postfix + dovecot combo that I could trust.
There are lots of ways I could automate/manage this little bit of complexity, but this nail is looking like a perfect fit for the containers + Kubernetes hammer. At the high level, I probably just need to run some docker containers (like postfix and dovecot and whatever else) and set aside some hostPath
volumes for Kubernetes to use, and make sure everything is hooked up the right way.
There are a few options for “pre-packaged postfix” (if you can call it that), here are a few of them:
NOTE If you’re looking for more awesome self-hosted stuff, the awesome-selfhosted repo is pretty amazing.
These options vary somewhat – mailinabox from what I can tell basically just installs everything and does it well enough that you don’t have to touch it again. mailcow and mailu offer what mailinabox offers plus a web UI to manage your configuration and do things to the postfix installation – managing accounts, etc.
Mailu (previously known as Freeposte.io) was actually one of the first solutions I came across and with their emphasis on use of containers I was pretty happy to choose them.
Unfortunately, the README instructions for Mailu only mentioned Docker Compose, but luckily a brave soul posted their kubernetes resource configuration so I had a place to start. Here’s the configuration in case it gets lost to time:
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: default
labels:
app: mailu
role: mail
tier: backend
spec:
selector:
app: mailu
role: mail
tier: backend
ports:
- name: redis
port: 6379
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: antispam
namespace: default
labels:
app: mailu
role: mail
tier: backend
spec:
selector:
app: mailu
role: mail
tier: backend
ports:
- name: antispam
port: 11333
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: antivirus
namespace: default
labels:
app: mailu
role: mail
tier: backend
spec:
selector:
app: mailu
role: mail
tier: backend
ports:
- name: antivirus
port: 3310
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: imap
namespace: default
labels:
app: mailu
role: mail
tier: backend
spec:
selector:
app: mailu
role: mail
tier: backend
ports:
- name: imap-auth
port: 2102
protocol: TCP
- name: imap-transport
port: 2525
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: mailu
namespace: default
labels:
app: mailu
role: mail
tier: backend
spec:
selector:
app: mailu
role: mail
tier: backend
ports:
- name: http
port: 80
protocol: TCP
- name: imap-default
port: 143
protocol: TCP
- name: imap-ssl
port: 993
protocol: TCP
- name: sieve
port: 4190
protocol: TCP
- name: smtp
port: 25
protocol: TCP
- name: smtp-ssl
port: 465
protocol: TCP
- name: smtp-starttls
port: 587
protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mailu
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
app: mailu
role: mail
tier: backend
spec:
containers:
- name: admin
image: mailu/admin:stable
imagePullPolicy: Always
env:
- name : DOMAIN
value : example.com
- name : HOSTNAME
value : mail.example.com
- name : POSTMASTER
value : admin
- name : SECRET_KEY
value : ChangeMeChangeMe
- name : DEBUG
value : "True"
volumeMounts:
- name: maildata
mountPath: /data
- name: dkim
mountPath: /dkim
- name: certs
mountPath: /certs
readOnly: true
# - name: docker
# mountPath: /var/run/docker.sock
# readOnly: true
ports:
- name: http
containerPort: 80
protocol: TCP
- name: redis
image: redis:latest
imagePullPolicy: Always
volumeMounts:
- mountPath: /data
name: redisdata
ports:
- containerPort: 6379
name: redis
protocol: TCP
- name: imap
image: mailu/dovecot:stable
imagePullPolicy: Always
env:
- name : DOMAIN
value : example.com
- name : HOSTNAME
value : mail.example.com
- name : POSTMASTER
value : admin
volumeMounts:
- mountPath: /data
name: maildata
- mountPath: /mail
name: mailstate
- mountPath: /overrides
name: overrides
- mountPath: /certs
name: certs
readOnly: true
ports:
- containerPort: 2102
name: imap-auth
protocol: TCP
- containerPort: 2525
name: imap-transport
protocol: TCP
- containerPort: 143
name: imap-default
protocol: TCP
- containerPort: 993
name: imap-ssl
protocol: TCP
- containerPort: 4190
name: sieve
protocol: TCP
- name: smtp
image: mailu/postfix:stable
imagePullPolicy: Always
env:
- name : DOMAIN
value : example.com
- name : HOSTNAME
value : mail.example.com
- name : MESSAGE_SIZE_LIMIT
value : "50000000"
- name : RELAYHOST
value : ""
volumeMounts:
- mountPath: /data
name: maildata
- mountPath: /overrides
name: overrides
- mountPath: /certs
name: certs
readOnly: true
ports:
- name: smtp
containerPort: 25
protocol: TCP
- name: smtp-ssl
containerPort: 465
protocol: TCP
- name: smtp-starttls
containerPort: 587
protocol: TCP
- name: milter
image: mailu/rmilter:stable
imagePullPolicy: Always
ports:
- name: milter
containerPort: 9900
protocol: TCP
volumeMounts:
- name: maildata
mountPath: /data
- name: dkim
mountPath: /dkim
- name: overrides
mountPath: /overrides
- name: certs
mountPath: /certs
readOnly: true
- name: antispam
image: mailu/rspamd:stable
imagePullPolicy: Always
ports:
- name: antispam
containerPort: 11333
protocol: TCP
volumeMounts:
- name: filter
mountPath: /var/lib/rspamd
- name: antivirus
image: mailu/clamav:stable
imagePullPolicy: Always
ports:
- name: antivirus
containerPort: 3310
protocol: TCP
volumeMounts:
- name: filter
mountPath: /data
volumes:
- name: redisdata
emptyDir: {}
- name: maildata
emptyDir: {}
- name: mailstate
emptyDir: {}
- name: overrides
emptyDir: {}
- name: dkim
emptyDir: {}
- name: filter
emptyDir: {}
- name: certs
secret:
items:
- key: tls.crt
path: cert.pem
- key: tls.key
path: key.pem
secretName: mail-example-com-letsencrypt-ssl
# - name: docker
# hostPath:
# path: /var/run/docker.sock
imagePullSecrets:
- name: myregistrykey
My first step was to copy this resource configuration that was posted and try my best to understand it – this meant going through all the resources, trying to figure out what they were for and what they were meant to accomplish, figuring how the milter
might speak to the mailu/postfix
image, etc. Outside of removing the lines around the registry pull key (since the official docker repo is fine for this), the configuration was largely usable.
Next step was to create directories for all the important information, along with updating the name of the secret that it was going to use for certs. Since I already set up TLS/SSL certs, I knew the secret name I wanted to use was letsencrypt-certs-all
. Note that the SSL setup is required, the imap
container will fail to start if it can’t load the cert files.
After changing all the information, I was able to create the resources successfully. I am definitely happy about how easy it was – the container hype (and kubernetes hype) are paying off wonderfully.
Now that the container seems to be running properly (at least according to kubectl get pods
and kubectl describe pod
), it’s time to kubectl port-forward
into the mailu admin container and start checking out/configuring things. Once port forwarding in I was greeted with the login screen:
But a bit of a problem – I don’t remember creating a user…
Looking at the Mailu setup guide showed me that there was more setup I needed to do, particularly running docker-compose run --rm admin python manage.py admin root example.net password
. Of course, that needs to be run from inside the mailu admin
container, so you can either kubectl exec
that command directly or kubectl exec -it <container> -- /bin/bash
to shell in and do it there.
Once I’m logged in, I can see the main Mailu interface:
Great success! One thing that immediately sticks out to me is the Mail Domains page – one of the things I’ve found somewhat difficult was managing virtual domains in Postfix, it’s awesome that they’ve offered a UI for that (though maybe that’s a pretty obvious feature a mail administrator would want).
Now that the admin interface is working properly, I need to add a few things to make sure it’s accessible, and the mail server itself is accessible from the outside world via SMTP/SMTPS, IMAPS, and the associated ports. You guessed it, it’s time to set up some Kubernetes Ingress Resources!
Here’s my first attempt at the ingress for the admin interface:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: mailu-admin-ing
spec:
tls:
- hosts:
- "mail.example.com"
secretName: letsencrypt-certs-all
rules:
- host: "mail.example.com"
http:
paths:
- path: "/admin"
backend:
serviceName: mailu
servicePort: 80
First quick step was to test the ingress to make sure it worked, and it did!
After checking the admin interface I also ran upon the DKIM generation features that Mailu comes with and was super impressed! Yet another thing I don’t have to go through the trouble of setting up on my own.
The NGINX Ingress controller I’ve been using up until this point is (obviously) using NGINX under the covers, so making sure email gets to the postfix service/pod/underlying docker container means that I need to forward email traffic through NGINX. I’ve actually never dealt with trying to put email traffic through NGINX before, so this prompted some internet searching on how to do email stuff with NGINX – I assumed there might be a bunch of different configuration variables/keywords I needed to use.
Turns out it’s not so big a deal, since it’s all TCP in the end, I just needed the general TCP ingress/loadbalancing mentioned in the README for the NGINX ingress controller.
This meant updating my Kubernetes system-level resource spec for the NGINX ingress controller:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-ingress-conf
namespace: kube-system
labels:
k8s-app: nginx-ingress-controller
data:
587: "default/mailu:587"
993: "default/mailu:993"
465: "default/mailu:465"
After applying the the updated Kubernetes ConfigMap however, using nmap
I could see that the port still wasn’t open/listening from my home computer. This small issue boiled down to making sure the right ports were exposed on the actual containers (for some reason they weren’t), so one more change to the Mailu resource config and I was good to go.
At this point now, the Admin interface as well as the actual mail server (the containers that are running postfix
, etc) are accessible from the outside world. Now it’s time to actually try sending emails and doing stuff.
If you’ve followed along with this blog you’ll know that I’ve only recently discovered the wonders and value of dedicated hosting (over VPS providers) – so I was curious to see just how much of the massive server Iv’e rented is now in use. To access my cAdvisor I ran a quick kubectl port-forward kube-apiserver-<port of your server> 5000:4194 -n kube-system
.
I found that about 30% of the RAM was being used, and just about no CPU, so I was pretty happy to see that. At this point theres a bunch of things running on the server at this point (all under Kubernetes), but I was glad to see that I wasn’t anywhere close to maxing it out. If you haven’t considered dedicated hosting, check out the Hetzner robot auction – it’s pretty awesome.
So now that the postfix server is reachable from the world wide web, it’s time to see if I can actually log in and use my mail server for what I want it for: sending emails.
Mozilla Thunderbird is one of the greatest pieces of software ever written, in my humble oopinion, and my go-to choice for an email client. Despite how great it is, it has a pretty annoying UI bug/feature that I almost always get stuck on whenever I do new manual configurations, so I ran into that again here, and after some head-scratching and finding that bug report again, I was able to get past it and make a manual account. Basically, if you put in every single setting (nothing can be on “auto”), then Thunderbird will let you by with a manual configuration. BTW, auto configuration is actually a file that Thunderbird is just expecting to find, there’s even a Mailu issue about it.
Even with the configuration set up in Thunderbird, I would consistently fail to log in to my account, and couldn’t figure out why. My testing methodology was this:
kubectl logs -f mailu-3284661181-zwb76 imap
(open this in a console and watch for errors)After a while I realized that I was trying to log in using a system user when what I was supposed to be using was the user as configured in Mailu – i.e. my “username” was “user@example.com”, NOT just “user”. Felt pretty dumb, but was glad to be past this minor hiccup.
Since everything was semi-working at this point I started porting all my DNS configuration over to point at this new mail server (so mail.example.com
might have bene pointed at somewhere else but now I was pointing it at the server running Kubernetes). Along with this it’s important to update your DKIM-related DNS entries to what Mailu has generated as well, so your emails have a better chance of ending up in Inboxes and not spam folders.
After doing this, it was time to do the most important thing: send an actual email.
After trying to send an email from Thunderbird I got an error – par for the course with me setting up anything. Weirdly enough, Here’s what the postfix
container logs looked like:
postfix/smtpd[191]: warning: SASL: Connect to inet:imap:2102 failed: Operation timed out
postfix/smtpd[191]: fatal: no SASL authentication mechanisms
postfix/master[145]: warning: process /usr/lib/postfix/smtpd pid 191 exit status 1
postfix/master[145]: warning: /usr/lib/postfix/smtpd: bad command startup -- throttling
Seeing the errors above, I was wondering if there was some setup that I failed to do… Why would I have absolutely no SASL authentication mechanisms? Isn’t that what Mailu was offering? I logged in already for Thunderbird, I wonder why sending email wasn’t working. Then I had a thought.. is receiving mail even working? I tried to send myself something from my gmail account and here’s what I saw:
postfix/anvil[189]: statistics: max connection rate 1/60s for (submission:172.17.0.4) at Aug 16 21:03:50
postfix/anvil[189]: statistics: max connection count 1 for (submission:172.17.0.4) at Aug 16 21:03:50
postfix/anvil[189]: statistics: max cache size 1 at Aug 16 21:03:50
That output looks just fine, nothign particularly error-related there, but there was nothing in my mailbox. Now it’s pretty clear that not everything is set up right. One of the first things I noticed in the logs was that it couldn’t access the milter
at port 9900
… Maybe I’m having more connection problems than just the milter?
Welp, looks like in actuality, neither sending nor receiving emails is working properly.
One of the best things that I’ve figured out while working with Kubernetes is if you can’t figure out what’s going wrong, jump into the container and poke around! A quick kubectl exec -it <pod> -- /bin/bash
and I was into the actual postfix container, poking around and looking at the configurations in /etc/postfix
. To be honest, going through the Postfix documentation lots of times and touching on the SASL README more than once also helped me to understand what I was/wasn’t looking for here.
After some looking at the configuration, and looking to more logs, I realized that imap:2102
(which was in the configuration) was actually timing out/inaccessible from inside the postfix
container itself. The imap
service is supposed to expose dovecot – pretty big issue if it’s unreachable, maybe I am receiving emails (I don’t see any DAEMON errors in gmail), but they’re just not getting served up through IMAP properly?
Now it’s time to figure out why the imap
service isn’t working properly. After checking kubectl describe svc imap
, it looks like the service has endpoints, has an IP, and is accessible from a tutum/curl
container (a container I routinely spin up just to curl things and make sure they’re accessible). So weirdly enough, now I’m convinced the imap
service IS working properly and is accessible, but postfix just can’t access it for some reason.
I tried one more change – updating /etc/postfix/main.cf
and changing the smtpd_sasl_path to the IP of the service, and then to the endpoint of the actual
mailu` container. After doing that, the errors changed:
postfix/smtpd[206]: connect from unknown[172.17.0.4]
postfix/smtpd[206]: SSL_accept error from unknown[172.17.0.4]: lost connection
postfix/smtpd[206]: lost connection after CONNECT from unknown[172.17.0.4]
postfix/smtpd[206]: disconnect from unknown[172.17.0.4] commands=0/0
postfix/smtpd[206]: connect from unknown[172.17.0.4]
postfix/smtpd[206]: fatal: host/service milter/9900 not found: Name does not resolve
postfix/master[146]: warning: process /usr/lib/postfix/smtpd pid 206 exit status 1
NOW it’s complaining about not finding the milter – which makes me think that things got better. I figured the milter might have had very similar issues so now I try the same trick for the milter as well (using the IP of the container) and find that it works, and the errors change AGAIN:
postfix/smtpd[224]: warning: unknown[172.17.0.4]: SASL LOGIN authentication failed: UGFzc3dvcmQ6
postfix/smtpd[224]: warning: unknown[172.17.0.4]: SASL PLAIN authentication failed: UGFzc3dvcmQ6
postfix/smtpd[224]: warning: unknown[172.17.0.4]: SASL LOGIN authentication failed: UGFzc3dvcmQ6
postfix/smtpd[224]: warning: unknown[172.17.0.4]: SASL PLAIN authentication failed: UGFzc3dvcmQ6
postfix/smtpd[224]: warning: unknown[172.17.0.4]: SASL LOGIN authentication failed: UGFzc3dvcmQ6
Now it’s telling me that my login was failing – not that an SASL method was missing and not that the mitler was inaccessible. Fixing this ended up requiring going back to my Thunderbird configuration and changing the username from user
to user@example.com
– that was just a bit of an error on my part, forgetting that the username needed to be the full email address. Once I got that fixed, sending emails was finally working!
Here’s where things get a little fuzzy – eventually I was able to replace the smtpd_sasl_path
configuration variable with inet:imap:2102
and it started working properly. I’m not sure exactly what happened to make the service that should have been working to start doing the right thing, but I didn’t leave any notes so I can’t write about it here :(.
Here’s the final massive configuration that worked for me:
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: mailu-admin-ing
labels:
app: mailu
role: mail
tier: backend
spec:
tls:
- hosts:
- "mail.example.com"
secretName: letsencrypt-certs-all
rules:
- host: "mail.example.com"
http:
paths:
- path: "/admin"
backend:
serviceName: mailu-admin
servicePort: 80
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mailu-redis
spec:
replicas: 1
template:
metadata:
labels:
app: mailu-redis
role: mail
tier: backend
spec:
containers:
- name: redis
image: redis:latest
imagePullPolicy: Always
volumeMounts:
- mountPath: /data
name: redisdata
ports:
- containerPort: 6379
name: redis
protocol: TCP
volumes:
- name: redisdata
hostPath:
path: /var/data/mailu/redisdata
---
apiVersion: v1
kind: Service
metadata:
name: redis
labels:
app: mailu-redis
role: mail
tier: backend
spec:
selector:
app: mailu
role: mail
tier: backend
ports:
- name: redis
port: 6379
protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mailu-imap
spec:
replicas: 1
template:
metadata:
labels:
app: mailu-imap
role: mail
tier: backend
spec:
containers:
- name: imap
image: mailu/dovecot:stable
imagePullPolicy: Always
env:
- name : DOMAIN
value : example.com
- name : HOSTNAME
value : mail.example.com
- name : POSTMASTER
value : admin
volumeMounts:
- mountPath: /data
name: maildata
- mountPath: /mail
name: mailstate
- mountPath: /overrides
name: overrides
- mountPath: /certs
name: certs
readOnly: true
ports:
- containerPort: 2102
- containerPort: 2525
- containerPort: 143
- containerPort: 993
- containerPort: 4190
volumes:
- name: maildata
hostPath:
path: /var/data/mailu/maildata
- name: mailstate
hostPath:
path: /var/data/mailu/mailstate
- name: overrides
hostPath:
path: /var/data/mailu/overrides
- name: certs
secret:
items:
- key: tls.crt
path: cert.pem
- key: tls.key
path: key.pem
secretName: letsencrypt-certs-all
---
apiVersion: v1
kind: Service
metadata:
name: imap
labels:
app: mailu
role: mail
tier: backend
spec:
selector:
app: mailu-imap
role: mail
tier: backend
ports:
ports:
- name: imap-auth
port: 2102
protocol: TCP
- name: imap-transport
port: 2525
protocol: TCP
- name: imap-default
port: 143
protocol: TCP
- name: imap-ssl
port: 993
protocol: TCP
- name: sieve
port: 4190
protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mailu-smtp
spec:
replicas: 1
template:
metadata:
labels:
app: mailu-smtp
role: mail
tier: backend
spec:
containers:
- name: smtp
image: mailu/postfix:stable
imagePullPolicy: Always
env:
- name : DOMAIN
value : example.com
- name : HOSTNAME
value : mail.example.com
- name : MESSAGE_SIZE_LIMIT
value : "50000000"
- name : RELAYHOST
value : ""
volumeMounts:
- mountPath: /data
name: maildata
- mountPath: /overrides
name: overrides
- mountPath: /certs
name: certs
readOnly: true
ports:
- name: smtp
containerPort: 25
protocol: TCP
- name: smtp-ssl
containerPort: 465
protocol: TCP
- name: smtp-starttls
containerPort: 587
protocol: TCP
volumes:
- name: maildata
hostPath:
path: /var/data/mailu/maildata
- name: overrides
hostPath:
path: /var/data/mailu/overrides
- name: certs
secret:
items:
- key: tls.crt
path: cert.pem
- key: tls.key
path: key.pem
secretName: letsencrypt-certs-all
---
apiVersion: v1
kind: Service
metadata:
name: smtp
labels:
app: mailu
role: mail
tier: backend
spec:
selector:
app: mailu-smtp
role: mail
tier: backend
ports:
- name: smtp
port: 25
protocol: TCP
- name: smtp-ssl
port: 465
protocol: TCP
- name: smtp-starttls
port: 587
protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mailu-milter
spec:
replicas: 1
template:
metadata:
labels:
app: mailu-milter
role: mail
tier: backend
spec:
containers:
- name: milter
image: mailu/rmilter:stable
imagePullPolicy: Always
ports:
- name: milter
containerPort: 9900
protocol: TCP
volumeMounts:
- name: maildata
mountPath: /data
- name: dkim
mountPath: /dkim
- name: overrides
mountPath: /overrides
- name: certs
mountPath: /certs
readOnly: true
volumes:
- name: maildata
hostPath:
path: /var/data/mailu/maildata
- name: overrides
hostPath:
path: /var/data/mailu/overrides
- name: dkim
hostPath:
path: /var/data/mailu/dkim
- name: certs
secret:
items:
- key: tls.crt
path: cert.pem
- key: tls.key
path: key.pem
secretName: letsencrypt-certs-all
---
apiVersion: v1
kind: Service
metadata:
name: milter
labels:
app: mailu-milter
role: mail
tier: backend
spec:
selector:
app: mailu-milter
role: mail
tier: backend
ports:
- name: milter
port: 9900
protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mailu-security
spec:
replicas: 1
template:
metadata:
labels:
app: mailu-security
role: mail
tier: backend
spec:
containers:
- name: antispam
image: mailu/rspamd:stable
imagePullPolicy: Always
ports:
- name: antispam
containerPort: 11333
protocol: TCP
volumeMounts:
- name: filter
mountPath: /var/lib/rspamd
- name: antivirus
image: mailu/clamav:stable
imagePullPolicy: Always
ports:
- name: antivirus
containerPort: 3310
protocol: TCP
volumeMounts:
- name: filter
mountPath: /data
volumes:
- name: filter
hostPath:
path: /var/data/mailu/filter
---
apiVersion: v1
kind: Service
metadata:
name: antispam
labels:
app: mailu-antispam
role: mail
tier: backend
spec:
selector:
app: mailu-security
role: mail
tier: backend
ports:
- name: antispam
port: 11333
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: antivirus
labels:
app: mailu-antivirus
role: mail
tier: backend
spec:
selector:
app: mailu-security
role: mail
tier: backend
ports:
- name: antivirus
port: 3310
protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mailu-admin
spec:
replicas: 1
template:
metadata:
labels:
app: mailu-admin
role: mail
tier: backend
spec:
containers:
- name: admin
image: mailu/admin:stable
imagePullPolicy: Always
env:
- name : DOMAIN
value : example.com
- name : HOSTNAME
value : mail.example.com
- name : POSTMASTER
value : core
- name : SECRET_KEY
value : pleasereplacethiswithsomethingelse
- name : DEBUG
value : "True"
volumeMounts:
- name: maildata
mountPath: /data
- name: dkim
mountPath: /dkim
- name: certs
mountPath: /certs
readOnly: true
# - name: docker
# mountPath: /var/run/docker.sock
# readOnly: true
ports:
- name: http
containerPort: 80
protocol: TCP
volumes:
- name: maildata
hostPath:
path: /var/data/mailu/maildata
- name: dkim
hostPath:
path: /var/data/mailu/dkim
- name: certs
secret:
items:
- key: tls.crt
path: cert.pem
- key: tls.key
path: key.pem
secretName: letsencrypt-certs-all
# - name: docker
# hostPath:
# path: /var/run/docker.sock
---
apiVersion: v1
kind: Service
metadata:
name: mailu-admin
labels:
app: mailu-admin
role: mail
tier: backend
spec:
selector:
app: mailu-admin
role: mail
tier: backend
ports:
- name: http
port: 80
protocol: TCP
After getting all fo this working, I also found some time to contribute the configuration to the Mailu team which felt pretty great because I always say “oh maybe I’ll contribute” but never do.
After all this wandering and ups/downs, I’ve finally got a pretty ergonomic email set up now, with nice easy-to-use web UI management provided by Mailu. I was pretty happy with myself at this point so I called it a day here (and I still use this set up to serve my emails).
I hope you find it easier to set up with this guide (at the very least with the resource configuration)!