diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 000000000..7e6d2dfe5
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,43 @@
+# This Dockerfile creates a production release image for the project. This
+# downloads the release from releases.hashicorp.com and therefore requires that
+# the release is published before building the Docker image.
+#
+# We don't rebuild the software because we want the exact checksums and
+# binary signatures to match the software and our builds aren't fully
+# reproducible currently.
+FROM alpine:3
+
+# NAME and VERSION are the name of the software in releases.hashicorp.com
+# and the version to download.
+ARG NAME=consul-template
+ARG VERSION
+
+# version label is required for build process
+LABEL maintainer="John Eikenberry <jae@zhar.net>"
+LABEL version=$VERSION
+
+# UID and GID of consul-template user and group.
+# These are the defaults, this makes them explicit and overridable.
+ARG UID=100
+ARG GID=1000
+
+# Set ARGs as ENV so that they can be used in ENTRYPOINT/CMD
+ENV NAME=${NAME}
+ENV VERSION=${VERSION}
+
+# This is the location of the releases.
+ENV HASHICORP_RELEASES=https://releases.hashicorp.com
+
+# Create a user and group first so the IDs get set the same way,
+# even as the rest of this may change over time.
+RUN addgroup -g ${GID} ${NAME} && adduser -u ${UID} -S -G ${NAME} ${NAME}
+
+# Set up certificates, base tools, and software.
+COPY fetch-n-verify.sh docker-entrypoint.sh /
+RUN /fetch-n-verify.sh # removes self when done
+
+ENTRYPOINT ["/docker-entrypoint.sh"]
+
+USER ${NAME}:${NAME}
+CMD /bin/${NAME}
+
diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh
new file mode 100755
index 000000000..344daf7b7
--- /dev/null
+++ b/docker/docker-entrypoint.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# Don't use dumb-init as it isn't required and the end-user has the option
+# to set it via the `--init` option.
+
+set -e
+
+# If the user is trying to run consul-template directly with some arguments,
+# then pass them to consul-template.
+# On alpine /bin/sh is busybox which supports this bashism.
+if [ "${1:0:1}" = '-' ]
+then
+    set -- /bin/consul-template "$@"
+fi
+
+# MUST exec here for consul-template to replace the shell as PID 1 in order
+# to properly propagate signals from the OS to the consul-template process.
+exec "$@"
diff --git a/docker/fetch-n-verify.sh b/docker/fetch-n-verify.sh
new file mode 100755
index 000000000..a200921b7
--- /dev/null
+++ b/docker/fetch-n-verify.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# requires environment variables..
+#
+# HASHICORP_RELEASES - URL for releases
+# NAME - application's name
+# VERSION - application version (eg. 1.2.3)
+
+set -eux
+apk add --no-cache ca-certificates gnupg
+
+BUILD_GPGKEY=C874011F0AB405110D02105534365D9472D7468F
+found=''
+
+for server in \
+    hkp://p80.pool.sks-keyservers.net:80 \
+    hkp://keyserver.ubuntu.com:80 \
+    hkp://pgp.mit.edu:80 \
+; do
+    echo "Fetching GPG key $BUILD_GPGKEY from $server";
+    gpg --keyserver "$server" --recv-keys "$BUILD_GPGKEY" && found=yes && break;
+done
+
+test -z "$found" && echo >&2 "error: failed to fetch GPG key $BUILD_GPGKEY" && exit 1
+mkdir -p /tmp/build && cd /tmp/build
+
+apkArch="$(apk --print-arch)"
+case "${apkArch}" in \
+    aarch64) ARCH='arm64' ;;
+    armhf) ARCH='armhfv6' ;;
+    x86) ARCH='386' ;;
+    x86_64) ARCH='amd64' ;;
+    *) echo >&2 "error: unsupported architecture: ${apkArch} (see ${HASHICORP_RELEASES}/${NAME}/${VERSION}/)" && exit 1 ;;
+esac
+
+wget ${HASHICORP_RELEASES}/${NAME}/${VERSION}/${NAME}_${VERSION}_linux_${ARCH}.zip
+wget ${HASHICORP_RELEASES}/${NAME}/${VERSION}/${NAME}_${VERSION}_SHA256SUMS
+wget ${HASHICORP_RELEASES}/${NAME}/${VERSION}/${NAME}_${VERSION}_SHA256SUMS.sig
+gpg --batch --verify ${NAME}_${VERSION}_SHA256SUMS.sig ${NAME}_${VERSION}_SHA256SUMS
+grep ${NAME}_${VERSION}_linux_${ARCH}.zip ${NAME}_${VERSION}_SHA256SUMS | sha256sum -c
+unzip -d /bin ${NAME}_${VERSION}_linux_${ARCH}.zip
+
+apk del gnupg
+cd /tmp
+rm -rf /tmp/build
+rm -rf /root/.gnupg
+rm "$0"