diff --git a/kodi.yaml b/kodi.yaml
index a6a59776620c501ab2a5a4dd7281fe3461253de9..c8c05116195b9190c685e26583d0a3cdade1de84 100644
--- a/kodi.yaml
+++ b/kodi.yaml
@@ -2,7 +2,6 @@
 - hosts:
     - kodi
   roles:
-    - debian_server
     - kodi
   become: true
   become_user: root
diff --git a/roles/debian_server/handlers/main.yml b/roles/debian_server/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..84d97303727eeeb487fbf534357965b3df5a618b
--- /dev/null
+++ b/roles/debian_server/handlers/main.yml
@@ -0,0 +1,8 @@
+---
+- name: Rebuild initramfs
+  command:
+    cmd: update-initramfs -u
+
+- name: Update GRUB
+  command:
+    cmd: update-grub
diff --git a/roles/debian_server/tasks/main.yml b/roles/debian_server/tasks/main.yml
index 4328752667c6c0f64d213a626a476608fb6e3653..af3cb9fa07b7615d5f8da350ad57fd67b36fe4e9 100644
--- a/roles/debian_server/tasks/main.yml
+++ b/roles/debian_server/tasks/main.yml
@@ -5,6 +5,15 @@
       - ansible_distribution == "Debian"
       - ansible_distribution_major_version|int >= 10
 
+- name: Disable cgroup2 for Docker
+  lineinfile:
+    backup: true
+    line: |-
+      GRUB_CMDLINE_LINUX_DEFAULT="quiet systemd.unified_cgroup_hierarchy=0"
+    path: /etc/default/grub
+  notify:
+    - Update GRUB
+
 - name: Enable the backports repo
   loop:
     - deb
diff --git a/roles/kodi/files/kodi@.service b/roles/kodi/files/kodi.service
similarity index 62%
rename from roles/kodi/files/kodi@.service
rename to roles/kodi/files/kodi.service
index 751fea9c6c882df6e96d5712d943de0adce37627..7ca8002e8306037c4ba4d453edeaff7f24a61a71 100644
--- a/roles/kodi/files/kodi@.service
+++ b/roles/kodi/files/kodi.service
@@ -1,6 +1,6 @@
 [Unit]
 Description=Kodi Media Center on %i
-After=systemd-user-sessions.service sound.target network-online.target
+After=systemd-user-sessions.service sound.target network-online.target xorg.service
 
 # Require the library to be mounted.
 After=srv-library.mount
@@ -12,27 +12,17 @@ After=dbus.socket
 Conflicts=getty@%i.service
 Before=graphical.target
 
-# On systems without virtual consoles, don't start
-ConditionPathExists=/dev/tty0
-
 [Service]
 User=kodi
 PAMName=login
-ExecStart=flatpak run --device=all --filesystem=/srv/library tv.kodi.Kodi --standalone --windowing=gbm -fs
+Environment="DISPLAY=:0"
+ExecStart=flatpak run --device=all --filesystem=/etc/group --filesystem=/srv/library tv.kodi.Kodi --standalone --windowing=x11 -fs
 Type=simple
-Restart=on-abort
+Restart=always
 RestartSec=5
 KillMode=control-group
 
-# A virtual terminal is needed.
-TTYPath=/dev/%i
-TTYReset=yes
-TTYVHangup=yes
-TTYVTDisallocate=yes
-
 # Fail to start if not controlling the tty.
-StandardOutput=tty
-StandardInput=tty
 StandardError=journal
 
 # Log this user with utmp, letting it show up with commands 'w' and 'who'.
@@ -41,4 +31,4 @@ UtmpMode=user
 
 [Install]
 WantedBy=graphical.target
-DefaultInstance=tty7
+DefaultInstance=tty1
diff --git a/roles/kodi/files/xorg.service b/roles/kodi/files/xorg.service
new file mode 100644
index 0000000000000000000000000000000000000000..cc0ae5344f6698d0c9a475e02d09d097bf5a1587
--- /dev/null
+++ b/roles/kodi/files/xorg.service
@@ -0,0 +1,41 @@
+[Unit]
+Description=X Windows display server
+After=systemd-user-sessions.service
+
+# D-Bus is necessary for contacting logind. Logind is required.
+Wants=dbus.socket
+After=dbus.socket
+
+Conflicts=getty@tty7.service
+Before=graphical.target
+
+# On systems without virtual consoles, don't start
+ConditionPathExists=/dev/tty7
+
+[Service]
+User=kodi
+SupplementaryGroups=tty
+PAMName=login
+ExecStart=startx
+Type=simple
+Restart=on-abort
+RestartSec=5
+KillMode=control-group
+
+# A virtual terminal is needed.
+TTYPath=/dev/tty7
+TTYReset=yes
+TTYVHangup=yes
+TTYVTDisallocate=yes
+
+# Fail to start if not controlling the tty.
+StandardOutput=tty
+StandardInput=tty
+StandardError=journal
+
+# Log this user with utmp, letting it show up with commands 'w' and 'who'.
+UtmpIdentifier=tty7
+UtmpMode=user
+
+[Install]
+WantedBy=graphical.target
diff --git a/roles/kodi/handlers/main.yml b/roles/kodi/handlers/main.yml
index d041eb181139cf8ef7beb27079a194eb738bb1cc..63b8267a1ab927da7487e6320238c931160d1285 100644
--- a/roles/kodi/handlers/main.yml
+++ b/roles/kodi/handlers/main.yml
@@ -1,4 +1,10 @@
 ---
-- name: Rebuild initramfs
-  command:
-    cmd: update-initramfs -u
+- name: Restart Xorg
+  service:
+    name: xorg.service
+    state: restarted
+
+- name: Restart Kodi
+  service:
+    name: kodi.service
+    state: restarted
diff --git a/roles/kodi/meta/main.yml b/roles/kodi/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..312c74ab33a9c7f7deda2f4f4ec07e3871d6f647
--- /dev/null
+++ b/roles/kodi/meta/main.yml
@@ -0,0 +1,13 @@
+---
+galaxy_info:
+  author: Nimrod Adar
+  company: Shore
+  description: Standalone Kodi
+  license: MIT
+  min_ansible_version: 2.10
+  platforms:
+    - name: Debian
+      versions:
+        - Buster
+dependencies:
+  - role: debian_server
diff --git a/roles/kodi/tasks/main.yml b/roles/kodi/tasks/main.yml
index 2c050d5ffd394febbf50db2b0d0d8382ba3bd4e5..1c858da1c178c59278df460e88d2e9fbb227be03 100644
--- a/roles/kodi/tasks/main.yml
+++ b/roles/kodi/tasks/main.yml
@@ -1,16 +1,22 @@
 ---
 - name: APT install
   apt:
+    cache_valid_time: 3600
+    install_recommends: false
     name:
       - alsa-utils
       - avahi-daemon
       - desktop-base
       - flatpak
-      # - plymouth-themes
+      - plymouth-label
+      - plymouth-themes
       - firmware-linux
       - udisks2
       - unison
       - upower
+      - xorg
+    state: present
+    update_cache: true
 
 - name: Configure boot splash
   copy:
@@ -23,6 +29,31 @@
   notify:
     - Rebuild initramfs
 
+- name: Enable boot splash
+  lineinfile:
+    backup: true
+    # yamllint disable-line rule:line-length
+    line: GRUB_CMDLINE_LINUX_DEFAULT="quiet splash systemd.unified_cgroup_hierarchy=0"
+    path: /etc/default/grub
+  notify:
+    - Update GRUB
+
+- name: Create library mountpoint
+  file:
+    mode: 0o0755
+    path: /srv/library
+    state: directory
+
+- name: Mount library
+  ansible.posix.mount:
+    backup: true
+    fstype: auto
+    opts: defaults
+    path: /srv/library
+    src: UUID=cbc01549-0acf-472f-8964-2701e7fb4927
+    state: mounted
+  notify: Restart Kodi
+
 - name: Add Flatpak remotes
   with_dict:
     flathub: https://flathub.org/repo/flathub.flatpakrepo
@@ -43,6 +74,12 @@
 - name: Create user
   user:
     create_home: true
+    groups:
+      - audio
+      - cdrom
+      - input
+      - plugdev
+      - video
     home: /var/lib/kodi
     name: kodi
     password: '!'  # pragma: allowlist secret
@@ -50,16 +87,36 @@
     state: present
     system: true
     uid: 900
+  notify:
+    - Restart Xorg
+    - Restart Kodi
 
-- name: Copy service
+- name: Configure rootless Xorg
+  copy:
+    backup: true
+    content: |
+      allowed_users=anybody
+    dest: /etc/X11/Xwrapper.config
+    mode: 0o0644
+  notify:
+    - Restart Xorg
+
+- name: Copy services
+  with_items: &services
+    - xorg.service
+    - kodi.service
   copy:
     dest: /etc/systemd/system/
     mode: preserve
-    src: kodi@.service
+    src: '{{ item }}'
+  notify:
+    - Restart Xorg
+    - Restart Kodi
 
-- name: Enable service
+- name: Enable services
+  with_items: *services
   service:
     daemon-reload: true
     enabled: true
-    name: kodi@tty7.service
+    name: '{{ item }}'
     state: started