diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7471698
--- /dev/null
+++ b/README.md
@@ -0,0 +1,163 @@
+# simple-shortener
+
+Easily wrap a self-hosted URL shortening service around your personal site.
+
+[View on Docker Hub](https://hub.docker.com/r/jessiehildebrandt/simple-shortener)
+
+Created with [Fennel](https://fennel-lang.org), [Turbo](https://github.com/kernelsauce/turbo), and [Mithril](https://mithril.js.org/).
+
+[![Build Status](https://gitlab.com/jessieh/simple-shortener/badges/main/pipeline.svg)](https://gitlab.com/jessieh/simple-shortener/-/pipelines)
+
+## Table of Contents
+
+ - [Demo](#demo)
+ - [Deploying](#deploying)
+ - [Configuration](#configuration)
+ - [API](#documentation)
+ - [TOTP Issuer Icons](#totp-issuer-icons)
+
+## Demo
+
+
+
+## Deploying
+
+**NOTE**: You will need to configure `auth_secret` before the service will run. See **[Configuration](#configuration)**.
+
+With Docker1:
+
+```bash
+docker run -d \
+-p 80:80 \
+--env-file config.env \
+--mount source=shortener-db,target=/simple-shortener/db \
+--mount type=bind,source=/PATH/TO/YOUR/SITE,target=/simple-shortener/static/landing_page,readonly \
+jessiehildebrandt/simple-shortener
+```
+
+With Docker Compose1:
+
+```yaml
+simple-shortener:
+ image: jessiehildebrandt/simple-shortener
+ env_file: config.env
+ ports:
+ - 80:80
+ volumes:
+ - shortener-db:/simple-shortener/db
+ - /PATH/TO/YOUR/SITE:/simple-shortener/static/landing_page:ro
+
+volumes:
+ shortener-db:
+```
+
+After deploying, you should be able to navigate your browser to `` to view your site, or `/shorten` to log in to the control panel. If you have TOTP auth enabled (on by default), check your Docker logs for a QR code to scan with your TOTP generator app of choice. If you disabled TOTP auth, you can log in by entering `auth_secret` as the passcode.
+
+1 You should probably avoid directly exposing the Turbo HTTP server as in these examples, and should instead opt to use a more robust server as a reverse-proxy.
+
+## Configuration
+
+You can easily configure your deployment by supplying an environment variable file with your desired settings.
+
+An [example environment variable file](config_template.env) is provided for use as a template.
+
+Supported configuration options:
+
+### auth_secret ***(REQUIRED)***
+**string**
+
+*THIS VALUE NEEDS TO BE SET BEFORE THE SERVICE WILL START!*
+
+This is used to authenticate sessions for the shortener control panel and the REST API.
+Depending on configuration, this can either be used as a TOTP secret or as a password.
+
+### enable_control_panel
+**boolean**
+
+Whether or not a static control panel page for interacting with the shortening service will be exposed at `/shorten`.
+
+Default `true`
+
+### enable_landing_page
+**boolean**
+
+Whether or not a static landing page will be served when not visiting shortened links or the control panel.
+
+Default `true`
+
+### landing_page_index
+**string**
+
+The path to the file to use as the index for the landing page.
+
+*This only has an effect when `enable_landing_page` is set to true.*
+
+Default `index.html`
+
+### listen_port
+**number**
+
+The port that the HTTP server will listen on.
+
+Default `80`
+
+### query_limit
+**number**
+
+The maximum number of database entries that the API will return in a single query.
+
+Default `100`
+
+### session_max_length_hours
+**number**
+
+The duration (in hours) that an API session will be valid for once signed in, regardless of activity.
+
+Default `24`
+
+### session_max_idle_length_hours
+**number**
+
+The duration (in hours) that an API session will be valid for without any activity.
+
+Default `1`
+
+### use_secure_cookies
+**boolean**
+
+Whether or not to tag API session cookies with the `Secure` and `SameSite=Strict` attributes.'
+
+Secure cookies expect your server to have HTTPS enabled, and will prevent the control panel and API from functioning over unsecured connections.
+
+Default `true`
+
+### use_totp
+**boolean**
+
+Whether or not `auth_secret` will be used as a TOTP secret instead of a password.
+
+If enabled, the server will print a QR code to stdout containing a standardized URL that you can scan with most TOTP generators.
+
+(TOTP is recommended, but you may want to disable it if (e.g) your system cannot be synchronized to global time.)
+
+Default `true`
+
+## API
+
+The shortening service exposes a simple API at `/shorten/api` that you may consume from your own control panel1, a browser extension, etc.
+
+The API endpoints and response codes are documented in the docstrings of their respective [handler modules](src/handlers).
+
+1 If you wish to replace the default control panel, you can provide your own by mounting it at `/simple-shortener/static/control_panel`.
+
+## TOTP Issuer Icons
+
+Should your TOTP provider application of choice support them, the following issuer icons are available for use.
+
+### SVG
+
+
+
+### PNG
+
+