diff --git a/README.md b/README.md
index c2ac174cf9..9fd3619be2 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,7 @@ If you have a spare domain name you can configure applications to be accessible
* [Jackett](https://github.com/Jackett/Jackett) - API Support for your favorite torrent trackers
* [Jellyfin](https://jellyfin.github.io) - The Free Software Media System
* [Joomla](https://www.joomla.org/) - Open source content management system
+* [Kavita](https://www.kavitareader.com/) - Digital library which supports a vast array of file formats
* [Komga](https://komga.org/) - a media server for your comics, mangas, BDs and magazines
* [Krusader](https://krusader.org/) - Twin panel file management for your desktop
* [Lidarr](https://github.com/lidarr/Lidarr) - Music collection manager for Usenet and BitTorrent users
diff --git a/nas.yml b/nas.yml
index d5680f2a05..0922570907 100644
--- a/nas.yml
+++ b/nas.yml
@@ -194,6 +194,10 @@
tags:
- joomla
+ - role: kavita
+ tags:
+ - kavita
+
- role: komga
tags:
- komga
diff --git a/roles/kavita/defaults/main.yml b/roles/kavita/defaults/main.yml
new file mode 100644
index 0000000000..ebf8336aad
--- /dev/null
+++ b/roles/kavita/defaults/main.yml
@@ -0,0 +1,25 @@
+---
+kavita_enabled: false
+kavita_available_externally: false
+
+# uid / gid
+kavita_user_id: "1000"
+kavita_group_id: "1000"
+
+# directories
+kavita_data_directory: "{{ docker_home }}/kavita"
+kavita_books_directory: "{{ books_root }}"
+kavita_comics_directory: "{{ comics_root }}"
+
+# image
+kavita_image: "linuxserver/kavita"
+
+# network
+kavita_port: "5002"
+kavita_hostname: "kavita"
+
+# specs
+kavita_memory: 1g
+
+# docker
+kavita_container_name: kavita
diff --git a/roles/kavita/molecule/default/molecule.yml b/roles/kavita/molecule/default/molecule.yml
new file mode 100644
index 0000000000..0fe89fb0dd
--- /dev/null
+++ b/roles/kavita/molecule/default/molecule.yml
@@ -0,0 +1,6 @@
+---
+provisioner:
+ inventory:
+ group_vars:
+ all:
+ kavita_enabled: true
diff --git a/roles/kavita/molecule/default/side_effect.yml b/roles/kavita/molecule/default/side_effect.yml
new file mode 100644
index 0000000000..4729485d36
--- /dev/null
+++ b/roles/kavita/molecule/default/side_effect.yml
@@ -0,0 +1,10 @@
+---
+- name: Stop
+ hosts: all
+ become: true
+ tasks:
+ - name: "Include {{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }} role"
+ include_role:
+ name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}"
+ vars:
+ kavita_enabled: false
diff --git a/roles/kavita/molecule/default/verify.yml b/roles/kavita/molecule/default/verify.yml
new file mode 100644
index 0000000000..af6c754ec4
--- /dev/null
+++ b/roles/kavita/molecule/default/verify.yml
@@ -0,0 +1,18 @@
+---
+- name: Verify
+ hosts: all
+ gather_facts: false
+ tasks:
+ - include_vars:
+ file: ../../defaults/main.yml
+
+ - name: Get container state
+ docker_container_info:
+ name: "{{ kavita_container_name }}"
+ register: result
+
+ - name: Check Kavita is running
+ assert:
+ that:
+ - result.container['State']['Status'] == "running"
+ - result.container['State']['Restarting'] == false
diff --git a/roles/kavita/molecule/default/verify_stopped.yml b/roles/kavita/molecule/default/verify_stopped.yml
new file mode 100644
index 0000000000..e4280dc0cb
--- /dev/null
+++ b/roles/kavita/molecule/default/verify_stopped.yml
@@ -0,0 +1,18 @@
+---
+- name: Verify
+ hosts: all
+ gather_facts: false
+ tasks:
+ - include_vars:
+ file: ../../defaults/main.yml
+
+ - name: Try and stop and remove Kavita
+ docker_container:
+ name: "{{ kavita_container_name }}"
+ state: absent
+ register: result
+
+ - name: Check Kavita is stopped
+ assert:
+ that:
+ - not result.changed
diff --git a/roles/kavita/tasks/main.yml b/roles/kavita/tasks/main.yml
new file mode 100644
index 0000000000..34b2638478
--- /dev/null
+++ b/roles/kavita/tasks/main.yml
@@ -0,0 +1,43 @@
+---
+- name: Start Kavita
+ block:
+ - name: Create Kavita Directories
+ file:
+ path: "{{ item }}"
+ state: directory
+ with_items:
+ - "{{ kavita_data_directory }}/config"
+
+ - name: Kavita Docker Container
+ docker_container:
+ name: "{{ kavita_container_name }}"
+ image: "{{ kavita_image }}"
+ pull: true
+ volumes:
+ - "{{ kavita_data_directory }}/config:/config"
+ - "{{ kavita_comics_directory }}:/comics"
+ - "{{ kavita_books_directory }}:/books"
+ env:
+ TZ: "{{ ansible_nas_timezone }}"
+ PUID: "{{ kavita_user_id }}"
+ PGID: "{{ kavita_group_id }}"
+ ports:
+ - "{{ kavita_port }}:5000"
+ restart_policy: unless-stopped
+ memory: "{{ kavita_memory }}"
+ labels:
+ traefik.enable: "{{ kavita_available_externally | string }}"
+ traefik.http.routers.kavita.rule: "Host(`kavita.{{ ansible_nas_domain }}`)"
+ traefik.http.routers.kavita.tls.certresolver: "letsencrypt"
+ traefik.http.routers.kavita.tls.domains[0].main: "{{ ansible_nas_domain }}"
+ traefik.http.routers.kavita.tls.domains[0].sans: "*.{{ ansible_nas_domain }}"
+ traefik.http.services.kavita.loadbalancer.server.port: "5000"
+ when: kavita_enabled is true
+
+- name: Stop Kavita
+ block:
+ - name: Stop Kavita
+ docker_container:
+ name: "{{ kavita_container_name }}"
+ state: absent
+ when: kavita_enabled is false
diff --git a/website/docs/applications/media-serving/kavita.md b/website/docs/applications/media-serving/kavita.md
new file mode 100644
index 0000000000..e15c837637
--- /dev/null
+++ b/website/docs/applications/media-serving/kavita.md
@@ -0,0 +1,17 @@
+---
+title: "Kavita"
+---
+
+Homepage:
+
+Github:
+
+Docker Image:
+
+Lighting fast with a slick design, Kavita is a rocket fueled self-hosted digital library which supports a vast array of file formats. Install to start reading and share your server with your friends.
+
+## Usage
+
+Set `kavita_enabled: true` in your `inventories//nas.yml` file.
+
+Access the webui at by default.