summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Dockerfile61
-rw-r--r--README.md132
-rw-r--r--dav.conf25
-rw-r--r--default-ssl.conf18
-rw-r--r--default.conf11
-rwxr-xr-xdocker-entrypoint.sh98
6 files changed, 345 insertions, 0 deletions
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..e18b21a
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,61 @@
+FROM httpd:alpine
+MAINTAINER Bytemark Hosting "support@bytemark.co.uk"
+
+# This variable is inherited from httpd:alpine image:
+# ENV HTTPD_PREFIX /usr/local/apache2
+
+RUN set -ex; \
+ # Create Debian-style subdirectories.
+ mkdir -p "$HTTPD_PREFIX/conf/conf-available"; \
+ mkdir -p "$HTTPD_PREFIX/conf/conf-enabled"; \
+ mkdir -p "$HTTPD_PREFIX/conf/sites-available"; \
+ mkdir -p "$HTTPD_PREFIX/conf/sites-enabled"
+
+# Copy in our configuration files.
+COPY dav.conf "$HTTPD_PREFIX/conf/conf-available"
+COPY default.conf "$HTTPD_PREFIX/conf/sites-available"
+COPY default-ssl.conf "$HTTPD_PREFIX/conf/sites-available"
+
+RUN set -ex; \
+ # Create empty default DocumentRoot.
+ mkdir -p "/var/www/html"; \
+ # Create directories for Dav data and lock database.
+ mkdir -p "/var/lib/dav"; \
+ mkdir -p "/var/lib/dav/data"; \
+ touch "/var/lib/dav/DavLock"; \
+ chown -R www-data:www-data "/var/lib/dav"; \
+ \
+ # Enable DAV modules.
+ for i in dav dav_fs; do \
+ sed -i -e "/^#LoadModule ${i}_module.*/s/^#//" "$HTTPD_PREFIX/conf/httpd.conf"; \
+ done; \
+ \
+ # Make sure authentication modules are enabled.
+ for i in authn_core authn_file authz_core authz_user auth_basic auth_digest; do \
+ sed -i -e "/^#LoadModule ${i}_module.*/s/^#//" "$HTTPD_PREFIX/conf/httpd.conf"; \
+ done; \
+ \
+ # Make sure other modules are enabled.
+ for i in alias headers mime setenvif; do \
+ sed -i -e "/^#LoadModule ${i}_module.*/s/^#//" "$HTTPD_PREFIX/conf/httpd.conf"; \
+ done; \
+ \
+ # Run httpd as "www-data" (instead of "daemon").
+ for i in User Group; do \
+ sed -i -e "s|^$i .*|$i www-data|" "$HTTPD_PREFIX/conf/httpd.conf"; \
+ done; \
+ \
+ # Include enabled configs and sites.
+ printf '%s\n' "Include conf/conf-enabled/*.conf" \
+ >> "$HTTPD_PREFIX/conf/httpd.conf"; \
+ printf '%s\n' "Include conf/sites-enabled/*.conf" \
+ >> "$HTTPD_PREFIX/conf/httpd.conf"; \
+ \
+ # Enable dav and default site.
+ ln -s ../conf-available/dav.conf "$HTTPD_PREFIX/conf/conf-enabled"; \
+ ln -s ../sites-available/default.conf "$HTTPD_PREFIX/conf/sites-enabled"
+
+COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
+EXPOSE 80/tcp 443/tcp
+ENTRYPOINT [ "docker-entrypoint.sh" ]
+CMD [ "httpd-foreground" ]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7ad8090
--- /dev/null
+++ b/README.md
@@ -0,0 +1,132 @@
+## Supported tags
+
+* [`2.4`, `latest` (*stretch/Dockerfile*)](https://github.com/BytemarkHosting/docker-webdav/blob/master/2.4/Dockerfile)
+
+## Quick reference
+
+This image runs an easily configurable WebDAV server with Apache.
+
+* **Code repository:**
+ https://github.com/BytemarkHosting/docker-webdav
+* **Where to file issues:**
+ https://github.com/BytemarkHosting/docker-webdav/issues
+* **Maintained by:**
+ [Bytemark Hosting](https://www.bytemark.co.uk)
+* **Supported architectures:**
+ [Any architecture that the `httpd` image supports](https://hub.docker.com/_/httpd/)
+
+## Usage
+
+### Basic WebDAV server
+
+This example starts a WebDAV server.
+
+When using unencrypted HTTP, use `Digest` authentication (instead of `Basic`)
+to avoid sending plaintext passwords in the clear.
+
+To make sure your data doesn't get deleted, you'll probably want to create a
+persistent storage volume (`-v vol-webdav:/var/lib/dav`) or bind mount a
+directory (`-v /path/to/directory:/var/lib/dav`):
+
+```
+docker run --restart always -v /srv/dav:/var/lib/dav \
+ -e AUTH_TYPE=Digest -e USERNAME=alice -e PASSWORD=secret1234 \
+ --publish 80:80 -d bytemark/webdav
+
+```
+
+#### Via Docker Compose:
+
+```
+version: '3'
+services:
+ mail:
+ image: bytemark/webdav
+ restart: always
+ ports:
+ - "80:80"
+ environment:
+ AUTH_TYPE: Digest
+ USERNAME: alice
+ PASSWORD: secret1234
+ volumes:
+ - /srv/dav:/var/lib/dav
+
+```
+### Secure WebDAV with SSL
+
+We recommend you use a reverse proxy (eg, Traefik) to handle SSL certificates.
+
+If you're happy with a self-signed certificate, you can specify `-e
+SSL_CERT=selfsigned` and the container will generate one for you.
+
+```
+docker run --restart always -v /srv/dav:/var/lib/dav \
+ -e AUTH_TYPE=Basic -e USERNAME=test -e PASSWORD=test \
+ -e SSL_CERT=selfsigned --publish 443:443 -d bytemark/webdav
+
+```
+
+### Authenticate multiple clients
+
+Specifying `USERNAME` and `PASSWORD` only supports a single user. Bind mount
+your own file to `/user.passwd` and the container will use that instead.
+
+If using `Basic` authentication, run the following commands:
+
+```
+touch user.passwd
+htpasswd -B user.passwd alice
+htpasswd -B user.passwd bob
+
+```
+
+If using `Digest` authentication, run the following commands. (NB: The default
+`REALM` is `WebDAV`. If you specify your own `REALM`, you'll need to run
+`htdigest` again with the new name.)
+
+
+```
+touch user.passwd
+htdigest user.passwd WebDAV alice
+htdigest user.passwd WebDAV bob
+
+```
+
+Once you've created your own `user.passwd`, bind mount it into your container
+with `-v /path/to/user.passwd:/user.passwd`.
+
+### Environment variables
+
+All environment variables are optional. You probably want to at least specify
+`USERNAME` and `PASSWORD` (or bind mount your own authentication file to
+`/user.passwd`) otherwise nobody will be able to access your WebDAV server!
+
+* **`SERVER_NAMES`**: Comma-separated list of domains (eg,
+ `example.com,www.example.com`). The first is set as the
+ [ServerName](https://httpd.apache.org/docs/current/mod/core.html#servername),
+ and the rest (if any) are set as
+ [ServerAlias](https://httpd.apache.org/docs/current/mod/core.html#serveralias).
+ The default is `localhost`.
+* **`LOCATION`**: The URL path for WebDAV (eg, if set to `/webdav` then clients
+ should connect to `example.com/webdav`). The default is `/`.
+* **`AUTH_TYPE`**: Apache authentication type to use. This can be `Basic` (best
+ choice for HTTPS) or `Digest` (best choice for HTTP). The default is `Basic`.
+* **`REALM`**: Sets
+ [AuthName](https://httpd.apache.org/docs/current/mod/mod_authn_core.html#authname),
+ an identifier that is displayed to clients when they connect. The default is
+ `WebDAV`.
+* **`USERNAME`**: Authenticate with this username (and the password below).
+ This is ignored if you bind mount your own authentication file to
+ `/user.passwd`.
+* **`PASSWORD`**: Authenticate with this password (and the username above).
+ This is ignored if you bind mount your own authentication file to
+ `/user.passwd`.
+* **`ANONYMOUS_METHODS`**: Comma-separated list of HTTP request methods (eg,
+ `GET,POST,OPTIONS,PROPFIND`). Clients can use any method you specify here
+ without authentication. Set to `ALL` to disable authentication. The default
+ is to disallow any anonymous access.
+* **`SSL_CERT`**: Set to `selfsigned` to generate a self-signed certificate and
+ enable Apache's SSL module. If you specify `SERVER_NAMES`, the first domain
+ is set as the Common Name.
+
diff --git a/dav.conf b/dav.conf
new file mode 100644
index 0000000..caacd03
--- /dev/null
+++ b/dav.conf
@@ -0,0 +1,25 @@
+DavLockDB "/var/lib/dav/DavLock"
+Alias / "/var/lib/dav/data/"
+<Directory "/var/lib/dav/data/">
+ Dav On
+ Options Indexes FollowSymLinks
+
+ AuthType Basic
+ AuthName "WebDAV"
+ AuthUserFile "/user.passwd"
+ <RequireAny>
+ Require valid-user
+ </RequireAny>
+</Directory>
+
+# These disable redirects on non-GET requests for directories that
+# don't include the trailing slash (for misbehaving clients).
+BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
+BrowserMatch "MS FrontPage" redirect-carefully
+BrowserMatch "^WebDrive" redirect-carefully
+BrowserMatch "^WebDAVFS/1.[01234]" redirect-carefully
+BrowserMatch "^gnome-vfs/1.0" redirect-carefully
+BrowserMatch "^XML Spy" redirect-carefully
+BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
+BrowserMatch " Konqueror/4" redirect-carefully
+BrowserMatch "^gvfs" redirect-carefully
diff --git a/default-ssl.conf b/default-ssl.conf
new file mode 100644
index 0000000..ef90866
--- /dev/null
+++ b/default-ssl.conf
@@ -0,0 +1,18 @@
+Listen 443
+<VirtualHost *:443>
+ Protocols h2 http/1.1
+ ServerName localhost
+ DocumentRoot "/var/www/html/"
+ <Directory "/var/www/html/">
+ Require all denied
+ </Directory>
+ CustomLog /proc/self/fd/1 combined
+ ErrorLog /proc/self/fd/2
+ SSLEngine on
+ SSLCertificateFile /cert.pem
+ SSLCertificateKeyFile /privkey.pem
+ SSLProtocol all -SSLv3
+ SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
+ SSLHonorCipherOrder on
+ SSLSessionTickets off
+</VirtualHost>
diff --git a/default.conf b/default.conf
new file mode 100644
index 0000000..e309338
--- /dev/null
+++ b/default.conf
@@ -0,0 +1,11 @@
+<VirtualHost *:80>
+ ServerName localhost
+ DocumentRoot "/var/www/html/"
+ <Directory "/var/www/html/">
+ Require all denied
+ </Directory>
+ CustomLog /proc/self/fd/1 combined
+ ErrorLog /proc/self/fd/2
+ # This lets certain DAV methods work behind an SSL reverse proxy.
+ RequestHeader edit Destination ^https http early
+</VirtualHost>
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
new file mode 100755
index 0000000..cff51eb
--- /dev/null
+++ b/docker-entrypoint.sh
@@ -0,0 +1,98 @@
+#!/bin/sh
+set -e
+
+# Environment variables that are used if not empty:
+# SERVER_NAMES
+# LOCATION
+# AUTH_TYPE
+# REALM
+# USERNAME
+# PASSWORD
+# ANONYMOUS_METHODS
+# SSL_CERT
+
+# Just in case this environment variable has gone missing.
+HTTPD_PREFIX="${HTTPD_PREFIX:-/usr/local/apache2}"
+
+# Configure vhosts.
+if [ "x$SERVER_NAMES" != "x" ]; then
+ # Use first domain as Apache ServerName.
+ SERVER_NAME="${SERVER_NAMES%%,*}"
+ sed -e "s|ServerName .*|ServerName $SERVER_NAME|" \
+ -i "$HTTPD_PREFIX"/conf/sites-available/default*.conf
+
+ # Replace commas with spaces and set as Apache ServerAlias.
+ SERVER_ALIAS="`printf '%s\n' "$SERVER_NAMES" | tr ',' ' '`"
+ sed -e "/ServerName/a\ \ ServerAlias $SERVER_ALIAS" \
+ -i "$HTTPD_PREFIX"/conf/sites-available/default*.conf
+fi
+
+# Configure dav.conf
+if [ "x$LOCATION" != "x" ]; then
+ sed -e "s|Alias /|Alias $LOCATION|" \
+ -i "$HTTPD_PREFIX/conf/conf-available/dav.conf"
+fi
+if [ "x$REALM" != "x" ]; then
+ sed -e "s|AuthName .*|AuthName \"$REALM\"|" \
+ -i "$HTTPD_PREFIX/conf/conf-available/dav.conf"
+else
+ REALM="WebDAV"
+fi
+if [ "x$AUTH_TYPE" != "x" ]; then
+ # Only support "Basic" and "Digest".
+ if [ "$AUTH_TYPE" != "Basic" ] && [ "$AUTH_TYPE" != "Digest" ]; then
+ printf '%s\n' "$AUTH_TYPE: Unknown AuthType" 1>&2
+ exit 1
+ fi
+ sed -e "s|AuthType .*|AuthType $AUTH_TYPE|" \
+ -i "$HTTPD_PREFIX/conf/conf-available/dav.conf"
+fi
+
+# Add password hash, unless "user.passwd" already exists (ie, bind mounted).
+if [ ! -e "/user.passwd" ]; then
+ touch "/user.passwd"
+ # Only generate a password hash if both username and password given.
+ if [ "x$USERNAME" != "x" ] && [ "x$PASSWORD" != "x" ]; then
+ if [ "$AUTH_TYPE" = "Digest" ]; then
+ # Can't run `htdigest` non-interactively, so use other tools.
+ HASH="`printf '%s' "$USERNAME:$REALM:$PASSWORD" | md5sum | awk '{print $1}'`"
+ printf '%s\n' "$USERNAME:$REALM:$HASH" > /user.passwd
+ else
+ htpasswd -B -b -c "/user.passwd" $USERNAME $PASSWORD
+ fi
+ fi
+fi
+
+# If specified, allow anonymous access to specified methods.
+if [ "x$ANONYMOUS_METHODS" != "x" ]; then
+ if [ "$ANONYMOUS_METHODS" = "ALL" ]; then
+ sed -e "s/Require valid-user/Require all granted/" \
+ -i "$HTTPD_PREFIX/conf/conf-available/dav.conf"
+ else
+ sed -e "/Require valid-user/a\ \ \ \ Require method $ANONYMOUS_METHODS" \
+ -i "$HTTPD_PREFIX/conf/conf-available/dav.conf"
+ fi
+fi
+
+case "${SSL_CERT:-none}" in
+ "selfsigned")
+ # Generate self-signed SSL certificate.
+ # If SERVER_NAMES is given, use the first domain as the Common Name.
+ if [ ! -e /privkey.pem ] || [ ! -e /cert.pem ]; then
+ apk add --no-cache openssl
+ openssl req -x509 -newkey rsa:2048 -days 1000 -nodes \
+ -keyout /privkey.pem -out /cert.pem -subj "/CN=${SERVER_NAME:-selfsigned}"
+ apk del --no-cache openssl
+ fi
+ # Enable SSL Apache modules.
+ for i in http2 ssl; do
+ sed -i -e "/^#LoadModule ${i}_module.*/s/^#//" "$HTTPD_PREFIX/conf/httpd.conf"
+ done
+ # Enable SSL vhost.
+ if [ -e /privkey.pem ] && [ -e /cert.pem ]; then
+ ln -s ../sites-available/default-ssl.conf "$HTTPD_PREFIX/conf/sites-enabled"; \
+ fi
+ ;;
+esac
+
+exec "$@"