diff --git a/lib/CF.pm b/lib/CF.pm
index 8410084ef3d6cd2119071058fb6380eb6b71de6d..5293b285123ecc8817c454ed6bbf80354d770390 100644
--- a/lib/CF.pm
+++ b/lib/CF.pm
@@ -92,7 +92,7 @@ sub startup {
     $r->get('/')->to(cb => sub { shift->redirect_to('/api.html');});
 
     $r->websocket('/ws/posts')->to('Posts#ws');
-    $r->websocket('/ws/announcements')->to('Announcements#ws');
+    $r->websocket('/ws')->to('Websockets#main');
 }
 
 1;
diff --git a/lib/CF/Controller/Websockets.pm b/lib/CF/Controller/Websockets.pm
new file mode 100644
index 0000000000000000000000000000000000000000..04bad7e16e0937d2340ba8566bf61b9c621ce15e
--- /dev/null
+++ b/lib/CF/Controller/Websockets.pm
@@ -0,0 +1,25 @@
+package CF::Controller::Websockets;
+
+use Mojo::Base 'Mojolicious::Controller';
+use Mojo::Pg::PubSub;
+use feature 'signatures';
+no warnings qw{ experimental::signatures };
+
+sub main {
+    my $c = shift;
+
+    $c->inactivity_timeout(600);
+
+    my $pubsub = Mojo::Pg::PubSub->new(pg => $c->pg);
+
+    $pubsub->listen(notify => sub($pubsub, $payload) {
+        $c->send($payload);
+    });
+
+    $c->on(finish => sub ($c, $code, $reason = undef) {
+        $pubsub->unlisten('notify');
+        $c->app->log->debug("WebSocket closed with status $code");
+    });
+}
+
+1;