diff --git a/Dockerfile b/Dockerfile
index 17f625040fb08f5aa5cda4c209a4e5aed580769f..be53c31902b6acbee7f0ea3b2fe2c232bb00ac8f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -9,8 +9,10 @@ RUN go build -o smtpd smtpd.go
 FROM registry.git.autistici.org/ai3/docker/apache2-base:master
 COPY start.sh /start.sh
 COPY build.sh /tmp/build.sh
+COPY ai-lurker-ui.patch /tmp/ai-lurker-ui.patch
 COPY conf/ /etc/
 COPY --from=build /go/src/smtpd /usr/bin/smtpd
-RUN /tmp/build.sh && rm /tmp/build.sh
+RUN /tmp/build.sh && rm /tmp/build.sh /tmp/ai-lurker-ui.patch
+COPY logo.png /var/lib/lurker-www-orig/logo.png
 ENTRYPOINT ["/usr/local/bin/chaperone"]
 
diff --git a/README.md b/README.md
index 0db655fe63552624b3ab6ec10afff290d5ec987c..0607386ebf37995a84d612d7f988df6a4d82f923 100644
--- a/README.md
+++ b/README.md
@@ -8,3 +8,26 @@ instead of using two separate container images.
 Configuration and data storage must be mounted respectively in
 */etc/lurker* and */var/lib/lurker*.
 
+Instead of running a full-blown Postfix instance, this container runs
+a very simple [SMTP server](smtpd.go) that is only suitable for internal
+traffic.
+
+The image expects /var/lib/lurker to be mounted externally with the
+right permissions, and to contain the *www* and *data* subdirectories.
+
+## Environment variables
+
+* `DOMAIN`: domain for the HTTP website, minus the *lists* prefix
+* `APACHE_PORT`: port for the HTTP service
+* `SMTP_PORT`: port for the SMTP service
+* `SMTP_EHLO_HOSTNAME`: hostname to use for SMTP EHLO
+* `LURKER_ADDR_RX`: regular expression to match SMTP recipients and
+  extract the list name from it. It should include a single regexp
+  group (the list name). The default handles plus-extension addresses
+  using the *lurker* username (`lurker\\+([^@]+)@.*`), but it is
+  recommended to extend it to match the expected domain name as well.
+* `LURKER_DATA_DIR`: data directory for Lurker (default */var/lib/lurker/data*).
+
+When Lurker is performing maintenance on its database, incoming
+SMTP reception is temporarily suspended.
+
diff --git a/ai-lurker-ui.patch b/ai-lurker-ui.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e5345420c1c6fc3d6f73f3edb2afc262422ebc33
--- /dev/null
+++ b/ai-lurker-ui.patch
@@ -0,0 +1,169 @@
+diff -urN ui_/common.xsl ui/common.xsl
+--- ui_/common.xsl	2016-12-20 12:02:51.000000000 +0000
++++ ui/common.xsl	2017-09-16 13:59:48.788481408 +0000
+@@ -313,7 +313,7 @@
+ <xsl:template name="navbar">
+  <table>
+   <tr>
+-   <td><xsl:call-template name="link-to-top"/></td>
++   <td></td>
+    <td nowrap="NOWRAP"><xsl:call-template name="language-dropdown"/></td>
+   </tr>
+  </table>
+diff -urN ui_/default.css ui/default.css
+--- ui_/default.css	2016-12-20 12:02:51.000000000 +0000
++++ ui/default.css	2017-09-16 13:59:48.428473648 +0000
+@@ -1,9 +1,9 @@
+ body {
+   padding: 0px;
+-  margin: 0px;
+-  background-color: #BBF;
++  margin: 5px;
++  background-color: #FFF;
+   color: black;
+-  font-family: serif;
++  font-family: Arial, Helvetica, sans-serif;
+ }
+ 
+ form {
+@@ -11,13 +11,13 @@
+ }
+ 
+ div.header {
+-  background-color: #BBF;
++  background-color: #FFF;
+   padding: 4px 0.25em 0.25em 0.25em;
+-  border-bottom: 1px solid #434399;
+ }
+ 
+ div.footer {
+-  background-color: #BBF;
++display: none;
++  background-color: #FFF;
+   padding: 0.25em 0.25em 1px 0.25em;
+   border-top: 1px solid #434399;
+ }
+@@ -57,8 +57,8 @@
+   font-size: 100%;
+ }
+ 
+-a:link    { color:#11F }
+-a:visited { color:#00B }
++a:link    { color:#000 }
++a:visited { color:#000 }
+ a:hover   { color:#F00 }
+ a:active  { color:#A00 }
+ h1 a:visited { color:#11F }
+@@ -113,7 +113,7 @@
+ tr.lit  { background-color:#77F }  /* even rows in mindex/thread/search tables */
+ tr.row1 { background-color:#DDD }  /* even rows in mindex/thread/search tables */
+ tr.row2 { background-color:#EEE }  /* odd rows in mindex/thread/search tables  */
+-tr.rowover { background-color:#CAC } /* active (= mouseOver) rows in mindex/thread/search tables */
++tr.rowover { background-color:#FFF } /* active (= mouseOver) rows in mindex/thread/search tables */
+ 
+ div.body {
+   padding: 1em;
+@@ -171,7 +171,7 @@
+ table.navigation {
+   width: 100%;
+   font-size: 80%;
+-  background-color: #e8e8e8;
++  background-color: #FFF;
+ 
+ /* disabled until mozilla fixes the progressive render bug with images
+   border-top: 1px solid #969696;
+@@ -183,7 +183,7 @@
+ 
+ table.navigation th {
+   font-size: 100%;
+-  background-color: #969696;
++  background-color: #FFF;
+   padding: 3px;
+ }
+ 
+@@ -214,10 +214,13 @@
+ }
+ 
+ ul {
++  list-style-type: none;
+   margin-bottom: 0em;
+   margin-top: 0em;
+ }
+ 
++li { padding: 1px; }
++
+ h1.group {
+   margin: 0px;
+ }
+@@ -309,3 +312,7 @@
+ .url { }     /* "url" elements used inside of message's mime contents */
+ .quote { }   /* "quote" elements used inside of message's mime contents */
+ .art { margin: 0em; } /* "art" elements used inside of message's mime contents */
++
++
++input { padding: 3px; font-size: 12px; margin: 1px; border: 1px solid #CCC; }
++select { padding: 3px; font-size: 10px; margin: 1px; border: 1px solid #CCC; }
+diff -urN ui_/list.xsl ui/list.xsl
+--- ui_/list.xsl	2016-12-20 12:02:51.000000000 +0000
++++ ui/list.xsl	2017-09-16 13:59:48.476474682 +0000
+@@ -107,7 +107,7 @@
+     </table>
+     
+     <table class="navigation">
+-     <tr><th align="left" colspan="2"><xsl:value-of select="$jump-to-date"/></th></tr>
++     <tr><th align="left" colspan="2"></th></tr>
+      <tr>
+       <td>
+         <!-- make this the same height as mindex -->
+diff -urN ui_/message.xsl ui/message.xsl
+--- ui_/message.xsl	2016-12-20 12:02:51.000000000 +0000
++++ ui/message.xsl	2017-09-16 13:59:48.280470457 +0000
+@@ -274,7 +274,7 @@
+     <img src="../imgs/trash.png" alt="{$delete-message}" title="{$delete-message}"/>
+    </a>
+    <xsl:if test="mbox/list/email/@address">
+-    <br/><xsl:call-template name="reply-link"/>
++    <br/><br/><xsl:call-template name="reply-link"/>
+    </xsl:if>
+   </td>
+  </tr></table>
+diff -urN ui_/mindex.xsl ui/mindex.xsl
+--- ui_/mindex.xsl	2016-12-20 12:02:51.000000000 +0000
++++ ui/mindex.xsl	2017-09-16 13:59:48.692479338 +0000
+@@ -62,7 +62,7 @@
+     </table>
+     
+     <table class="navigation">
+-     <tr><th align="left" colspan="3"><xsl:value-of select="$jump-to-date"/></th></tr>
++     <tr><th align="left" colspan="3"></th></tr>
+      <tr>
+       <td>
+        <xsl:choose>
+diff -urN ui_/splash.xsl ui/splash.xsl
+--- ui_/splash.xsl	2016-12-20 12:02:51.000000000 +0000
++++ ui/splash.xsl	2017-09-16 13:59:48.548476235 +0000
+@@ -39,7 +39,7 @@
+    </xsl:otherwise>
+   </xsl:choose>
+   <xsl:text> &#8212; </xsl:text>
+-  <i><xsl:value-of select="description"/></i>
++  <xsl:value-of select="description"/>
+  </li>
+  <xsl:text>&#10;</xsl:text>
+ </xsl:template>
+@@ -75,13 +75,13 @@
+    <div class="header">
+     <table class="external">
+      <tr>
+-      <td align="left"><h1><xsl:value-of select="server/archive"/></h1></td>
++      <td align="left"><img src="/logo.png"/></td>
+       <td align="right"><xsl:call-template name="navbar"/></td>
+      </tr>
+     </table>
+     
+     <table class="navigation">
+-     <tr><th align="left"><xsl:value-of select="$search-menu"/></th></tr>
++     <tr><th align="left"></th></tr>
+      <tr><td nowrap="NOWRAP" align="center">
+       <form action="{server/cgi-url}/keyword.cgi" accept-charset="UTF-8" onsubmit="form_timezone(this)">
+        <input type="hidden" name="doc-url" value="{server/doc-url}"/>
diff --git a/build.sh b/build.sh
index 6b12278a2dca2c83e04840d0cbece64efd00729f..7269705581611d3941910ad68cbd68360b1b87d4 100755
--- a/build.sh
+++ b/build.sh
@@ -3,9 +3,12 @@
 # Install script for Lurker inside a Docker container.
 #
 
+BUILD_PACKAGES="
+	patch
+"
+
 PACKAGES="
 	lurker
-	python3-aiosmtpd
 "
 
 install_packages() {
@@ -20,10 +23,8 @@ die() {
 set -x
 
 # Install packages (aiosmtpd comes from backports in stretch).
-echo "deb http://deb.debian.org/debian stretch-backports main" \
-    > /etc/apt/sources.list.d/backports.list
 apt-get -q update
-install_packages ${PACKAGES} \
+install_packages ${BUILD_PACKAGES} ${PACKAGES} \
     || die "could not install packages"
 
 # Enable the apache modules we need.
@@ -39,15 +40,19 @@ mkdir -p /var/lib/lurker
 # so the original files would disappear "below" the mount. To
 # prevent this, we copy the files to a well-known location
 # beforehand, and set up links at run-time.
-mkdir -p /var/lib/lurker-www
-mv /etc/lurker/ui /var/lib/lurker-www/ui
-mv /var/lib/lurker/www/index.html /var/lib/lurker-www/index.html
+mkdir -p /var/lib/lurker-www-orig
+mv /etc/lurker/ui /var/lib/lurker-www-orig/ui
+mv /var/lib/lurker/www/index.html /var/lib/lurker-www-orig/index.html
+
+# Apply our UI patch.
+(cd /var/lib/lurker-www-orig/ui && patch -p1 </tmp/ai-lurker-ui.patch)
 
 # Clear the existing default config
 # (this will be mounted externally).
 rm -fr /etc/lurker/*
 
 # Clean up.
+apt-get --purge remove ${BUILD_PACKAGES}
 apt-get autoremove -y
 apt-get clean
 rm -fr /var/lib/apt/lists/*
diff --git a/logo.png b/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..064cb4f6ecccedb6608ac5e830118f0af7235d2b
Binary files /dev/null and b/logo.png differ
diff --git a/start.sh b/start.sh
index 8a01ede77d05697c01116022077a6ac8801371ff..c4f2f3831a44101ed77069676774b1550060a5a2 100755
--- a/start.sh
+++ b/start.sh
@@ -1,7 +1,27 @@
 #!/bin/sh
+#
+# Setup script for the Lurker Docker container.
+#
+# Since /var/lib/lurker is mounted externally, ensure that it
+# has the required structure, and that all the contents that
+# were originally installed by the lurker package in those
+# directories are correctly symlinked to $static_dir.
+#
 
+data_dir=/var/lib/lurker/data
 www_dir=/var/lib/lurker/www
-static_dir=/var/lib/lurker-www
+static_dir=/var/lib/lurker-www-orig
+
+umask 077
+set -e
+
+echo "Checking dirs..." >&2
+
+mkdir -p ${data_dir}
+mkdir -p ${www_dir}
+for sub in attach list mbox message mindex search splash thread zap; do
+    mkdir -p ${www_dir}/${sub}
+done
 
 echo "Fixing symlinks..." >&2
 
@@ -18,4 +38,11 @@ if [ ! -e ${www_dir}/lurker.docroot ]; then
     touch ${www_dir}/lurker.docroot
 fi
 
+# The logo.png symlink switches between custom / builtin.
+logo_src=${static_dir}/logo.png
+if [ -e /etc/lurker/logo.png ]; then
+    logo_src=/etc/lurker/logo.png
+fi
+ln -sf ${logo_src} ${www_dir}/logo.png
+
 exit 0