diff --git a/common/icons/radicale.svg b/common/icons/radicale.svg
new file mode 100644
index 0000000..1ad5206
--- /dev/null
+++ b/common/icons/radicale.svg
@@ -0,0 +1,9 @@
+<svg height="300" xmlns="http://www.w3.org/2000/svg" width="300">
+  <path fill="#a40000" d="M 186,188 C 184,98 34,105 47,192 C 59,279 130,296 130,296 C 130,296 189,277 186,188 z"/>
+  <path fill="#ffffff" d="M 73,238 C 119,242 140,241 177,222 C 172,270 131,288 131,288 C 131,288 88,276 74,238 z"/>
+  <g fill="none" stroke="#4e9a06" stroke-width="15">
+    <path d="M 103,137 C 77,69 13,62 13,62"/>
+    <path d="M 105,136 C 105,86 37,20 37,20"/>
+    <path d="M 105,135 C 112,73 83,17 83,17"/>
+  </g>
+</svg>
diff --git a/docs/ports.md b/docs/ports.md
index ab22423..70ec739 100644
--- a/docs/ports.md
+++ b/docs/ports.md
@@ -18,3 +18,4 @@ The idea is to always use consecutive ports, but never go back and try to recycl
 | 8412 | [prometheus nginx exporter](../hosts/nixos/lapetus/services/prometheus.nix) |
 | 8413 | [commafeed](../hosts/nixos/lapetus/services/commafeed.nix)                  |
 | 8414 | [invidious](../hosts/nixos/lapetus/services/invidious.nix)                  |
+| 8415 | [radicale](../hosts/nixos/lapetus/services/radicale.nix)                    |
diff --git a/hosts/nixos/lapetus/default.nix b/hosts/nixos/lapetus/default.nix
index a44d6f6..416356c 100644
--- a/hosts/nixos/lapetus/default.nix
+++ b/hosts/nixos/lapetus/default.nix
@@ -18,6 +18,7 @@
     ./services/commafeed.nix
     ./services/invidious.nix
     ./services/diptime.nix
+    ./services/radicale.nix
     ./filesystems
     ./hardware
   ];
diff --git a/hosts/nixos/lapetus/services/homer.nix b/hosts/nixos/lapetus/services/homer.nix
index ad8294a..4c6121c 100644
--- a/hosts/nixos/lapetus/services/homer.nix
+++ b/hosts/nixos/lapetus/services/homer.nix
@@ -81,10 +81,10 @@ in
                 url = "https://search.moonythm.dev";
               }
               {
-                name = "Commafeed";
-                subtitle = "RSS reader";
-                logo = icon "commafeed.png";
-                url = "https://rss.moonythm.dev";
+                name = "Radicale";
+                subtitle = "Calendar server";
+                logo = icon "radicale.svg";
+                url = "https://cal.moonythm.dev";
               }
             ];
           }
@@ -132,6 +132,12 @@ in
                 icon = fa "globe";
                 url = "https://diptime.moonythm.dev";
               }
+              {
+                name = "Commafeed";
+                subtitle = "RSS reader";
+                logo = icon "commafeed.png";
+                url = "https://rss.moonythm.dev";
+              }
             ];
           }
           # }}}
diff --git a/hosts/nixos/lapetus/services/radicale.nix b/hosts/nixos/lapetus/services/radicale.nix
new file mode 100644
index 0000000..0fc6f41
--- /dev/null
+++ b/hosts/nixos/lapetus/services/radicale.nix
@@ -0,0 +1,20 @@
+{ config, ... }:
+let
+  port = 8415;
+  dataDir = "/persist/data/radicale";
+in
+{
+  service.radicale = {
+    enable = true;
+
+    settings = {
+      server.hosts = [ "localhost:${port}" ];
+      storage.filesystem_folder = dataDir;
+    };
+  };
+
+  systemd.tmpfiles.rules = [ "d ${dataDir} 0700 radicale radicale" ];
+
+  services.nginx.virtualHosts."cal.moonythm.dev" =
+    config.satellite.proxy port { };
+}