diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index c9326766..2007f466 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -10,9 +10,10 @@ Contributions to this project are [released](https://help.github.com/articles/gi
 2. Configure and install the dependencies: `go mod download`
 3. Create a new branch: `git checkout -b my-branch-name`
 4. Make your change
-5. Build your code with [GoReleaser](https://goreleaser.com/): `goreleaser release --skip-publish --skip-validate --rm-dist`
-6. Push to your fork and [submit a pull request](https://github.com/crazy-max/diun/compare)
-7. Pat your self on the back and wait for your pull request to be reviewed and merged.
+5. Test your code: `go test -covermode=atomic ./...`
+6. Build with [GoReleaser](https://goreleaser.com/): `goreleaser release --skip-publish --skip-validate --rm-dist`
+7. Push to your fork and [submit a pull request](https://github.com/crazy-max/diun/compare)
+8. Pat your self on the back and wait for your pull request to be reviewed and merged.
 
 Here are a few things you can do that will increase the likelihood of your pull request being accepted:
 
diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md
index 406efb1e..da941917 100644
--- a/.github/SUPPORT.md
+++ b/.github/SUPPORT.md
@@ -1,5 +1,7 @@
 # Support [![](https://isitmaintained.com/badge/resolution/crazy-max/diun.svg)](https://isitmaintained.com/project/crazy-max/diun)
 
+First, [be a good guy](https://github.com/kossnocorp/etiquette/blob/master/README.md).
+
 ## Reporting an issue
 
 Please do a search in [open issues](https://github.com/crazy-max/diun/issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1c6424d4..79763c0c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -9,12 +9,20 @@ on:
       - 'v*'
     paths-ignore:
       - '**.md'
+      - '.github/workflows/docs.yml'
+      - 'docs/**'
+      - 'Dockerfile.mkdocs'
+      - 'mkdocs.yml'
   pull_request:
     branches:
       - 'master'
       - 'v*'
     paths-ignore:
       - '**.md'
+      - '.github/workflows/docs.yml'
+      - 'docs/**'
+      - 'Dockerfile.mkdocs'
+      - 'mkdocs.yml'
 
 jobs:
 
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 00000000..5556a100
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,49 @@
+name: docs
+
+on:
+  push:
+    branches:
+      - 'master'
+      - 'v*'
+    tags:
+      - 'v*'
+    paths:
+      - '.github/workflows/docs.yml'
+      - 'docs/**'
+      - 'Dockerfile.mkdocs'
+      - 'mkdocs.yml'
+  pull_request:
+    branches:
+      - 'master'
+      - 'v*'
+    paths:
+      - '.github/workflows/docs.yml'
+      - 'docs/**'
+      - 'Dockerfile.mkdocs'
+      - 'mkdocs.yml'
+
+jobs:
+  publish:
+    runs-on: ubuntu-latest
+    steps:
+      -
+        name: Checkout
+        uses: actions/checkout@v2
+      -
+        name: Build mkdocs Docker image
+        run: |
+          docker build -t mkdocs -f ./Dockerfile.mkdocs ./
+      -
+        name: Build docs
+        run: |
+          docker run --rm -v "$(pwd):/docs" mkdocs build --strict
+          sudo chown -R $(id -u):$(id -g) ./site
+      -
+        name: Deploy
+        if: success() && github.event_name != 'pull_request' && endsWith(github.ref, github.event.repository.default_branch)
+        uses: crazy-max/ghaction-github-pages@v2
+        with:
+          target_branch: gh-pages
+          build_dir: site
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index bf0cf150..b1ff764f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,5 @@
 .dev
 /bin
 /dist
+
+/site
diff --git a/.res/screenshot.png b/.res/screenshot.png
new file mode 100644
index 00000000..09b8d6dd
Binary files /dev/null and b/.res/screenshot.png differ
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7ec7cfc..e481f023 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
 
 ## 3.0.0 (2020/05/27)
 
+> :warning: See **Migration notes** in the documentation for breaking changes.
+
 * Add script notification (#53)
 * Add Teams notification (#72)
 * Add `--test-notif` flag (#23)
@@ -23,8 +25,6 @@
 * Add upgrade notes
 * Update deps
 
-> :warning: See [**UPGRADE NOTES**](UPGRADE.md#2x--3x) for breaking changes.
-
 ## 2.6.1 (2020/03/26)
 
 * Downgrade containers/image to 5.2.1 (#54)
@@ -66,6 +66,8 @@
 
 ## 2.0.0 (2019/12/14)
 
+> :warning: See **Migration notes** in the documentation for breaking changes.
+
 * Include provider in notifications
 * Add providers documentation
 * Move image validation and improve job execution
@@ -78,8 +80,6 @@
 * Go 1.13.5
 * Seconds field optional for schedule
 
-> :warning: See [**UPGRADE NOTES**](UPGRADE.md#1x--2x) for breaking changes.
-
 ## 1.4.1 (2019/10/20)
 
 * Update deps
@@ -121,6 +121,8 @@
 
 ## 1.0.0 (2019/07/01)
 
+> :warning: See **Migration notes** in the documentation for breaking changes.
+
 * Always run on startup. Flag `--run-startup` removed.
 * Display next execution time
 * Use v3 robfig/cron
@@ -129,8 +131,6 @@
 * Review config file structure
 * Improve worker pool
 
-> :warning: See [**UPGRADE NOTES**](UPGRADE.md#0x--1x) for breaking changes.
-
 ## 0.5.0 (2019/06/09)
 
 * Add worker pool to parallelize analyses
diff --git a/Dockerfile.mkdocs b/Dockerfile.mkdocs
new file mode 100644
index 00000000..ffc851c2
--- /dev/null
+++ b/Dockerfile.mkdocs
@@ -0,0 +1,12 @@
+FROM squidfunk/mkdocs-material:5.3.0
+
+RUN \
+  apk add --no-cache \
+    git \
+    git-fast-import \
+    openssh \
+  && apk add --no-cache --virtual .build gcc musl-dev \
+  && pip install --no-cache-dir \
+    'mkdocs-macros-plugin' \
+  && apk del .build gcc musl-dev \
+  && rm -rf /tmp/*
diff --git a/README.md b/README.md
index 6f631428..e42c8b18 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
 <p align="center"><a href="https://github.com/crazy-max/diun" target="_blank"><img height="128" src="https://raw.githubusercontent.com/crazy-max/diun/master/.res/diun.png"></a></p>
 
 <p align="center">
+  <a href="https://crazy-max.github.io/diun/"><img src="https://img.shields.io/badge/doc-mkdocs-02a6f2?style=flat-square&logo=read-the-docs" alt="Documentation"></a>
   <a href="https://github.com/crazy-max/diun/releases/latest"><img src="https://img.shields.io/github/release/crazy-max/diun.svg?style=flat-square" alt="GitHub release"></a>
   <a href="https://github.com/crazy-max/diun/releases/latest"><img src="https://img.shields.io/github/downloads/crazy-max/diun/total.svg?style=flat-square" alt="Total downloads"></a>
   <a href="https://github.com/crazy-max/diun/actions?workflow=build"><img src="https://img.shields.io/github/workflow/status/crazy-max/diun/build?label=build&logo=github&style=flat-square" alt="Build Status"></a>
@@ -20,38 +21,11 @@
 [Docker image](https://hub.docker.com/r/crazymax/diun/)) to receive notifications when a Docker image is updated on
 a Docker registry.
 
-![](.res/notif-slack.png)
-
-## Features
-
-* Allow to watch a Docker repository and report new tags
-* Include and exclude filters with regular expression for tags
-* Internal cron implementation through go routines
-* Worker pool to parallelize analyses
-* Allow overriding image os and architecture
-* [Docker](doc/providers/docker.md), [Swarm](doc/providers/swarm.md),
-[Kubernetes](doc/providers/kubernetes.md) and [File](doc/providers/file.md) providers available
-* Get notified through Gotify, Mail, Slack, Telegram and [more](doc/notifications.md)
-* Enhanced logging
-* Timezone can be changed
-* Official [Docker image available](doc/install/docker.md)
+![](.res/screenshot.png)
 
 ## Documentation
 
-* Install
-  * [With Docker](doc/install/docker.md)
-  * [From binary](doc/install/binary.md)
-  * [Linux service](doc/install/linux-service.md)
-* [Getting started](doc/getting-started.md)
-* [Configuration](doc/configuration.md)
-* Providers
-  * [Docker](doc/providers/docker.md)
-  * [Swarm](doc/providers/swarm.md)
-  * [Kubernetes](doc/providers/kubernetes.md)
-  * [File](doc/providers/file.md)
-* [Notifications](doc/notifications.md)
-* [FAQ](doc/faq.md)
-* [Upgrade notes](UPGRADE.md)
+Documentation can be found on https://crazy-max.github.io/diun/
 
 ## How can I help?
 
diff --git a/UPGRADE.md b/UPGRADE.md
deleted file mode 100644
index 97149d23..00000000
--- a/UPGRADE.md
+++ /dev/null
@@ -1,158 +0,0 @@
-# Upgrade notes
-
-* [2.x > 3.x](#2x--3x)
-  * [File provider](#file-provider)
-  * [Allow only one Docker and Swarm provider](#allow-only-one-docker-and-swarm-provider)
-  * [Remove `enable` setting for notifiers](#remove-enable-setting-for-notifiers)
-* [1.x > 2.x](#1x--2x)
-* [0.x > 1.x](#0x--1x)
-
-## 2.x > 3.x
-
-### File provider
-
-`static` provider has been renamed `file`. This now allows the static configuration to be declared in one or more files to avoid overloading the current configuration file and also dynamic updating.
-
-> **2.x**
-```yaml
-providers:
-  static:
-    - name: docker.io/crazymax/diun
-      watch_repo: true
-      max_tags: 10
-```
-
-> **3.x**
-```yaml
-providers:
-  file:
-    # Watch images from filename /path/to/config.yml
-    filename: /path/to/config.yml
-    # OR watch images from directory /path/to/config/folder
-    directory: /path/to/config/folder
-```
-```yaml
-# /path/to/config.yml
-- name: docker.io/crazymax/diun
-  watch_repo: true
-  max_tags: 10
-```
-
-### Allow only one Docker and Swarm provider
-
-Now you can declare only one Docker and/or Swarm provider.
-
-> **2.x**
-```yaml
-providers:
-  docker:
-    mydocker:
-      watch_stopped: true
-  providers:
-    swarm:
-      myswarm:
-        watch_by_default: true
-```
-
-> **3.x**
-```yaml
-providers:
-  docker:
-    watch_stopped: true
-  swarm:
-    watch_by_default: true
-```
-
-### Remove `enable` setting for notifiers
-
-The `enable` entry has been removed for notifiers. If you don't want a notifier to be enabled, you must now remove its configuration.
-
-> **2.x**
-```yaml
-notif:
-  amqp:
-    enable: false
-    host: localhost
-    port: 5672
-  gotify:
-    enable: true
-    endpoint: http://gotify.foo.com
-    token: Token123456
-    priority: 1
-    timeout: 10
-```
-
-> **3.x**
-```yaml
-notif:
-  gotify:
-    endpoint: http://gotify.foo.com
-    token: Token123456
-    priority: 1
-    timeout: 10
-```
-
-## 1.x > 2.x
-
-`image` field has been moved to `providers.static` in configuration file:
-
-> **1.x**
-```yaml
-image:
-  - name: docker.io/crazymax/diun
-    watch_repo: true
-    max_tags: 10
-```
-
-> **2.x**
-```yaml
-providers:
-  static:
-    - name: docker.io/crazymax/diun
-      watch_repo: true
-      max_tags: 10
-```
-
-See [providers configuration](doc/configuration.md#providers) for more info.
-
-## 0.x > 1.x
-
-Some fields in configuration file has been changed:
-
-* `registries` renamed `regopts`
-* `items` renamed `image`
-* `items[].image` renamed `image[].name`
-* `items[].registry_id` renamed `image[].regopts_id`
-* `watch.os` and `watch.arch` moved to `image[].os` and `image[].arch`
-
-> **0.x**
-```yaml
-watch:
-  os: linux
-  arch: amd64
-
-registries:
-  someregistryoptions:
-    username: foo
-    password: bar
-    timeout: 20
-
-items:
-  - image: docker.io/crazymax/nextcloud:latest
-    registry_id: someregistryoptions
-```
-
-> **1.x**
-```yaml
-regopts:
-  someregistryoptions:
-    username: foo
-    password: bar
-    timeout: 20
-
-image:
-  - name: docker.io/crazymax/nextcloud:latest
-    regopts_id: someregistryoptions
-    os: linux
-    arch: amd64
-```
diff --git a/doc/install/binary.md b/doc/install/binary.md
deleted file mode 100644
index d2c50cb8..00000000
--- a/doc/install/binary.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Installation from binary
-
-## Download
-
-Diun binaries are available in [releases](https://github.com/crazy-max/diun/releases) page.
-
-Choose the archive matching the destination platform and extract diun:
-
-```
-wget -qO- https://github.com/crazy-max/diun/releases/download/v3.0.0/diun_3.0.0_linux_x86_64.tar.gz | tar -zxvf - diun
-```
-
-After getting the binary, it can be tested with [`./diun --help`](../getting-started.md#diun-cli) command and moved to a permanent location.
-
-## Server configuration
-
-Steps below are the recommended server configuration.
-
-### Prepare environment
-
-Create user to run diun (ex. `diun`)
-
-```
-groupadd diun
-useradd -s /bin/false -d /bin/null -g diun diun
-```
-
-### Create required directory structure
-
-```
-mkdir -p /var/lib/diun
-chown diun:diun /var/lib/diun/
-chmod -R 750 /var/lib/diun/
-mkdir /etc/diun
-chown diun:diun /etc/diun
-chmod 770 /etc/diun
-```
-
-### Configuration
-
-Create your first [configuration](../configuration.md) file in `/etc/diun/diun.yml` and type:
-
-```
-chown diun:diun /etc/diun/diun.yml
-chmod 644 /etc/diun/diun.yml
-```
-
-> 💡 Not required if you want to only rely on environment variables
-
-### Copy binary to global location
-
-```
-cp diun /usr/local/bin/diun
-```
-
-## Running Diun
-
-After the above steps, two options to run Diun:
-
-### 1. Creating a service file (recommended)
-
-See how to create [Linux service](linux-service.md) to start Diun automatically.
-
-### 2. Running from command-line/terminal
-
-```
-DIUN_DB_PATH=/var/lib/diun/diun.db /usr/local/bin/diun --config /etc/diun/diun.yml
-```
-
-## Updating to a new version
-
-You can update to a new version of Diun by stopping it, replacing the binary at `/usr/local/bin/diun` and restarting the instance.
-
-If you have carried out the installation steps as described above, the binary should have the generic name `diun`. Do not change this, i.e. to include the version number.
diff --git a/doc/install/docker.md b/doc/install/docker.md
deleted file mode 100644
index cdec993b..00000000
--- a/doc/install/docker.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# Installation with Docker
-
-Diun provides automatically updated Docker :whale: images within [Docker Hub](https://hub.docker.com/r/crazymax/diun). It is possible to always use the latest stable tag or to use another service that handles updating Docker images.
-
-Following platforms for this image are available:
-
-```
-$ docker run --rm mplatform/mquery crazymax/diun:latest
-Image: crazymax/diun:latest
- * Manifest List: Yes
- * Supported platforms:
-   - linux/amd64
-   - linux/arm/v6
-   - linux/arm/v7
-   - linux/arm64
-   - linux/386
-   - linux/ppc64le
-   - linux/s390x
-```
-
-## Volumes
-
-* `/data`: Contains bbolt database which retains Docker images manifests
-
-## Usage
-
-Docker compose is the recommended way to run this image. Copy the content of folder [.res/compose](../../.res/compose) in `/opt/diun/` on your host for example. Edit the compose file with your preferences and run the following commands:
-
-```
-docker-compose up -d
-docker-compose logs -f
-```
-
-Or use the following command:
-
-```
-$ docker run -d --name diun \
-  -e "TZ=Europe/Paris" \
-  -e "LOG_LEVEL=info" \
-  -e "LOG_JSON=false" \
-  -e "DIUN_WATCH_WORKERS=20" \
-  -e "DIUN_WATCH_SCHEDULE=*/30 * * * *" \
-  -e "DIUN_PROVIDERS_DOCKER=true" \
-  -e "DIUN_PROVIDERS_DOCKER_WATCHSTOPPED=true" \
-  -v "$(pwd)/data:/data" \
-  -v "/var/run/docker.sock:/var/run/docker.sock" \
-  crazymax/diun:latest
-```
-
-To upgrade your installation to the latest release:
-
-```
-docker-compose pull
-docker-compose up -d
-```
diff --git a/doc/install/linux-service.md b/doc/install/linux-service.md
deleted file mode 100644
index abf880b8..00000000
--- a/doc/install/linux-service.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Run as service on Debian based distro
-
-## Using systemd
-
-> :warning: Make sure to follow the instructions to [install from binary](binary.md) before.
-
-Run the below command in a terminal:
-
-```
-sudo vim /etc/systemd/system/diun.service
-```
-
-Copy the sample [diun.service](../../.res/examples/systemd/diun.service).
-
-Change the user, group, and other required startup values following your needs.
-
-Enable and start Diun at boot:
-
-```
-sudo systemctl enable diun
-sudo systemctl start diun
-```
-
-To view logs:
-
-```
-journalctl -fu diun.service
-```
diff --git a/doc/notifications.md b/doc/notifications.md
deleted file mode 100644
index 79e7a3f3..00000000
--- a/doc/notifications.md
+++ /dev/null
@@ -1,267 +0,0 @@
-# Notifications
-
-* [Amqp](#amqp)
-* [Gotify](#gotify)
-* [Mail](#mail)
-* [Rocket.Chat](#rocketchat)
-* [Script](#script)
-* [Slack / Mattermost](#slack--mattermost)
-* [Teams](#teams)
-* [Telegram](#telegram)
-* [Webhook](#webhook)
-
-## Amqp
-
-You can send notifications to any amqp compatible server with the following settings.
-
-### Configuration file
-
-* `amqp`
-  * `host`: AMQP server host (default `localhost`). **required**
-  * `port`: AMQP server port (default `5672`). **required**
-  * `username`: AMQP username.
-  * `usernameFile`: Use content of secret file as AMQP username if `username` not defined.
-  * `password`: AMQP password.
-  * `passwordFile`: Use content of secret file as AMQP password if `password` not defined.
-  * `exchange`: Name of the exchange the message will be sent to.
-  * `queue`: Name of the queue the message will be sent to. **required**
-
-### Environment variables
-
-* `DIUN_NOTIF_AMQP_HOST`
-* `DIUN_NOTIF_AMQP_EXCHANGE`
-* `DIUN_NOTIF_AMQP_PORT`
-* `DIUN_NOTIF_AMQP_USERNAME`
-* `DIUN_NOTIF_AMQP_USERNAMEFILE`
-* `DIUN_NOTIF_AMQP_PASSWORD`
-* `DIUN_NOTIF_AMQP_PASSWORDFILE`
-* `DIUN_NOTIF_AMQP_QUEUE`
-
-### Sample
-
-The JSON response will look like this:
-
-```json
-{
-  "diun_version": "0.3.0",
-  "status": "new",
-  "provider": "file",
-  "image": "docker.io/crazymax/swarm-cronjob:0.2.1",
-  "hub_link": "https://hub.docker.com/r/crazymax/swarm-cronjob",
-  "mime_type": "application/vnd.docker.distribution.manifest.v2+json",
-  "digest": "sha256:5913d4b5e8dc15430c2f47f40e43ab2ca7f2b8df5eee5db4d5c42311e08dfb79",
-  "created": "2019-01-24T10:26:49.152006005Z",
-  "platform": "linux/amd64"
-}
-```
-
-## Gotify
-
-Notifications can be sent using a [Gotify](https://gotify.net/) instance.
-
-### Configuration file
-
-* `gotify`
-  * `endpoint`: Gotify base URL (e.g. `http://gotify.foo.com`). **required**
-  * `token`: Application token. **required**
-  * `priority`: The priority of the message (default `1`).
-  * `timeout`: Timeout specifies a time limit for the request to be made. (default `10s`).
-
-### Environment variables
-
-* `DIUN_NOTIF_GOTIFY_ENDPOINT`
-* `DIUN_NOTIF_GOTIFY_TOKEN`
-* `DIUN_NOTIF_GOTIFY_PRIORITY`
-* `DIUN_NOTIF_GOTIFY_TIMEOUT`
-
-### Sample
-
-![](../.res/notif-gotify.png)
-
-## Mail
-
-Notifications can be sent through SMTP.
-
-### Configuration file
-
-* `mail`
-  * `host`: SMTP server host. (default `localhost`) **required**
-  * `port`: SMTP server port. (default `25`) **required**
-  * `ssl`: SSL defines whether an SSL connection is used. Should be false in most cases since the auth mechanism should use STARTTLS. (default `false`)
-  * `insecureSkipVerify`: Controls whether a client verifies the server's certificate chain and hostname. (default `false`)
-  * `username`: SMTP username.
-  * `usernameFile`: Use content of secret file as SMTP username if `username` not defined.
-  * `password`: SMTP password.
-  * `passwordFile`: Use content of secret file as SMTP password if `password` not defined.
-  * `from`: Sender email address. **required**
-  * `to`: Recipient email address. **required**
-
-### Environment variables
-
-* `DIUN_NOTIF_MAIL_HOST`
-* `DIUN_NOTIF_MAIL_PORT`
-* `DIUN_NOTIF_MAIL_SSL`
-* `DIUN_NOTIF_MAIL_INSECURESKIPVERIFY`
-* `DIUN_NOTIF_MAIL_USERNAME`
-* `DIUN_NOTIF_MAIL_USERNAMEFILE`
-* `DIUN_NOTIF_MAIL_PASSWORD`
-* `DIUN_NOTIF_MAIL_PASSWORDFILE`
-* `DIUN_NOTIF_MAIL_FROM`
-* `DIUN_NOTIF_MAIL_TO`
-
-### Sample
-
-![](../.res/notif-mail.png)
-
-## Rocket.Chat
-
-Allow to send notifications to your Rocket.Chat channel.
-
-> You must first create a _Personal Access Token_ through your account settings on your RocketChat instance.
-
-### Configuration file
-
-* `rocketchat`
-  * `endpoint`: Rocket.Chat base URL (e.g. `http://rocket.foo.com:3000`). **required**
-  * `channel`: Channel name with the prefix in front of it. **required**
-  * `userID`: User ID. **required**
-  * `token`: Authentication token. **required**
-  * `timeout`: Timeout specifies a time limit for the request to be made. (default `10s`).
-
-### Environment variables
-
-* `DIUN_NOTIF_ROCKETCHAT_ENDPOINT`
-* `DIUN_NOTIF_ROCKETCHAT_CHANNEL`
-* `DIUN_NOTIF_ROCKETCHAT_USERID`
-* `DIUN_NOTIF_ROCKETCHAT_TOKEN`
-* `DIUN_NOTIF_ROCKETCHAT_TIMEOUT`
-
-### Sample
-
-![](../.res/notif-rocketchat.png)
-
-## Script
-
-You can call a script when a notification occured. Following environment variables will be passed:
-
-```
-DIUN_VERSION=3.0.0
-DIUN_ENTRY_STATUS=new
-DIUN_ENTRY_PROVIDER=file
-DIUN_ENTRY_IMAGE=docker.io/crazymax/diun:latest
-DIUN_ENTRY_HUBLINK=https://hub.docker.com/r/crazymax/diun
-DIUN_ENTRY_MIMETYPE=application/vnd.docker.distribution.manifest.list.v2+json
-DIUN_ENTRY_DIGEST=sha256:216e3ae7de4ca8b553eb11ef7abda00651e79e537e85c46108284e5e91673e01
-DIUN_ENTRY_CREATED=2020-03-26 12:23:56 +0000 UTC
-DIUN_ENTRY_PLATFORM=linux/amd64
-```
-
-### Configuration file
-
-* `script`
-  * `cmd`: Command or script to execute. **required**
-  * `args`: List of args to pass to `cmd`.
-  * `dir`: Specifies the working directory of the command.
-
-### Environment variables
-
-* `DIUN_NOTIF_SCRIPT_CMD`
-* `DIUN_NOTIF_SCRIPT_ARGS`
-* `DIUN_NOTIF_SCRIPT_DIR`
-
-## Slack / Mattermost
-
-You can send notifications to your Slack channel using an [incoming webhook URL](https://api.slack.com/messaging/webhooks).
-
-### Configuration file
-
-* `slack`
-  * `webhookURL`: Slack [incoming webhook URL](https://api.slack.com/messaging/webhooks). **required**
-
-### Environment variables
-
-* `DIUN_NOTIF_SLACK_WEBHOOKURL`
-
-### Sample
-
-![](../.res/notif-slack.png)
-
-Mattermost webhooks are compatible with Slack notification without any special configuration (if Webhooks are enabled).
-
-## Teams
-
-You can send notifications to your Teams team-channel using an [incoming webhook URL](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/what-are-webhooks-and-connectors).
-
-### Configuration file
-
-* `teams`
-  * `webhookURL`: Teams [incoming webhook URL](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/what-are-webhooks-and-connectors). **required**
-
-### Environment variables
-
-* `DIUN_NOTIF_TEAMS_WEBHOOKURL`
-
-### Sample
-
-![](../.res/notif-teams.png)
-
-## Telegram
-
-Notifications can be sent via Telegram using a [Telegram Bot](https://core.telegram.org/bots).
-
-Follow the [instructions](https://core.telegram.org/bots#6-botfather) to set up a bot and get it's token.
-
-Message the [GetID bot](https://t.me/getidsbot) to find your chat ID.
-Multiple chat IDs can be provided in order to deliver notifications to multiple recipients.
-
-### Configuration file
-
-* `telegram`
-  * `token`: Telegram bot token. **required**
-  * `chatIDs`: List of chat IDs to send notifications to. **required**
-
-### Environment variables
-
-* `DIUN_NOTIF_TELEGRAM_TOKEN`
-* `DIUN_NOTIF_TELEGRAM_CHATIDS` (comma separated)
-
-### Sample
-
-![](../.res/notif-telegram.png)
-
-## Webhook
-
-You can send webhook notifications with the following settings.
-
-### Configuration file
-
-* `webhook`
-  * `endpoint`: URL of the HTTP request. **required**
-  * `method`: HTTP method (default `GET`). **required**
-  * `headers`: Map of additional headers to be sent (key is case insensitive).
-  * `timeout`: Timeout specifies a time limit for the request to be made. (default `10s`)
-
-### Environment variables
-
-* `DIUN_NOTIF_WEBHOOK_ENDPOINT`
-* `DIUN_NOTIF_WEBHOOK_METHOD`
-* `DIUN_NOTIF_WEBHOOK_HEADERS_<KEY>`
-* `DIUN_NOTIF_WEBHOOK_TIMEOUT`
-
-### Sample
-
-The JSON response will look like this:
-
-```json
-{
-  "diun_version": "4.0.0",
-  "status": "new",
-  "provider": "file",
-  "image": "docker.io/crazymax/diun:latest",
-  "hub_link": "https://hub.docker.com/r/crazymax/diun",
-  "mime_type": "application/vnd.docker.distribution.manifest.list.v2+json",
-  "digest": "sha256:216e3ae7de4ca8b553eb11ef7abda00651e79e537e85c46108284e5e91673e01",
-  "created": "2020-03-26T12:23:56Z",
-  "platform": "linux/amd64"
-}
-```
diff --git a/docs/assets/favicon.ico b/docs/assets/favicon.ico
new file mode 100644
index 00000000..18a41f36
Binary files /dev/null and b/docs/assets/favicon.ico differ
diff --git a/docs/assets/logo.png b/docs/assets/logo.png
new file mode 100644
index 00000000..08373132
Binary files /dev/null and b/docs/assets/logo.png differ
diff --git a/docs/assets/meta/apple-touch-icon-114x114.png b/docs/assets/meta/apple-touch-icon-114x114.png
new file mode 100644
index 00000000..86e986b9
Binary files /dev/null and b/docs/assets/meta/apple-touch-icon-114x114.png differ
diff --git a/docs/assets/meta/apple-touch-icon-120x120.png b/docs/assets/meta/apple-touch-icon-120x120.png
new file mode 100644
index 00000000..c5c19e85
Binary files /dev/null and b/docs/assets/meta/apple-touch-icon-120x120.png differ
diff --git a/docs/assets/meta/apple-touch-icon-144x144.png b/docs/assets/meta/apple-touch-icon-144x144.png
new file mode 100644
index 00000000..2e046332
Binary files /dev/null and b/docs/assets/meta/apple-touch-icon-144x144.png differ
diff --git a/docs/assets/meta/apple-touch-icon-152x152.png b/docs/assets/meta/apple-touch-icon-152x152.png
new file mode 100644
index 00000000..f57b54c5
Binary files /dev/null and b/docs/assets/meta/apple-touch-icon-152x152.png differ
diff --git a/docs/assets/meta/apple-touch-icon-57x57.png b/docs/assets/meta/apple-touch-icon-57x57.png
new file mode 100644
index 00000000..c566bee9
Binary files /dev/null and b/docs/assets/meta/apple-touch-icon-57x57.png differ
diff --git a/docs/assets/meta/apple-touch-icon-60x60.png b/docs/assets/meta/apple-touch-icon-60x60.png
new file mode 100644
index 00000000..b29fb35f
Binary files /dev/null and b/docs/assets/meta/apple-touch-icon-60x60.png differ
diff --git a/docs/assets/meta/apple-touch-icon-72x72.png b/docs/assets/meta/apple-touch-icon-72x72.png
new file mode 100644
index 00000000..f64240a4
Binary files /dev/null and b/docs/assets/meta/apple-touch-icon-72x72.png differ
diff --git a/docs/assets/meta/apple-touch-icon-76x76.png b/docs/assets/meta/apple-touch-icon-76x76.png
new file mode 100644
index 00000000..a45c446d
Binary files /dev/null and b/docs/assets/meta/apple-touch-icon-76x76.png differ
diff --git a/docs/assets/meta/card.png b/docs/assets/meta/card.png
new file mode 100644
index 00000000..b3ae6cfd
Binary files /dev/null and b/docs/assets/meta/card.png differ
diff --git a/docs/assets/meta/favicon-128.png b/docs/assets/meta/favicon-128.png
new file mode 100644
index 00000000..8d0537f6
Binary files /dev/null and b/docs/assets/meta/favicon-128.png differ
diff --git a/docs/assets/meta/favicon-16x16.png b/docs/assets/meta/favicon-16x16.png
new file mode 100644
index 00000000..4099a2cb
Binary files /dev/null and b/docs/assets/meta/favicon-16x16.png differ
diff --git a/docs/assets/meta/favicon-196x196.png b/docs/assets/meta/favicon-196x196.png
new file mode 100644
index 00000000..aafbc648
Binary files /dev/null and b/docs/assets/meta/favicon-196x196.png differ
diff --git a/docs/assets/meta/favicon-32x32.png b/docs/assets/meta/favicon-32x32.png
new file mode 100644
index 00000000..9ba59094
Binary files /dev/null and b/docs/assets/meta/favicon-32x32.png differ
diff --git a/docs/assets/meta/favicon-96x96.png b/docs/assets/meta/favicon-96x96.png
new file mode 100644
index 00000000..6a5aec44
Binary files /dev/null and b/docs/assets/meta/favicon-96x96.png differ
diff --git a/docs/assets/meta/mstile-144x144.png b/docs/assets/meta/mstile-144x144.png
new file mode 100644
index 00000000..2e046332
Binary files /dev/null and b/docs/assets/meta/mstile-144x144.png differ
diff --git a/docs/assets/meta/mstile-150x150.png b/docs/assets/meta/mstile-150x150.png
new file mode 100644
index 00000000..46ee522e
Binary files /dev/null and b/docs/assets/meta/mstile-150x150.png differ
diff --git a/docs/assets/meta/mstile-310x150.png b/docs/assets/meta/mstile-310x150.png
new file mode 100644
index 00000000..13ba8dcd
Binary files /dev/null and b/docs/assets/meta/mstile-310x150.png differ
diff --git a/docs/assets/meta/mstile-310x310.png b/docs/assets/meta/mstile-310x310.png
new file mode 100644
index 00000000..df0f9d07
Binary files /dev/null and b/docs/assets/meta/mstile-310x310.png differ
diff --git a/docs/assets/meta/mstile-70x70.png b/docs/assets/meta/mstile-70x70.png
new file mode 100644
index 00000000..8d0537f6
Binary files /dev/null and b/docs/assets/meta/mstile-70x70.png differ
diff --git a/.res/notif-gotify.png b/docs/assets/notif/gotify.png
similarity index 100%
rename from .res/notif-gotify.png
rename to docs/assets/notif/gotify.png
diff --git a/.res/notif-mail.png b/docs/assets/notif/mail.png
similarity index 100%
rename from .res/notif-mail.png
rename to docs/assets/notif/mail.png
diff --git a/.res/notif-rocketchat.png b/docs/assets/notif/rocketchat.png
similarity index 100%
rename from .res/notif-rocketchat.png
rename to docs/assets/notif/rocketchat.png
diff --git a/.res/notif-slack.png b/docs/assets/notif/slack.png
similarity index 100%
rename from .res/notif-slack.png
rename to docs/assets/notif/slack.png
diff --git a/.res/notif-teams.png b/docs/assets/notif/teams.png
similarity index 100%
rename from .res/notif-teams.png
rename to docs/assets/notif/teams.png
diff --git a/.res/notif-telegram.png b/docs/assets/notif/telegram.png
similarity index 100%
rename from .res/notif-telegram.png
rename to docs/assets/notif/telegram.png
diff --git a/docs/config/db.md b/docs/config/db.md
new file mode 100644
index 00000000..26778726
--- /dev/null
+++ b/docs/config/db.md
@@ -0,0 +1,15 @@
+# Database configuration
+
+## `path`
+
+Path to Bolt database file where images manifests are stored. (default `diun.db`)
+
+!!! example "Config file"
+    ```yaml
+    db:
+      path:
+        token: diun.db
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_DB_PATH`
diff --git a/doc/configuration.md b/docs/config/index.md
similarity index 50%
rename from doc/configuration.md
rename to docs/config/index.md
index abe4a4a1..d0e5d2a6 100644
--- a/doc/configuration.md
+++ b/docs/config/index.md
@@ -1,17 +1,8 @@
 # Configuration
 
-* [Overview](#overview)
-* [Configuration file](#configuration-file)
-* [Reference](#reference)
-  * [db](#db)
-  * [watch](#watch)
-  * [notif](#notif)
-  * [regopts](#regopts)
-  * [providers](#providers)
-
 ## Overview
 
-There are two different ways to define static configuration options in Diun:
+There are two different ways to define configuration in Diun:
 
 * In a [configuration file](#configuration-file)
 * As environment variables
@@ -90,7 +81,7 @@ regopts:
   onemore:
     username: foo2
     password: bar2
-    insecureTls: true
+    insecureTLS: true
 
 providers:
   docker:
@@ -107,59 +98,21 @@ providers:
 
 ## Reference
 
-### db
-
-* `path`: Path to Bolt database file where images manifests are stored. (default `diun.db`)
-
-You can also use the following environment variables:
-
-* `DIUN_DB_PATH`
-
-### watch
-
-* `workers`: Maximum number of workers that will execute tasks concurrently. (default `10`)
-* `schedule`: [CRON expression](https://godoc.org/github.com/robfig/cron#hdr-CRON_Expression_Format) to schedule Diun watcher. (default `0 * * * *`)
-* `firstCheckNotif`: Send notification at the very first analysis of an image. (default `false`)
-
-You can also use the following environment variables:
-
-* `DIUN_WATCH_WORKERS`
-* `DIUN_WATCH_SCHEDULE`
-* `DIUN_WATCH_FIRSTCHECKNOTIF`
-
-### notif
-
-* [amqp](notifications.md#amqp)
-* [gotify](notifications.md#gotify)
-* [mail](notifications.md#mail)
-* [rocketchat](notifications.md#rocketchat)
-* [script](notifications.md#script)
-* [slack](notifications.md#slack--mattermost)
-* [teams](notifications.md#teams)
-* [telegram](notifications.md#telegram)
-* [webhook](notifications.md#webhook)
-
-### regopts
-
-* `username`: Registry username.
-* `usernameFile`: Use content of secret file as registry username if `username` not defined.
-* `password`: Registry password.
-* `passwordFile`: Use content of secret file as registry password if `password` not defined.
-* `timeout`: Timeout is the maximum amount of time for the TCP connection to establish. (default `10s`)
-* `insecureTls`: Allow contacting docker registry over HTTP, or HTTPS with failed TLS verification. (default `false`)
-
-You can also use the following environment variables:
-
-* `DIUN_REGOPTS_<NAME>_USERNAME`
-* `DIUN_REGOPTS_<NAME>_USERNAMEFILE`
-* `DIUN_REGOPTS_<NAME>_PASSWORD`
-* `DIUN_REGOPTS_<NAME>_PASSWORDFILE`
-* `DIUN_REGOPTS_<NAME>_TIMEOUT`
-* `DIUN_REGOPTS_<NAME>_INSECURETLS`
-
-### providers
-
-* [docker](providers/docker.md)
-* [swarm](providers/swarm.md)
-* [kubernetes](providers/kubernetes.md)
-* [file](providers/file.md)
+* [db](db.md)
+* [watch](watch.md)
+* notif
+    * [amqp](../notif/amqp.md)
+    * [gotify](../notif/amqp.md)
+    * [mail](../notif/amqp.md)
+    * [rocketchat](../notif/amqp.md)
+    * [script](../notif/amqp.md)
+    * [slack](../notif/amqp.md)
+    * [teams](../notif/amqp.md)
+    * [telegram](../notif/amqp.md)
+    * [webhook](../notif/amqp.md)
+* [regopts](regopts.md)
+* providers
+    * [docker](../providers/docker.md)
+    * [file](../providers/file.md)
+    * [kubernetes](../providers/kubernetes.md)
+    * [swarm](../providers/swarm.md)
diff --git a/docs/config/notif.md b/docs/config/notif.md
new file mode 100644
index 00000000..7ca66290
--- /dev/null
+++ b/docs/config/notif.md
@@ -0,0 +1,11 @@
+# Notifications configuration
+
+* [`amqp`](../notif/amqp.md)
+* [`gotify`](../notif/gotify.md)
+* [`mail`](../notif/mail.md)
+* [`rocketchat`](../notif/rocketchat.md)
+* [`script`](../notif/script.md)
+* [`slack`](../notif/slack.md)
+* [`teams`](../notif/teams.md)
+* [`telegram`](../notif/telegram.md)
+* [`webhook`](../notif/webhook.md)
diff --git a/docs/config/providers.md b/docs/config/providers.md
new file mode 100644
index 00000000..03360cd6
--- /dev/null
+++ b/docs/config/providers.md
@@ -0,0 +1,6 @@
+# Providers configuration
+
+* [`docker`](../providers/docker.md)
+* [`file`](../providers/file.md)
+* [`kubernetes`](../providers/kubernetes.md)
+* [`swarm`](../providers/swarm.md)
diff --git a/docs/config/regopts.md b/docs/config/regopts.md
new file mode 100644
index 00000000..6b4c5eb3
--- /dev/null
+++ b/docs/config/regopts.md
@@ -0,0 +1,87 @@
+# Registries options configuration
+
+## `username`
+
+Registry username.
+
+!!! example "Config file"
+    ```yaml
+    regopts:
+      <name>:
+        username: foo
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_REGOPTS_<NAME>_USERNAME`
+
+## `usernameFile`
+
+Use content of secret file as registry username if `username` not defined.
+
+!!! example "Config file"
+    ```yaml
+    regopts:
+      <name>:
+        usernameFile: /run/secrets/username
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_REGOPTS_<NAME>_USERNAMEFILE`
+
+## `password`
+
+Registry password.
+
+!!! example "Config file"
+    ```yaml
+    regopts:
+      <name>:
+        username: foo
+        password: bar
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_REGOPTS_<NAME>_PASSWORD`
+
+## `passwordFile`
+
+Use content of secret file as registry password if `password` not defined.
+
+!!! example "Config file"
+    ```yaml
+    regopts:
+      <name>:
+        usernameFile: /run/secrets/username
+        usernameFile: /run/secrets/password
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_REGOPTS_<NAME>_PASSWORDFILE`
+
+## `timeout`
+
+Timeout is the maximum amount of time for the TCP connection to establish. (default `10s`)
+
+!!! example "Config file"
+    ```yaml
+    regopts:
+      <name>:
+        timeout: 10s
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_REGOPTS_<NAME>_TIMEOUT`
+
+## `insecureTLS`
+
+Allow contacting docker registry over HTTP, or HTTPS with failed TLS verification. (default `false`)
+
+!!! example "Config file"
+    ```yaml
+    regopts:
+      <name>:
+        insecureTLS: false
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_REGOPTS_<NAME>_INSECURETLS`
diff --git a/docs/config/watch.md b/docs/config/watch.md
new file mode 100644
index 00000000..b148596a
--- /dev/null
+++ b/docs/config/watch.md
@@ -0,0 +1,40 @@
+# Watch configuration
+
+## `workers`
+
+Maximum number of workers that will execute tasks concurrently. (default `10`)
+
+!!! example "Config file"
+    ```yaml
+    watch:
+      workers: 10
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_WATCH_WORKERS`
+
+## `schedule`
+
+[CRON expression](https://godoc.org/github.com/robfig/cron#hdr-CRON_Expression_Format) to schedule Diun watcher. (default `0 * * * *`)
+
+!!! example "Config file"
+    ```yaml
+    watch:
+      schedule: "0 * * * *"
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_WATCH_SCHEDULE`
+
+## `firstCheckNotif`
+
+Send notification at the very first analysis of an image. (default `false`)
+
+!!! example "Config file"
+    ```yaml
+    watch:
+      firstCheckNotif: false
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_WATCH_FIRSTCHECKNOTIF`
diff --git a/docs/contributing.md b/docs/contributing.md
new file mode 100644
index 00000000..503251d2
--- /dev/null
+++ b/docs/contributing.md
@@ -0,0 +1,29 @@
+# Contributing
+
+Hi there! I'm thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
+
+Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license]({{ config.repo_url }}/blob/master/LICENSE).
+
+## Submitting a pull request
+
+1. [Fork]({{ config.repo_url }}fork) and clone the repository
+2. Configure and install the dependencies: `go mod download`
+3. Create a new branch: `git checkout -b my-branch-name`
+4. Make your changes
+5. Test your code: `go test -covermode=atomic ./...`
+6. Build with [GoReleaser](https://goreleaser.com/): `goreleaser release --skip-publish --skip-validate`
+7. Push to your fork and [submit a pull request]({{ config.repo_url }}compare)
+8. Pat your self on the back and wait for your pull request to be reviewed and merged.
+
+Here are a few things you can do that will increase the likelihood of your pull request being accepted:
+
+* Make sure the `README.md` and any other relevant **documentation are kept up-to-date**.
+* I try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
+* Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**.
+* Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
+
+## Resources
+
+* [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
+* [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
+* [GitHub Help](https://help.github.com)
diff --git a/docs/css/extra.css b/docs/css/extra.css
new file mode 100644
index 00000000..a5fc376d
--- /dev/null
+++ b/docs/css/extra.css
@@ -0,0 +1,3 @@
+.md-typeset__table code {
+  word-break: normal;
+}
diff --git a/docs/donate.md b/docs/donate.md
new file mode 100644
index 00000000..1f4edb60
--- /dev/null
+++ b/docs/donate.md
@@ -0,0 +1,5 @@
+**Diun** :bell: is free and open source and always will be.
+
+All kinds of contributions are welcome! The most basic way to show your support is to [star the project]({{ config.repo_rul }}), or to raise issues.
+
+You can also support this project by [**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max) or by making a [Paypal donation](https://www.paypal.me/crazyws) to ensure this journey continues indefinitely!
diff --git a/doc/faq.md b/docs/faq.md
similarity index 79%
rename from doc/faq.md
rename to docs/faq.md
index 5695b6aa..e0157e50 100644
--- a/doc/faq.md
+++ b/docs/faq.md
@@ -1,21 +1,17 @@
 # FAQ
 
-* [Test notifications](#test-notifications)
-* [field docker|swarm uses unsupported type: invalid](#field-dockerswarm-uses-unsupported-type-invalid)
-* [No image found in manifest list for architecture [], variant [], OS []](#no-image-found-in-manifest-list-for-architecture--variant--os-)
-
 ## Test notifications
 
-Through the [command line](getting-started.md#diun-cli) with:
+Through the [command line](get-started.md#diun-cli) with:
 
-```
-diun --config ./diun.yml --test-notif
+```shell
+$ diun --config ./diun.yml --test-notif
 ```
 
 Or within a container:
 
-```
-docker-compose exec diun --test-notif
+```shell
+$ docker-compose exec diun --test-notif
 ```
 
 ## field docker|swarm uses unsupported type: invalid
@@ -34,7 +30,7 @@ providers:
   docker: {}
 ```
 
-## No image found in manifest list for architecture [], variant [], OS []
+## No image found in manifest list for architecture, variant, OS
 
 If you encounter this kind of error, you are probably using the [file provider](providers/file.md) containing an image with an erroneous or empty platform. If the platform is not filled in, it will be deduced automatically from the information of your operating system on which Diun is running.
 
diff --git a/doc/getting-started.md b/docs/get-started.md
similarity index 53%
rename from doc/getting-started.md
rename to docs/get-started.md
index 33296c46..82b44bcf 100644
--- a/doc/getting-started.md
+++ b/docs/get-started.md
@@ -1,7 +1,28 @@
-# Getting started
+## What is Diun?
 
-* [Diun CLI](#diun-cli)
-* [Run with the Docker provider](#run-with-the-docker-provider)
+**D**ocker **I**mage **U**pdate **N**otifier is a CLI application written in [Go](https://golang.org/) and delivered as a
+[single executable](https://github.com/crazy-max/diun/releases/latest) (and a [Docker image](install/docker.md))
+to receive notifications when a Docker image is updated on a Docker registry.
+
+## Purpose
+
+The goal of this project is to provide the easiest, fastest, and most painless way of setting up a self-hosted service to handle this.
+With Go, this can be done with an independent binary distribution across all platforms and architectures that Go supports.
+This support includes Linux, macOS, and Windows, on architectures like amd64, i386, ARM, PowerPC, and others.
+
+## Features
+
+* Allow to watch a Docker repository and report new tags
+* Include and exclude filters with regular expression for tags
+* Internal cron implementation through go routines
+* Worker pool to parallelize analyses
+* Allow overriding image os and architecture
+* [Docker](providers/docker.md), [Swarm](providers/swarm.md), [Kubernetes](providers/kubernetes.md)
+and [File](providers/file.md) providers available
+* Get notified through Gotify, Mail, Slack, Telegram and [more](config/index.md#reference)
+* Enhanced logging
+* Timezone can be changed
+* Official [Docker image available](install/docker.md)
 
 ## Diun CLI
 
@@ -24,11 +45,13 @@ Flags:
 
 Following environment variables can be used in place of flags:
 
-* `CONFIG`: Diun configuration file
-* `TZ`: Timezone assigned (default `UTC`)
-* `LOG_LEVEL`: Log level output (default `info`)
-* `LOG_JSON`: Enable JSON logging output (default `false`)
-* `LOG_CALLER`: Enable to add `file:line` of the caller (default `false`)
+| Name               | Default       | Description   |
+|--------------------|---------------|---------------|
+| `CONFIG`           |               | Diun configuration file |
+| `TZ`               | `UTC`         | Timezone assigned |
+| `LOG_LEVEL`        | `info`        | Log level output |
+| `LOG_JSON`         | `false`       | Enable JSON logging output |
+| `LOG_CALLER`       | `false`       | Enable to add `file:line` of the caller |
 
 ## Run with the Docker provider
 
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..77075b8e
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,4 @@
+---
+template: home.html
+title: Diun
+---
diff --git a/docs/install/binary.md b/docs/install/binary.md
new file mode 100644
index 00000000..393ce809
--- /dev/null
+++ b/docs/install/binary.md
@@ -0,0 +1,89 @@
+# Installation from binary
+
+## Download
+
+Diun binaries are available on [releases]({{ config.repo_url }}releases) page.
+
+Choose the archive matching the destination platform:
+
+* [diun_{{ app.version }}_darwin_i386.tar.gz]({{ config.repo_url }}releases/download/v{{ app.version }}/diun_{{ app.version }}_darwin_i386.tar.gz)
+* [diun_{{ app.version }}_darwin_x86_64.tar.gz]({{ config.repo_url }}/releases/download/v{{ app.version }}/diun_{{ app.version }}_darwin_x86_64.tar.gz)
+* [diun_{{ app.version }}_freebsd_i386.tar.gz]({{ config.repo_url }}/releases/download/v{{ app.version }}/diun_{{ app.version }}_freebsd_i386.tar.gz)
+* [diun_{{ app.version }}_freebsd_x86_64.tar.gz]({{ config.repo_url }}/releases/download/v{{ app.version }}/diun_{{ app.version }}_freebsd_x86_64.tar.gz)
+* [diun_{{ app.version }}_linux_arm64.tar.gz]({{ config.repo_url }}/releases/download/v{{ app.version }}/diun_{{ app.version }}_linux_arm64.tar.gz)
+* [diun_{{ app.version }}_linux_armv6.tar.gz]({{ config.repo_url }}/releases/download/v{{ app.version }}/diun_{{ app.version }}_linux_armv6.tar.gz)
+* [diun_{{ app.version }}_linux_armv7.tar.gz]({{ config.repo_url }}/releases/download/v{{ app.version }}/diun_{{ app.version }}_linux_armv7.tar.gz)
+* [diun_{{ app.version }}_linux_i386.tar.gz]({{ config.repo_url }}/releases/download/v{{ app.version }}/diun_{{ app.version }}_linux_i386.tar.gz)
+* [diun_{{ app.version }}_linux_x86_64.tar.gz]({{ config.repo_url }}/releases/download/v{{ app.version }}/diun_{{ app.version }}_linux_x86_64.tar.gz)
+* [diun_{{ app.version }}_windows_i386.zip]({{ config.repo_url }}/releases/download/v{{ app.version }}/diun_{{ app.version }}_windows_i386.zip)
+* [diun_{{ app.version }}_windows_x86_64.zip]({{ config.repo_url }}/releases/download/v{{ app.version }}/diun_{{ app.version }}_windows_x86_64.zip)
+
+And extract diun:
+
+```shell
+$ wget -qO- {{ config.repo_url }}releases/download/v{{ app.version }}/diun_{{ app.version }}_linux_x86_64.tar.gz | tar -zxvf - diun
+```
+
+After getting the binary, it can be tested with [`./diun --help`](../get-started.md#diun-cli) command and moved to a permanent location.
+
+## Server configuration
+
+Steps below are the recommended server configuration.
+
+### Prepare environment
+
+Create user to run diun (ex. `diun`)
+
+```shell
+$ groupadd diun
+$ useradd -s /bin/false -d /bin/null -g diun diun
+```
+
+### Create required directory structure
+
+```shell
+$ mkdir -p /var/lib/diun
+$ chown diun:diun /var/lib/diun/
+$ chmod -R 750 /var/lib/diun/
+$ mkdir /etc/diun
+$ chown diun:diun /etc/diun
+$ chmod 770 /etc/diun
+```
+
+### Configuration
+
+Create your first [configuration](../config/index.md) file in `/etc/diun/diun.yml` and type:
+
+```shell
+$ chown diun:diun /etc/diun/diun.yml
+$ chmod 644 /etc/diun/diun.yml
+```
+
+!!! note
+    Not required if you want to only rely on environment variables
+
+### Copy binary to global location
+
+```shell
+$ cp diun /usr/local/bin/diun
+```
+
+## Running Diun
+
+After the above steps, two options to run Diun:
+
+### 1. Creating a service file (recommended)
+
+See how to create [Linux service](linux-service.md) to start Diun automatically.
+
+### 2. Running from terminal
+
+```shell
+$ DIUN_DB_PATH=/var/lib/diun/diun.db /usr/local/bin/diun --config /etc/diun/diun.yml
+```
+
+## Updating to a new version
+
+You can update to a new version of Diun by stopping it, replacing the binary at `/usr/local/bin/diun` and restarting the instance.
+
+If you have carried out the installation steps as described above, the binary should have the generic name `diun`. Do not change this, i.e. to include the version number.
diff --git a/docs/install/docker.md b/docs/install/docker.md
new file mode 100644
index 00000000..e7742441
--- /dev/null
+++ b/docs/install/docker.md
@@ -0,0 +1,85 @@
+# Installation with Docker
+
+Diun provides automatically updated Docker :whale: images within [Docker Hub](https://hub.docker.com/r/crazymax/diun).
+It is possible to always use the latest stable tag or to use another service that handles updating Docker images.
+
+Following platforms for this image are available:
+
+```shell
+$ docker run --rm mplatform/mquery crazymax/diun:latest
+Image: crazymax/diun:latest
+ * Manifest List: Yes
+ * Supported platforms:
+   - linux/amd64
+   - linux/arm/v6
+   - linux/arm/v7
+   - linux/arm64
+   - linux/386
+   - linux/ppc64le
+   - linux/s390x
+```
+
+## Volumes
+
+| Path               | Description   |
+|--------------------|---------------|
+| `/data`            | Contains bbolt database which retains Docker images manifests |
+
+## Usage
+
+Docker compose is the recommended way to run this image. Copy the following `docker-compose.yml` in `/opt/diun/` on your host for example:
+
+```yaml
+version: "3.5"
+
+services:
+  diun:
+    image: crazymax/diun:latest
+    container_name: diun
+    volumes:
+      - "./data:/data"
+      - "/var/run/docker.sock:/var/run/docker.sock"
+    environment:
+      - "TZ=Europe/Paris"
+      - "LOG_LEVEL=info"
+      - "LOG_JSON=false"
+      - "DIUN_WATCH_WORKERS=20"
+      - "DIUN_WATCH_SCHEDULE=*/30 * * * *"
+      - "DIUN_PROVIDERS_DOCKER=true"
+    labels:
+      - "diun.enable=true"
+      - "diun.watch_repo=true"
+    restart: always
+```
+
+Edit this example with your preferences and run the following commands to bring up Diun:
+
+```shell
+$ docker-compose up -d
+$ docker-compose logs -f
+```
+
+Or use the following command:
+
+```shell
+$ docker run -d --name diun \
+  -e "TZ=Europe/Paris" \
+  -e "LOG_LEVEL=info" \
+  -e "LOG_JSON=false" \
+  -e "DIUN_WATCH_WORKERS=20" \
+  -e "DIUN_WATCH_SCHEDULE=*/30 * * * *" \
+  -e "DIUN_PROVIDERS_DOCKER=true" \
+  -e "DIUN_PROVIDERS_DOCKER_WATCHSTOPPED=true" \
+  -v "$(pwd)/data:/data" \
+  -v "/var/run/docker.sock:/var/run/docker.sock" \
+  -l "diun.enable=true" \
+  -l "diun.watch_repo=true" \
+  crazymax/diun:latest
+```
+
+To upgrade your installation to the latest release:
+
+```shell
+$ docker-compose pull
+$ docker-compose up -d
+```
diff --git a/docs/install/linux-service.md b/docs/install/linux-service.md
new file mode 100644
index 00000000..be4ed309
--- /dev/null
+++ b/docs/install/linux-service.md
@@ -0,0 +1,43 @@
+# Run as service on Debian based distro
+
+## Using systemd
+
+!!! warning
+    Make sure to follow the instructions to [install from binary](binary.md) before.
+
+To create a new service, paste this content in `/etc/systemd/system/diun.service`:
+
+```
+[Unit]
+Description=Diun
+Documentation={{ config.site_url }}
+After=syslog.target
+After=network.target
+
+[Service]
+RestartSec=2s
+Type=simple
+User=diun
+Group=diun
+ExecStart=/usr/local/bin/diun --config /etc/diun/diun.yml --log-level info
+Restart=always
+Environment=DIUN_DB_PATH=/var/lib/diun/diun.db
+
+[Install]
+WantedBy=multi-user.target
+```
+
+Change the user, group, and other required startup values following your needs.
+
+Enable and start Diun at boot:
+
+```shell
+$ sudo systemctl enable diun
+$ sudo systemctl start diun
+```
+
+To view logs:
+
+```shell
+$ journalctl -fu diun.service
+```
diff --git a/docs/migration/v0-to-v1.md b/docs/migration/v0-to-v1.md
new file mode 100644
index 00000000..55ce74d8
--- /dev/null
+++ b/docs/migration/v0-to-v1.md
@@ -0,0 +1,43 @@
+# Diun v0 to v1
+
+Some fields in configuration file has been changed:
+
+* `registries` renamed `regopts`
+* `items` renamed `image`
+* `items[].image` renamed `image[].name`
+* `items[].registry_id` renamed `image[].regopts_id`
+* `watch.os` and `watch.arch` moved to `image[].os` and `image[].arch`
+
+!!! example "v0"
+    ```yaml
+    watch:
+      os: linux
+      arch: amd64
+    
+    registries:
+      someregistryoptions:
+        username: foo
+        password: bar
+        timeout: 20
+    
+    items:
+      - image: docker.io/crazymax/nextcloud:latest
+        registry_id: someregistryoptions
+    ```
+
+!!! example "v1"
+    ```yaml
+    watch:
+      os: linux
+      arch: amd64
+    
+    registries:
+      someregistryoptions:
+        username: foo
+        password: bar
+        timeout: 20
+    
+    items:
+      - image: docker.io/crazymax/nextcloud:latest
+        registry_id: someregistryoptions
+    ```
diff --git a/docs/migration/v1-to-v2.md b/docs/migration/v1-to-v2.md
new file mode 100644
index 00000000..9d9b4b1a
--- /dev/null
+++ b/docs/migration/v1-to-v2.md
@@ -0,0 +1,20 @@
+# Diun v1 to v2
+
+`image` field has been moved to `providers.static` in configuration file:
+
+!!! example "v1"
+    ```yaml
+    image:
+      - name: docker.io/crazymax/diun
+        watch_repo: true
+        max_tags: 10
+    ```
+
+!!! example "v2"
+    ```yaml
+    providers:
+      static:
+        - name: docker.io/crazymax/diun
+          watch_repo: true
+          max_tags: 10
+    ```
diff --git a/docs/migration/v2-to-v3.md b/docs/migration/v2-to-v3.md
new file mode 100644
index 00000000..47ea4bc3
--- /dev/null
+++ b/docs/migration/v2-to-v3.md
@@ -0,0 +1,83 @@
+# Diun v2 to v3
+
+## File provider
+
+`static` provider has been renamed `file`. This now allows the static configuration to be declared in one or more files to avoid overloading the current configuration file and also dynamic updating.
+
+!!! example "v2"
+    ```yaml
+    providers:
+      static:
+        - name: docker.io/crazymax/diun
+          watch_repo: true
+          max_tags: 10
+    ```
+
+!!! example "v3"
+    ```yaml
+    providers:
+      file:
+        # Watch images from filename /path/to/config.yml
+        filename: /path/to/config.yml
+        # OR watch images from directory /path/to/config/folder
+        directory: /path/to/config/folder
+    ```
+    ```yaml
+    # /path/to/config.yml
+    - name: docker.io/crazymax/diun
+      watch_repo: true
+      max_tags: 10
+    ```
+
+## Allow only one Docker and Swarm provider
+
+Now you can declare only one Docker and/or Swarm provider. This is due to a limitation of the Docker engine.
+
+!!! example "v2"
+    ```yaml
+    providers:
+      docker:
+        mydocker:
+          watch_stopped: true
+      swarm:
+        myswarm:
+          watch_by_default: true
+    ```
+
+!!! example "v3"
+    ```yaml
+    providers:
+      docker:
+        watch_stopped: true
+      swarm:
+        watch_by_default: true
+    ```
+
+## Remove `enable` setting for notifiers
+
+The `enable` entry has been removed for notifiers. If you don't want a notifier to be enabled, you must now remove or comment its configuration.
+
+!!! example "v2"
+    ```yaml
+    notif:
+      amqp:
+        enable: false
+        host: localhost
+        port: 5672
+      gotify:
+        enable: true
+        endpoint: http://gotify.foo.com
+        token: Token123456
+        priority: 1
+        timeout: 10
+    ```
+
+!!! example "v3"
+    ```yaml
+    notif:
+      gotify:
+        endpoint: http://gotify.foo.com
+        token: Token123456
+        priority: 1
+        timeout: 10
+    ```
diff --git a/docs/notif/amqp.md b/docs/notif/amqp.md
new file mode 100644
index 00000000..c5f7da3f
--- /dev/null
+++ b/docs/notif/amqp.md
@@ -0,0 +1,57 @@
+# Amqp notifications
+
+You can send notifications to any amqp compatible server with the following settings.
+
+## Configuration
+
+!!! example "File"
+    ```yaml
+    notif:
+      amqp:
+        host: localhost
+        port: 5672
+        username: guest
+        password: guest
+        queue: queue
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_NOTIF_AMQP_HOST`
+    * `DIUN_NOTIF_AMQP_EXCHANGE`
+    * `DIUN_NOTIF_AMQP_PORT`
+    * `DIUN_NOTIF_AMQP_USERNAME`
+    * `DIUN_NOTIF_AMQP_USERNAMEFILE`
+    * `DIUN_NOTIF_AMQP_PASSWORD`
+    * `DIUN_NOTIF_AMQP_PASSWORDFILE`
+    * `DIUN_NOTIF_AMQP_QUEUE`
+
+| Name               | Default       | Description   |
+|--------------------|---------------|---------------|
+| `host`[^1]         | `localhost`   | AMQP server host |
+| `port`[^1]         | `5672`        | AMQP server port |
+| `username`         |               | AMQP username |
+| `usernameFile`     |               | Use content of secret file as AMQP username if `username` not defined |
+| `password`         |               | AMQP password |
+| `passwordFile`     |               | Use content of secret file as AMQP password if `password` not defined |
+| `exchange`         |               | Name of the exchange the message will be sent to |
+| `queue`[^1]        |               | Name of the queue the message will be sent to |
+
+## Sample
+
+The JSON response will look like this:
+
+```json
+{
+  "diun_version": "0.3.0",
+  "status": "new",
+  "provider": "file",
+  "image": "docker.io/crazymax/swarm-cronjob:0.2.1",
+  "hub_link": "https://hub.docker.com/r/crazymax/swarm-cronjob",
+  "mime_type": "application/vnd.docker.distribution.manifest.v2+json",
+  "digest": "sha256:5913d4b5e8dc15430c2f47f40e43ab2ca7f2b8df5eee5db4d5c42311e08dfb79",
+  "created": "2019-01-24T10:26:49.152006005Z",
+  "platform": "linux/amd64"
+}
+```
+
+[^1]: Value required
diff --git a/docs/notif/gotify.md b/docs/notif/gotify.md
new file mode 100644
index 00000000..274224a7
--- /dev/null
+++ b/docs/notif/gotify.md
@@ -0,0 +1,34 @@
+# Amqp notifications
+
+Notifications can be sent using a [Gotify](https://gotify.net/) instance.
+
+## Configuration
+
+!!! example "File"
+    ```yaml
+    notif:
+      gotify:
+        endpoint: http://gotify.foo.com
+        token: Token123456
+        priority: 1
+        timeout: 10s
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_NOTIF_GOTIFY_ENDPOINT`
+    * `DIUN_NOTIF_GOTIFY_TOKEN`
+    * `DIUN_NOTIF_GOTIFY_PRIORITY`
+    * `DIUN_NOTIF_GOTIFY_TIMEOUT`
+
+| Name               | Default       | Description   |
+|--------------------|---------------|---------------|
+| `endpoint`[^1]     |               | Gotify base URL |
+| `token`[^1]        |               | Application token |
+| `priority`         | `1`           | The priority of the message |
+| `timeout`          | `10s`         | Timeout specifies a time limit for the request to be made |
+
+## Sample
+
+![](../assets/notif/gotify.png)
+
+[^1]: Value required
diff --git a/docs/notif/mail.md b/docs/notif/mail.md
new file mode 100644
index 00000000..4cad6389
--- /dev/null
+++ b/docs/notif/mail.md
@@ -0,0 +1,48 @@
+# Mail notifications
+
+Notifications can be sent through SMTP.
+
+## Configuration
+
+!!! example "File"
+    ```yaml
+    notif:
+      mail:
+        host: localhost
+        port: 25
+        ssl: false
+        insecureSkipVerify: false
+        from: diun@example.com
+        to: webmaster@example.com
+    ```
+
+| Name                  | Default       | Description   |
+|-----------------------|---------------|---------------|
+| `host`[^1]            | `localhost`   | SMTP server host |
+| `port`[^1]            | `25`          | SMTP server port |
+| `ssl`                 | `false`       | SSL defines whether an SSL connection is used. Should be false in most cases since the auth mechanism should use STARTTLS |
+| `insecureSkipVerify`  | `false`       | Controls whether a client verifies the server's certificate chain and hostname |
+| `username`            |               | SMTP username |
+| `usernameFile`        |               | Use content of secret file as SMTP username if `username` not defined |
+| `password`            |               | SMTP password |
+| `passwordFile`        |               | Use content of secret file as SMTP password if `password` not defined |
+| `from`[^1]            |               | Sender email address |
+| `to`[^1]              |               | Recipient email address |
+
+!!! abstract "Environment variables"
+    * `DIUN_NOTIF_MAIL_HOST`
+    * `DIUN_NOTIF_MAIL_PORT`
+    * `DIUN_NOTIF_MAIL_SSL`
+    * `DIUN_NOTIF_MAIL_INSECURESKIPVERIFY`
+    * `DIUN_NOTIF_MAIL_USERNAME`
+    * `DIUN_NOTIF_MAIL_USERNAMEFILE`
+    * `DIUN_NOTIF_MAIL_PASSWORD`
+    * `DIUN_NOTIF_MAIL_PASSWORDFILE`
+    * `DIUN_NOTIF_MAIL_FROM`
+    * `DIUN_NOTIF_MAIL_TO`
+
+## Sample
+
+![](../assets/notif/mail.png)
+
+[^1]: Value required
diff --git a/docs/notif/rocketchat.md b/docs/notif/rocketchat.md
new file mode 100644
index 00000000..30d6ccc0
--- /dev/null
+++ b/docs/notif/rocketchat.md
@@ -0,0 +1,40 @@
+# Rocket.Chat notifications
+
+Allow to send notifications to your Rocket.Chat channel.
+
+## Configuration
+
+!!! example "File"
+    ```yaml
+    notif:
+      rocketchat:
+        endpoint: http://rocket.foo.com:3000
+        channel: "#general"
+        userID: abcdEFGH012345678
+        token: Token123456
+        timeout: 10s
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_NOTIF_ROCKETCHAT_ENDPOINT`
+    * `DIUN_NOTIF_ROCKETCHAT_CHANNEL`
+    * `DIUN_NOTIF_ROCKETCHAT_USERID`
+    * `DIUN_NOTIF_ROCKETCHAT_TOKEN`
+    * `DIUN_NOTIF_ROCKETCHAT_TIMEOUT`
+
+| Name               | Default       | Description   |
+|--------------------|---------------|---------------|
+| `endpoint`[^1]     |               | Rocket.Chat base URL |
+| `channel`[^1]      |               | Channel name with the prefix in front of it |
+| `userID`[^1]       |               | User ID |
+| `token`[^1]        |               | Authentication token |
+| `timeout`          | `10s`         | Timeout specifies a time limit for the request to be made |
+
+!!! warning
+    You must first create a _Personal Access Token_ through your account settings on your Rocket.Chat instance.
+
+## Sample
+
+![](../assets/notif/rocketchat.png)
+
+[^1]: Value required
diff --git a/docs/notif/script.md b/docs/notif/script.md
new file mode 100644
index 00000000..a1fd69dc
--- /dev/null
+++ b/docs/notif/script.md
@@ -0,0 +1,40 @@
+# Script notifications
+
+You can call a script when a notification occured. Following environment variables will be passed:
+
+```
+DIUN_VERSION=3.0.0
+DIUN_ENTRY_STATUS=new
+DIUN_ENTRY_PROVIDER=file
+DIUN_ENTRY_IMAGE=docker.io/crazymax/diun:latest
+DIUN_ENTRY_HUBLINK=https://hub.docker.com/r/crazymax/diun
+DIUN_ENTRY_MIMETYPE=application/vnd.docker.distribution.manifest.list.v2+json
+DIUN_ENTRY_DIGEST=sha256:216e3ae7de4ca8b553eb11ef7abda00651e79e537e85c46108284e5e91673e01
+DIUN_ENTRY_CREATED=2020-03-26 12:23:56 +0000 UTC
+DIUN_ENTRY_PLATFORM=linux/amd64
+```
+
+## Configuration
+
+!!! example "File"
+    ```yaml
+    notif:
+      script:
+        cmd: "myprogram"
+        args:
+          - "--anarg"
+          - "another"
+    ```
+
+| Name                  | Default       | Description   |
+|-----------------------|---------------|---------------|
+| `cmd`[^1]             |               | Command or script to execute |
+| `args`                |               | List of args to pass to `cmd` |
+| `dir`                 |               | Specifies the working directory of the command |
+
+!!! abstract "Environment variables"
+    * `DIUN_NOTIF_SCRIPT_CMD`
+    * `DIUN_NOTIF_SCRIPT_ARGS`
+    * `DIUN_NOTIF_SCRIPT_DIR`
+
+[^1]: Value required
diff --git a/docs/notif/slack.md b/docs/notif/slack.md
new file mode 100644
index 00000000..c2c85016
--- /dev/null
+++ b/docs/notif/slack.md
@@ -0,0 +1,28 @@
+# Slack notifications
+
+You can send notifications to your Slack channel using an [incoming webhook URL](https://api.slack.com/messaging/webhooks).
+
+!!! hint
+    Mattermost webhooks are compatible with Slack notification without any special configuration (if Webhooks are enabled).
+
+## Configuration
+
+!!! example "File"
+    ```yaml
+    notif:
+      slack:
+        webhookURL: https://hooks.slack.com/services/ABCD12EFG/HIJK34LMN/01234567890abcdefghij
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_NOTIF_SLACK_WEBHOOKURL`
+
+| Name               | Default       | Description   |
+|--------------------|---------------|---------------|
+| `webhookURL`[^1]   |               | Slack [incoming webhook URL](https://api.slack.com/messaging/webhooks) |
+
+## Sample
+
+![](../assets/notif/slack.png)
+
+[^1]: Value required
diff --git a/docs/notif/teams.md b/docs/notif/teams.md
new file mode 100644
index 00000000..c31bf5fc
--- /dev/null
+++ b/docs/notif/teams.md
@@ -0,0 +1,25 @@
+# Teams notifications
+
+You can send notifications to your Teams team-channel using an [incoming webhook URL](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/what-are-webhooks-and-connectors).
+
+## Configuration
+
+!!! example "File"
+    ```yaml
+    notif:
+      teams:
+        webhookURL: https://outlook.office.com/webhook/ABCD12EFG/HIJK34LMN/01234567890abcdefghij
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_NOTIF_TEAMS_WEBHOOKURL`
+
+| Name               | Default       | Description   |
+|--------------------|---------------|---------------|
+| `webhookURL`[^1]   |               | Teams [incoming webhook URL](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/what-are-webhooks-and-connectors) |
+
+## Sample
+
+![](../assets/notif/teams.png)
+
+[^1]: Value required
diff --git a/docs/notif/telegram.md b/docs/notif/telegram.md
new file mode 100644
index 00000000..041381c3
--- /dev/null
+++ b/docs/notif/telegram.md
@@ -0,0 +1,35 @@
+# Telegram notifications
+
+Notifications can be sent via Telegram using a [Telegram Bot](https://core.telegram.org/bots).
+
+Follow the [instructions](https://core.telegram.org/bots#6-botfather) to set up a bot and get it's token.
+
+Message the [GetID bot](https://t.me/getidsbot) to find your chat ID.
+Multiple chat IDs can be provided in order to deliver notifications to multiple recipients.
+
+## Configuration
+
+!!! example "File"
+    ```yaml
+    notif:
+      telegram:
+        token: aabbccdd:11223344
+        chatIDs:
+          - 123456789
+          - 987654321
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_NOTIF_TELEGRAM_TOKEN`
+    * `DIUN_NOTIF_TELEGRAM_CHATIDS` (comma separated)
+
+| Name               | Default       | Description   |
+|--------------------|---------------|---------------|
+| `token`[^1]        |               | Telegram bot token |
+| `chatIDs`[^1]      |               | List of chat IDs to send notifications to |
+
+## Sample
+
+![](../assets/notif/telegram.png)
+
+[^1]: Value required
diff --git a/docs/notif/webhook.md b/docs/notif/webhook.md
new file mode 100644
index 00000000..d7f4908a
--- /dev/null
+++ b/docs/notif/webhook.md
@@ -0,0 +1,48 @@
+# Webhook notifications
+
+You can send webhook notifications with the following settings.
+
+## Configuration
+
+!!! example "File"
+    ```yaml
+    notif:
+      gotify:
+        endpoint: http://gotify.foo.com
+        token: Token123456
+        priority: 1
+        timeout: 10s
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_NOTIF_WEBHOOK_ENDPOINT`
+    * `DIUN_NOTIF_WEBHOOK_METHOD`
+    * `DIUN_NOTIF_WEBHOOK_HEADERS_<KEY>`
+    * `DIUN_NOTIF_WEBHOOK_TIMEOUT`
+
+| Name               | Default       | Description   |
+|--------------------|---------------|---------------|
+| `endpoint`[^1]     |               | URL of the HTTP request |
+| `method`[^1]       | `GET`         | HTTP method |
+| `headers`          |               | Map of additional headers to be sent (key is case insensitive) |
+| `timeout`          | `10s`         | Timeout specifies a time limit for the request to be made |
+
+## Sample
+
+The JSON response will look like this:
+
+```json
+{
+  "diun_version": "4.0.0",
+  "status": "new",
+  "provider": "file",
+  "image": "docker.io/crazymax/diun:latest",
+  "hub_link": "https://hub.docker.com/r/crazymax/diun",
+  "mime_type": "application/vnd.docker.distribution.manifest.list.v2+json",
+  "digest": "sha256:216e3ae7de4ca8b553eb11ef7abda00651e79e537e85c46108284e5e91673e01",
+  "created": "2020-03-26T12:23:56Z",
+  "platform": "linux/amd64"
+}
+```
+
+[^1]: Value required
diff --git a/docs/overrides/home.html b/docs/overrides/home.html
new file mode 100644
index 00000000..43e2a90d
--- /dev/null
+++ b/docs/overrides/home.html
@@ -0,0 +1,167 @@
+{% extends "main.html" %}
+
+<!-- Render hero under tabs -->
+{% block tabs %}
+{{ super() }}
+
+<!-- Additional styles for landing page -->
+<style>
+
+  /* Application header should be static for the landing page */
+  .md-header {
+    position: initial;
+  }
+
+  /* Remove spacing, as we cannot hide it completely */
+  .md-main__inner {
+    margin: 0;
+  }
+
+  /* Hide main content for now */
+  .md-content {
+    display: none;
+  }
+
+  /* Gradient background + blob */
+  .tx-container {
+    padding-top: 1rem;
+    background:
+            url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1123 258'><path d='M1124,2c0,0 0,256 0,256l-1125,0l0,-48c0,0 16,5 55,5c116,0 197,-92 325,-92c121,0 114,46 254,46c140,0 214,-167 572,-166Z' style='fill: white' /></svg>") no-repeat bottom,
+            linear-gradient(
+                    to bottom,
+                    var(--md-primary-fg-color),
+                    hsla(280deg, 67%, 55%, 1) 99%,
+                    white 99%
+            );
+  }
+
+  /* Set inverted text color on hero */
+  .tx-hero {
+    margin: 0 .8rem;
+    color: var(--md-primary-bg-color);
+  }
+
+  /* Make main headline thicker */
+  .tx-hero h1 {
+    margin-bottom: 1rem;
+    color: currentColor;
+    font-weight: 700;
+  }
+
+  /* Ensure that blob doesn't overlap buttons */
+  .tx-hero__content {
+    padding-bottom: 6rem;
+  }
+
+  /* Adjust spacing of buttons and invert them */
+  .tx-hero .md-button {
+    margin-top: .5rem;
+    margin-right: .5rem;
+    color: var(--md-primary-bg-color);
+  }
+
+  /* Invert primary button */
+  .tx-hero .md-button--primary {
+    background-color: var(--md-primary-bg-color);
+    color: hsla(280deg, 37%, 48%, 1);
+    border-color: var(--md-primary-bg-color);
+  }
+
+  /* Invert hover and focus button states */
+  .tx-hero .md-button:hover,
+  .tx-hero .md-button:focus {
+    background-color: var(--md-accent-fg-color);
+    color: var(--md-default-bg-color);
+    border-color: var(--md-accent-fg-color);
+  }
+
+  /* [mobile portrait -]: Adjust headline */
+  @media screen and (max-width: 30em) {
+
+    /* Make main headline smaller */
+    .tx-hero h1 {
+      font-size: 1.4rem;
+    }
+  }
+
+  /* [tablet landscape +]: Display content and image next to each other */
+  @media screen and (min-width: 60em) {
+
+    /* Hide table of contents */
+    .md-sidebar--secondary {
+      display: none;
+    }
+
+    /* Use flex layout to align items */
+    .tx-hero {
+      display: flex;
+      align-items: stretch;
+    }
+
+    /* Increase bottom spacing and set dimensions */
+    .tx-hero__content {
+      max-width: 19rem;
+      margin-top: 3.5rem;
+      padding-bottom: 14vw;
+    }
+
+    /* Swap with teaser and set dimensions */
+    .tx-hero__image {
+      width: 38rem;
+      order: 1;
+      transform: translateX(4rem);
+    }
+  }
+
+  /* [screen +]: Adjust spacing */
+  @media screen and (min-width: 76.25em) {
+
+    /* Hide navigation */
+    .md-sidebar--primary {
+      display: none;
+    }
+
+    /* Ensure the image aligns with the repository information */
+    .tx-hero__image {
+      transform: translateX(8rem);
+    }
+  }
+
+  .tx-hero .capitalize {
+    font-weight: bold;
+    font-size: 1.4em;
+  }
+</style>
+
+<!-- Hero for landing page -->
+<section class="tx-container">
+  <div class="md-grid md-typeset">
+    <div class="tx-hero">
+
+      <!-- Hero image -->
+      <div class="tx-hero__image">
+        <img src="assets/logo.png" alt="" draggable="false">
+      </div>
+
+      <!-- Hero content -->
+      <div class="tx-hero__content">
+        <h1>Diun</h1>
+        <p><span class="capitalize">D</span> ocker <span class="capitalize">I</span> mage <span class="capitalize">U</span> pdate <span class="capitalize">N</span> otifier</p>
+        <p>{{ config.site_description }}.</p>
+        <a href="{{ page.next_page.url | url }}" title="{{ page.next_page.title | striptags }}" class="md-button md-button--primary">
+          Get started
+        </a>
+        <a href="{{ config.repo_url }}" title="{{ lang.t('source.link.title') }}" class="md-button">
+          Go to GitHub
+        </a>
+      </div>
+    </div>
+  </div>
+</section>
+{% endblock %}
+
+<!-- Content -->
+{% block content %}{% endblock %}
+
+<!-- Application footer -->
+{% block footer %}{% endblock %}
diff --git a/docs/overrides/main.html b/docs/overrides/main.html
new file mode 100644
index 00000000..ff457001
--- /dev/null
+++ b/docs/overrides/main.html
@@ -0,0 +1,82 @@
+{% extends "base.html" %}
+
+<!-- Custom front matter -->
+{% block extrahead %}
+
+<!-- Determine title -->
+{% set title = config.site_name %}
+{% if page and page.title and not page.is_homepage %}
+{% set title = config.site_name ~ " - " ~ page.title | striptags %}
+{% endif %}
+
+<!-- assets absolute URL -->
+{% set assets = config.site_url ~ 'assets' %}
+
+<!-- Some meta tags -->
+<link rel="apple-touch-icon-precomposed" sizes="57x57" href="{{ assets }}/meta/apple-touch-icon-57x57.png">
+<link rel="apple-touch-icon-precomposed" sizes="114x114" href="{{ assets }}/meta/apple-touch-icon-114x114.png">
+<link rel="apple-touch-icon-precomposed" sizes="72x72" href="{{ assets }}/meta/apple-touch-icon-72x72.png">
+<link rel="apple-touch-icon-precomposed" sizes="144x144" href="{{ assets }}/meta/apple-touch-icon-144x144.png">
+<link rel="apple-touch-icon-precomposed" sizes="60x60" href="{{ assets }}/meta/apple-touch-icon-60x60.png">
+<link rel="apple-touch-icon-precomposed" sizes="120x120" href="{{ assets }}/meta/apple-touch-icon-120x120.png">
+<link rel="apple-touch-icon-precomposed" sizes="76x76" href="{{ assets }}/meta/apple-touch-icon-76x76.png">
+<link rel="apple-touch-icon-precomposed" sizes="152x152" href="{{ assets }}/meta/apple-touch-icon-152x152.png">
+<link rel="icon" type="image/png" href="{{ assets }}/meta/favicon-196x196.png" sizes="196x196">
+<link rel="icon" type="image/png" href="{{ assets }}/meta/favicon-96x96.png" sizes="96x96">
+<link rel="icon" type="image/png" href="{{ assets }}/meta/favicon-32x32.png" sizes="32x32">
+<link rel="icon" type="image/png" href="{{ assets }}/meta/favicon-16x16.png" sizes="16x16">
+<link rel="icon" type="image/png" href="{{ assets }}/meta/favicon-128.png" sizes="128x128">
+<meta name="application-name" content="{{ config.site_name }}">
+<meta name="msapplication-TileColor" content="#FFFFFF">
+<meta name="msapplication-TileImage" content="{{ assets }}/meta/mstile-144x144.png">
+<meta name="msapplication-square70x70logo" content="{{ assets }}/meta/mstile-70x70.png">
+<meta name="msapplication-square150x150logo" content="{{ assets }}/meta/mstile-150x150.png">
+<meta name="msapplication-wide310x150logo" content="{{ assets }}/meta/mstile-310x150.png">
+<meta name="msapplication-square310x310logo" content="{{ assets }}/meta/mstile-310x310.png">
+<meta property="og:type" content="website">
+<meta property="og:title" content="{{ title }}">
+<meta property="og:description" content="{{ config.site_description }}">
+<meta property="og:url" content="{{ page.canonical_url }}">
+<meta property="og:image" content="{{ assets }}/meta/card.png">
+<meta property="og:image:type" content="image/png">
+<meta property="og:image:width" content="1200">
+<meta property="og:image:height" content="630">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:site" content="@crazyws">
+<meta name="twitter:creator" content="@crazyws">
+<meta name="twitter:title" content="{{ title }}">
+<meta name="twitter:description" content="{{ config.site_description }}">
+<meta name="twitter:image" content="{{ assets }}/card.png">
+{% endblock %}
+
+<!-- Announcement bar -->
+{% block announce %}
+<style>
+
+  /* Add background color transition */
+  .md-announce {
+    transition: background-color 125ms;
+  }
+
+  /* Change background color on link focus */
+  .md-announce:focus-within {
+    background-color: var(--md-accent-fg-color);
+  }
+
+  /* Preserve link color */
+  .md-announce a,
+  .md-announce a:focus,
+  .md-announce a:hover {
+    color: currentColor;
+  }
+
+  /* Don't wrap name of blog article */
+  .md-announce strong {
+    white-space: nowrap;
+  }
+</style>
+<a target="_blank" href="https://github.com/sponsors/crazy-max">
+  If you like this project and use it, consider sponsoring it via
+  <strong>GitHub <img alt="❤" class="twemoji md-footer-custom-text" src="https://twemoji.maxcdn.com/v/latest/svg/2764.svg" title="love"> Sponsors</strong>
+</a>
+{% endblock %}
diff --git a/doc/providers/docker.md b/docs/providers/docker.md
similarity index 67%
rename from doc/providers/docker.md
rename to docs/providers/docker.md
index 24d87d34..3ac94c21 100644
--- a/doc/providers/docker.md
+++ b/docs/providers/docker.md
@@ -1,12 +1,5 @@
 # Docker provider
 
-* [About](#about)
-* [Quick start](#quick-start)
-* [Provider configuration](#provider-configuration)
-  * [Configuration file](#configuration-file)
-  * [Environment variables](#environment-variables)
-* [Docker labels](#docker-labels)
-
 ## About
 
 The Docker provider allows you to analyze the containers of your Docker instance to extract images found and check for updates on the registry.
@@ -81,87 +74,104 @@ diun_1         | Sat, 14 Dec 2019 15:30:13 CET INF Cron initialized with schedul
 diun_1         | Sat, 14 Dec 2019 15:30:13 CET INF Next run in 29 minutes (2019-12-14 16:00:00 +0100 CET)
 ```
 
-## Provider configuration
+## Configuration
 
-### Configuration file
+!!! hint
+    Environment variable `DIUN_PROVIDERS_DOCKER=true` can be used to enable this provider with default values.
 
-#### `endpoint`
+### `endpoint`
 
 Server address to connect to. Local if empty.
 
-```yaml
-providers:
-  docker:
-    endpoint: "unix:///var/run/docker.sock"
-```
+!!! example "File"
+    ```yaml
+    providers:
+      docker:
+        endpoint: "unix:///var/run/docker.sock"
+    ```
 
-#### `apiVersion`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_DOCKER_ENDPOINT`
+
+### `apiVersion`
 
 Overrides the client version with the specified one.
 
-```yaml
-providers:
-  docker:
-    apiVersion: "1.39"
-```
+!!! example "File"
+    ```yaml
+    providers:
+      docker:
+        apiVersion: "1.39"
+    ```
 
-#### `tlsCertsPath`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_DOCKER_APIVERSION`
+
+### `tlsCertsPath`
 
 Path to load the TLS certificates from.
 
-```yaml
-providers:
-  docker:
-    tlsCertsPath: "/certs/"
-```
+!!! example "File"
+    ```yaml
+    providers:
+      docker:
+        tlsCertsPath: "/certs/"
+    ```
 
-#### `tlsVerify`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_DOCKER_TLSCERTSPATH`
+
+### `tlsVerify`
 
 Controls whether client verifies the server's certificate chain and hostname (default `true`).
 
-```yaml
-providers:
-  docker:
-    tlsVerify: true
-```
+!!! example "File"
+    ```yaml
+    providers:
+      docker:
+        tlsVerify: true
+    ```
 
-#### `watchByDefault`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_DOCKER_TLSVERIFY`
+
+### `watchByDefault`
 
 Enable watch by default. If false, containers that don't have `diun.enable=true` label will be ignored (default `false`).
 
-```yaml
-providers:
-  docker:
-    watchByDefault: false
-```
+!!! example "File"
+    ```yaml
+    providers:
+      docker:
+        watchByDefault: false
+    ```
 
-#### `watchStopped`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT`
+
+### `watchStopped`
 
 Include created and exited containers too (default `false`).
 
-```yaml
-providers:
-  docker:
-    watchStopped: false
-```
+!!! example "File"
+    ```yaml
+    providers:
+      docker:
+        watchStopped: false
+    ```
 
-### Environment variables
-
-* `DIUN_PROVIDERS_DOCKER`
-* `DIUN_PROVIDERS_DOCKER_ENDPOINT`
-* `DIUN_PROVIDERS_DOCKER_APIVERSION`
-* `DIUN_PROVIDERS_DOCKER_TLSCERTSPATH`
-* `DIUN_PROVIDERS_DOCKER_TLSVERIFY`
-* `DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT`
-* `DIUN_PROVIDERS_DOCKER_WATCHSTOPPED`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_DOCKER_WATCHSTOPPED`
 
 ## Docker labels
 
 You can configure more finely the way to analyze the image of your container through Docker labels:
 
-* `diun.enable`: Set to true to enable image analysis of this container.
-* `diun.regopts_id`: Registry options ID from [`regopts`](../configuration.md#regopts) to use.
-* `diun.watch_repo`: Watch all tags of this container image (default `false`).
-* `diun.max_tags`: Maximum number of tags to watch if `diun.watch_repo` enabled. 0 means all of them (default `0`).
-* `diun.include_tags`: Semi-colon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo`.
-* `diun.exclude_tags`: Semi-colon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo`.
+| Name                          | Default       | Description   |
+|-------------------------------|---------------|---------------|
+| `diun.enable`                 |               | Set to true to enable image analysis of this container |
+| `diun.regopts_id`             |               | Registry options ID from [`regopts`](../config/regopts.md) to use |
+| `diun.watch_repo`             | `false`       | Watch all tags of this container image |
+| `diun.max_tags`               | `0`           | Maximum number of tags to watch if `diun.watch_repo` enabled. `0` means all of them |
+| `diun.include_tags`           |               | Semi-colon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
+| `diun.exclude_tags`           |               | Semi-colon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
diff --git a/doc/providers/file.md b/docs/providers/file.md
similarity index 68%
rename from doc/providers/file.md
rename to docs/providers/file.md
index 49fb0261..dc578552 100644
--- a/doc/providers/file.md
+++ b/docs/providers/file.md
@@ -1,13 +1,5 @@
 # File provider
 
-* [About](#about)
-* [Example](#example)
-* [Quick start](#quick-start)
-* [Provider configuration](#provider-configuration)
-  * [Configuration file](#configuration-file)
-  * [Environment variables](#environment-variables)
-* [YAML configuration file](#yaml-configuration-file)
-
 ## About
 
 The file provider lets you define Docker images to analyze through a YAML file or a directory.
@@ -32,7 +24,7 @@ regopts:
   onemore:
     username: foo2
     password: bar2
-    insecureTls: true
+    insecureTLS: true
 
 providers:
   file:
@@ -129,50 +121,54 @@ Sat, 14 Dec 2019 15:32:28 UTC INF Cron initialized with schedule * * * * *
 Sat, 14 Dec 2019 15:32:28 UTC INF Next run in 31 seconds (2019-12-14 15:33:00 +0000 UTC)
 ```
 
-## Provider configuration
+## Configuration
 
-### Configuration file
-
-#### `filename`
+### `filename`
 
 Defines the path to the [configuration file](#yaml-configuration-file).
 
-> :warning: `filename` and `directory` are mutually exclusive.
+!!! warning
+    `filename` and `directory` are mutually exclusive
 
-```yaml
-providers:
-  file:
-    filename: /path/to/config/conf.yml
-```
+!!! example "File"
+    ```yaml
+    providers:
+      file:
+        filename: /path/to/config/conf.yml
+    ```
 
-#### `directory`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_FILE_FILENAME`
+
+### `directory`
 
 Defines the path to the directory that contains the [configuration files](#yaml-configuration-file) (`*.yml` or `*.yaml`).
 
-> :warning: `filename` and `directory` are mutually exclusive.
+!!! warning
+    `filename` and `directory` are mutually exclusive
 
-```yaml
-providers:
-  file:
-    directory: /path/to/config
-```
+!!! example "File"
+    ```yaml
+    providers:
+      file:
+        directory: /path/to/config
+    ```
 
-### Environment variables
-
-* `DIUN_PROVIDERS_FILE_DIRECTORY`
-* `DIUN_PROVIDERS_FILE_FILENAME`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_FILE_DIRECTORY`
 
 ## YAML configuration file
 
 The configuration file(s) defines a slice of images to analyze with the following fields:
 
-* `name`: Docker image name to watch using `registry/path:tag` format. If registry omitted, `docker.io` will be used and if tag omitted, `latest` will be used. **required**
-* `regopts_id`: Registry options ID from [`regopts`](../configuration.md#regopts) to use.
-* `watch_repo`: Watch all tags of this `image` repository (default `false`).
-* `max_tags`: Maximum number of tags to watch if `watch_repo` enabled. 0 means all of them (default `0`).
-* `include_tags`: List of regular expressions to include tags. Can be useful if you enable `watch_repo`.
-* `exclude_tags`: List of regular expressions to exclude tags. Can be useful if you enable `watch_repo`.
-* `platform`: Check a custom platform. (default will retrieve platform dynamically based on your operating system).
-  * `os`: Operating system to use.
-  * `arch`: CPU architecture to use.
-  * `variant`: Variant of the CPU to use.
+| Name                          | Default                          | Description   |
+|-------------------------------|----------------------------------|---------------|
+| `name`                        | `latest`                         | Docker image name to watch using `registry/path:tag` format. If registry omitted, `docker.io` will be used and if tag omitted, `latest` will be used |
+| `regopts_id`                  |                                  | Registry options ID from [`regopts`](../config/regopts.md) to use |
+| `watch_repo`                  | `false`                          | Watch all tags of this image |
+| `max_tags`                    | `0`                              | Maximum number of tags to watch if `watch_repo` enabled. `0` means all of them |
+| `include_tags`                |                                  | List of regular expressions to include tags. Can be useful if you enable `watch_repo` |
+| `exclude_tags`                |                                  | List of regular expressions to exclude tags. Can be useful if you enable `watch_repo` |
+| `platform.os`                 | dynamic based on your OS specs   | Operating system to use as custom platform |
+| `platform.arch`               | dynamic based on your OS specs   | CPU architecture to use as custom platform |
+| `platform.variant`            | dynamic based on your OS specs   | Variant of the CPU to use as custom platform |
diff --git a/doc/providers/kubernetes.md b/docs/providers/kubernetes.md
similarity index 70%
rename from doc/providers/kubernetes.md
rename to docs/providers/kubernetes.md
index 93270ea0..d4188c6b 100644
--- a/doc/providers/kubernetes.md
+++ b/docs/providers/kubernetes.md
@@ -1,12 +1,5 @@
 # Kubernetes provider
 
-* [About](#about)
-* [Quick start](#quick-start)
-* [Provider configuration](#provider-configuration)
-  * [Configuration file](#configuration-file)
-  * [Environment variables](#environment-variables)
-* [Kubernetes annotations](#kubernetes-annotations)
-
 ## About
 
 The Kubernetes provider allows you to analyze the pods of your Kubernetes cluster to extract images found and check for updates on the registry.
@@ -160,19 +153,24 @@ Wed, 17 Jun 2020 10:50:03 CEST INF New image found image=docker.io/library/nginx
 ...
 ```
 
-## Provider configuration
+## Configuration
 
-### Configuration file
+!!! hint
+    Environment variable `DIUN_PROVIDERS_KUBERNETES=true` can be used to enable this provider with default values.
 
-#### `endpoint`
+### `endpoint`
 
 The Kubernetes server endpoint as URL.
 
-```yaml
-providers:
-  kubernetes:
-    endpoint: "http://localhost:8080"
-```
+!!! example "File"
+    ```yaml
+    providers:
+      kubernetes:
+        endpoint: "http://localhost:8080"
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_KUBERNETES_ENDPOINT`
 
 Kubernetes server endpoint as URL, which is only used when the behavior based on environment variables described below does not apply.
 
@@ -182,86 +180,101 @@ The access token is looked up in `/var/run/secrets/kubernetes.io/serviceaccount/
 
 When the environment variables are not found, Diun tries to connect to the Kubernetes API server with an external-cluster client. In which case, the endpoint is required. Specifically, it may be set to the URL used by `kubectl proxy` to connect to a Kubernetes cluster using the granted authentication and authorization of the associated kubeconfig.
 
-#### `token`
-
-```yaml
-providers:
-  kubernetes:
-    token: "atoken"
-```
+### `token`
 
 Bearer token used for the Kubernetes client configuration.
 
-#### `tokenFile`
+!!! example "File"
+    ```yaml
+    providers:
+      kubernetes:
+        token: "atoken"
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_KUBERNETES_TOKEN`
+
+### `tokenFile`
 
 Use content of secret file as bearer token if `token` not defined.
 
-```yaml
-providers:
-  kubernetes:
-    tokenFile: "/run/secrets/token"
-```
+!!! example "File"
+    ```yaml
+    providers:
+      kubernetes:
+        tokenFile: "/run/secrets/token"
+    ```
 
-#### `certAuthFilePath`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_KUBERNETES_TOKEN`
+
+### `certAuthFilePath`
 
 Path to the certificate authority file. Used for the Kubernetes client configuration.
 
-```yaml
-providers:
-  kubernetes:
-    certAuthFilePath: "/a/ca.crt"
-```
+!!! example "File"
+    ```yaml
+    providers:
+      kubernetes:
+        certAuthFilePath: "/a/ca.crt"
+    ```
 
-#### `tlsInsecure`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_KUBERNETES_CERTAUTHFILEPATH`
+
+### `tlsInsecure`
 
 Controls whether client does not verify the server's certificate chain and hostname (default `false`).
 
-```yaml
-providers:
-  kubernetes:
-    tlsInsecure: false
-```
+!!! example "File"
+    ```yaml
+    providers:
+      kubernetes:
+        tlsInsecure: false
+    ```
 
-#### `namespaces`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_KUBERNETES_TLSINSECURE`
+
+### `namespaces`
 
 Array of namespaces to watch (default all namespaces).
 
-```yaml
-providers:
-  kubernetes:
-    namespaces:
-      - default
-      - production
-```
+!!! example "File"
+    ```yaml
+    providers:
+      kubernetes:
+        namespaces:
+          - default
+          - production
+    ```
 
-#### `watchByDefault`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_KUBERNETES_NAMESPACES` (comma separated)
+
+### `watchByDefault`
 
 Enable watch by default. If false, pods that don't have `diun.enable: "true"` annotation will be ignored (default `false`).
 
-```yaml
-providers:
-  kubernetes:
-    watchByDefault: false
-```
+!!! example "File"
+    ```yaml
+    providers:
+      kubernetes:
+        watchByDefault: false
+    ```
 
-### Environment variables
-
-* `DIUN_PROVIDERS_KUBERNETES`
-* `DIUN_PROVIDERS_KUBERNETES_ENDPOINT`
-* `DIUN_PROVIDERS_KUBERNETES_TOKEN`
-* `DIUN_PROVIDERS_KUBERNETES_TOKENFILE`
-* `DIUN_PROVIDERS_KUBERNETES_CERTAUTHFILEPATH`
-* `DIUN_PROVIDERS_KUBERNETES_TLSINSECURE`
-* `DIUN_PROVIDERS_KUBERNETES_NAMESPACES` (comma separated)
-* `DIUN_PROVIDERS_KUBERNETES_WATCHBYDEFAULT`
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_KUBERNETES_WATCHBYDEFAULT`
 
 ## Kubernetes annotations
 
 You can configure more finely the way to analyze the image of your pods through Kubernetes annotations:
 
-* `diun.enable`: Set to true to enable image analysis of this pod.
-* `diun.regopts_id`: Registry options ID from [`regopts`](../configuration.md#regopts) to use.
-* `diun.watch_repo`: Watch all tags of this pod image (default `false`).
-* `diun.max_tags`: Maximum number of tags to watch if `diun.watch_repo` enabled. 0 means all of them (default `0`).
-* `diun.include_tags`: Semi-colon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo`.
-* `diun.exclude_tags`: Semi-colon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo`.
+| Name                          | Default       | Description   |
+|-------------------------------|---------------|---------------|
+| `diun.enable`                 |               | Set to true to enable image analysis of this pod |
+| `diun.regopts_id`             |               | Registry options ID from [`regopts`](../config/regopts.md) to use |
+| `diun.watch_repo`             | `false`       | Watch all tags of this pod image |
+| `diun.max_tags`               | `0`           | Maximum number of tags to watch if `diun.watch_repo` enabled. `0` means all of them |
+| `diun.include_tags`           |               | Semi-colon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
+| `diun.exclude_tags`           |               | Semi-colon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
diff --git a/doc/providers/swarm.md b/docs/providers/swarm.md
similarity index 73%
rename from doc/providers/swarm.md
rename to docs/providers/swarm.md
index b784bf3e..1d4a2012 100644
--- a/doc/providers/swarm.md
+++ b/docs/providers/swarm.md
@@ -1,12 +1,5 @@
 # Swarm provider
 
-* [About](#about)
-* [Quick start](#quick-start)
-* [Provider configuration](#provider-configuration)
-  * [Configuration file](#configuration-file)
-  * [Environment variables](#environment-variables)
-* [Docker labels](#docker-labels)
-
 ## About
 
 The Swarm provider allows you to analyze the services of your Swarm cluster to extract images found and check for updates on the registry.
@@ -98,76 +91,91 @@ diun_diun.1.i1l4yuiafq6y@docker-desktop    | Sat, 14 Dec 2019 16:20:02 CET INF N
 ...
 ```
 
-## Provider configuration
+## Configuration
 
-### Configuration file
+!!! hint
+    Environment variable `DIUN_PROVIDERS_SWARM=true` can be used to enable this provider with default values.
 
-#### `endpoint`
+### `endpoint`
 
 Server address to connect to. Local if empty.
 
-```yaml
-providers:
-  swarm:
-    endpoint: "unix:///var/run/docker.sock"
-```
+!!! example "File"
+    ```yaml
+    providers:
+      swarm:
+        endpoint: "unix:///var/run/docker.sock"
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_SWARM_ENDPOINT`
 
 #### `apiVersion`
 
 Overrides the client version with the specified one.
 
-```yaml
-providers:
-  swarm:
-    apiVersion: "1.39"
-```
+!!! example "File"
+    ```yaml
+    providers:
+      swarm:
+        apiVersion: "1.39"
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_SWARM_APIVERSION`
 
 #### `tlsCertsPath`
 
 Path to load the TLS certificates from.
 
-```yaml
-providers:
-  swarm:
-    tlsCertsPath: "/certs/"
-```
+!!! example "File"
+    ```yaml
+    providers:
+      swarm:
+        tlsCertsPath: "/certs/"
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_SWARM_TLSCERTSPATH`
 
 #### `tlsVerify`
 
 Controls whether client verifies the server's certificate chain and hostname (default `true`).
 
-```yaml
-providers:
-  swarm:
-    tlsVerify: true
-```
+!!! example "File"
+    ```yaml
+    providers:
+      swarm:
+        tlsVerify: true
+    ```
+
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_SWARM_TLSVERIFY`
 
 #### `watchByDefault`
 
 Enable watch by default. If false, services that don't have `diun.enable=true` label will be ignored (default `false`).
 
-```yaml
-providers:
-  swarm:
-    watchByDefault: false
-```
+!!! example "File"
+    ```yaml
+    providers:
+      swarm:
+        watchByDefault: false
+    ```
 
-### Environment variables
+!!! abstract "Environment variables"
+    * `DIUN_PROVIDERS_SWARM_WATCHBYDEFAULT`
 
-* `DIUN_PROVIDERS_SWARM`
-* `DIUN_PROVIDERS_SWARM_ENDPOINT`
-* `DIUN_PROVIDERS_SWARM_APIVERSION`
-* `DIUN_PROVIDERS_SWARM_TLSCERTSPATH`
-* `DIUN_PROVIDERS_SWARM_TLSVERIFY`
-* `DIUN_PROVIDERS_SWARM_WATCHBYDEFAULT`
 
 ## Docker labels
 
 You can configure more finely the way to analyze the image of your service through Docker labels:
 
-* `diun.enable`: Set to true to enable image analysis of this container.
-* `diun.regopts_id`: Registry options ID from [`regopts`](../configuration.md#regopts) to use.
-* `diun.watch_repo`: Watch all tags of this container image (default `false`).
-* `diun.max_tags`: Maximum number of tags to watch if `diun.watch_repo` enabled. 0 means all of them (default `0`).
-* `diun.include_tags`: Semi-colon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo`.
-* `diun.exclude_tags`: Semi-colon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo`.
+| Name                          | Default       | Description   |
+|-------------------------------|---------------|---------------|
+| `diun.enable`                 |               | Set to true to enable image analysis of this service |
+| `diun.regopts_id`             |               | Registry options ID from [`regopts`](../config/regopts.md) to use |
+| `diun.watch_repo`             | `false`       | Watch all tags of this service image |
+| `diun.max_tags`               | `0`           | Maximum number of tags to watch if `diun.watch_repo` enabled. `0` means all of them |
+| `diun.include_tags`           |               | Semi-colon separated list of regular expressions to include tags. Can be useful if you enable `diun.watch_repo` |
+| `diun.exclude_tags`           |               | Semi-colon separated list of regular expressions to exclude tags. Can be useful if you enable `diun.watch_repo` |
diff --git a/docs/reporting-issue.md b/docs/reporting-issue.md
new file mode 100644
index 00000000..3764fdce
--- /dev/null
+++ b/docs/reporting-issue.md
@@ -0,0 +1,31 @@
+# Reporting an issue
+
+## Before submitting an issue
+
+First, [be a good guy](https://github.com/kossnocorp/etiquette/blob/master/README.md).
+
+Please do a search in [open issues]({{ config.repo_url }}issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed and read the [FAQ](faq.md) page first.
+
+If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment.
+
+:+1: - upvote
+
+:-1: - downvote
+
+If you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below.
+
+## Writing good bug reports and feature requests
+
+File a single issue per problem and feature request.
+
+* Do not enumerate multiple bugs or feature requests in the same issue.
+* Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes.
+
+The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix.
+
+You are now ready to [create a new issue]({{ config.repo_url }}issues/new/choose)!
+
+## Closure policy
+
+* Issues that don't have the information requested above (when applicable) will be closed immediately and the poster directed to the support guidelines.
+* Issues that go a week without a response from original poster are subject to closure at our discretion.
diff --git a/internal/model/regopts.go b/internal/model/regopts.go
index f83469b4..f66b28df 100644
--- a/internal/model/regopts.go
+++ b/internal/model/regopts.go
@@ -12,7 +12,7 @@ type RegOpts struct {
 	UsernameFile string         `yaml:"usernameFile,omitempty" json:"usernameFile,omitempty" validate:"omitempty,file"`
 	Password     string         `yaml:"password,omitempty" json:"password,omitempty" validate:"omitempty"`
 	PasswordFile string         `yaml:"passwordFile,omitempty" json:"passwordFile,omitempty" validate:"omitempty,file"`
-	InsecureTLS  *bool          `yaml:"insecureTls,omitempty" json:"insecureTls,omitempty" validate:"required"`
+	InsecureTLS  *bool          `yaml:"insecureTLS,omitempty" json:"insecureTLS,omitempty" validate:"required"`
 	Timeout      *time.Duration `yaml:"timeout,omitempty" json:"timeout,omitempty" validate:"required"`
 }
 
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 00000000..03afcd38
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,108 @@
+site_name: Diun
+site_description: Receive notifications when a Docker image is updated on a Docker registry
+site_author: CrazyMax
+site_url: https://diun.crazymax.dev
+edit_uri: edit/master/www/docs/
+docs_dir: docs
+
+repo_name: crazy-max/diun
+repo_url: https://github.com/crazy-max/diun
+copyright: |
+  Made with <img alt="❤" class="twemoji md-footer-custom-text" src="https://twemoji.maxcdn.com/v/latest/svg/2764.svg" title="love">
+  by <a target="_blank" href="https://crazymax.dev/">CrazyMax</a> and <a target="_blank" href="https://github.com/crazy-max/diun/graphs/contributors">contributors</a>.
+
+extra:
+  app:
+    version: 4.0.0
+  social:
+    - icon: fontawesome/brands/github-alt
+      link: https://github.com/crazy-max/diun
+
+theme:
+  name: material
+  custom_dir: docs/overrides
+  language: en
+  palette:
+    scheme: default
+    primary: light blue
+    accent: light blue
+  font:
+    text: Roboto
+    code: Roboto Mono
+  i18n:
+    prev: Previous
+    next: Next
+  logo: assets/logo.png
+  favicon: assets/favicon.ico
+  include_search_page: false
+  search_index_only: true
+
+plugins:
+  - macros
+  - search:
+      prebuild_index: python
+      lang:
+        - en
+  - git-revision-date-localized:
+      type: iso_datetime
+  - minify:
+      minify_html: true
+
+google_analytics:
+  - !!python/object/apply:os.getenv ["GOOGLE_ANALYTICS_KEY"]
+  - auto
+
+nav:
+  - Home: index.md
+  - Get started: get-started.md
+  - Installation:
+    - With Docker: install/docker.md
+    - From binary: install/binary.md
+    - Linux service: install/linux-service.md
+  - Configuration:
+    - Overview: config/index.md
+    - .db: config/db.md
+    - .watch: config/watch.md
+    - .notif: config/notif.md
+    - .regopts: config/regopts.md
+    - .providers: config/providers.md
+  - Notifications:
+    - Amqp: notif/amqp.md
+    - Gotify: notif/gotify.md
+    - Mail: notif/mail.md
+    - Rocket.Chat: notif/rocketchat.md
+    - Script: notif/script.md
+    - Slack: notif/slack.md
+    - Teams: notif/teams.md
+    - Telegram: notif/telegram.md
+    - Webhook: notif/webhook.md
+  - Providers:
+    - Docker: providers/docker.md
+    - File: providers/file.md
+    - Kubernetes: providers/kubernetes.md
+    - Swarm: providers/swarm.md
+  - FAQ: faq.md
+  - Migration:
+    - Diun v2 to v3: migration/v2-to-v3.md
+    - Diun v1 to v2: migration/v1-to-v2.md
+    - Diun v0 to v1: migration/v0-to-v1.md
+  - Reporting an issue: reporting-issue.md
+  - Contributing: contributing.md
+  - Donate: donate.md
+
+markdown_extensions:
+  - admonition
+  - codehilite
+  - footnotes
+  - meta
+  - pymdownx.details
+  - pymdownx.tabbed
+  - pymdownx.superfences
+  - pymdownx.emoji:
+      emoji_index: !!python/name:materialx.emoji.twemoji
+      emoji_generator: !!python/name:materialx.emoji.to_svg
+  - toc:
+      permalink: true
+
+extra_css:
+  - css/extra.css