diff --git a/scripts/certificates b/scripts/certificates
deleted file mode 100755
index 467785dd2d182fe75282a4b684270cccdeca3201..0000000000000000000000000000000000000000
--- a/scripts/certificates
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-script_directory="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-
-# Derived from https://www.linode.com/docs/guides/create-a-self-signed-tls-certificate/
-openssl req -new -newkey rsa:1024 -x509 -sha256 -days 36525 -nodes \
-  -subj '/CN=garagesensor.local' \
-  -out "$script_directory/../src/certificates/certificate-chain.pem" \
-  -keyout "$script_directory/../src/certificates/key.pem"
diff --git a/src/certificates/certificate-chain.pem b/src/certificates/certificate-chain.pem
deleted file mode 100644
index c8f077cc379aa11afcd110f24eccf071be8e2094..0000000000000000000000000000000000000000
--- a/src/certificates/certificate-chain.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBszCCARwCCQCj+re8WZ4+aDANBgkqhkiG9w0BAQsFADAdMRswGQYDVQQDDBJn
-YXJhZ2VzZW5zb3IubG9jYWwwIBcNMjMwMzA1MTk0ODIxWhgPMjEyMzAzMDYxOTQ4
-MjFaMB0xGzAZBgNVBAMMEmdhcmFnZXNlbnNvci5sb2NhbDCBnzANBgkqhkiG9w0B
-AQEFAAOBjQAwgYkCgYEAxSb4Ao/A6wxE/a4w9YOkHY+mzmnO9naqE/DDasJYQO5+
-MgLnpDgOcStQojfTJHHu8V2o0TqSadYZuY75c6A1oji0kG5CcpYOyhtpKdKjvEQ1
-3WPt+vBOCU3mmL1W7pS1RiNy3f/g3xC7qPEvW6nZZonafCO5f9edupNsBfbgSDUC
-AwEAATANBgkqhkiG9w0BAQsFAAOBgQAP51g4jkm2YQ3ADmNesKewHK2vSw248PS3
-SNAaxaj0n+6PEUZO/COOD5Of6yHZVDa4DAxKdGUdL/YIBkf8mceLfzNFbW8Le+t5
-OQ/YNFMXLobDf7HRkVzIfVXAwtoJqUY/DSEI0cMfpHIcNC4ThYgdreiANn2f1WDK
-YDe8O9X5UA==
------END CERTIFICATE-----
diff --git a/src/certificates/key.pem b/src/certificates/key.pem
deleted file mode 100644
index e88c97207f424f460b36f3b99cfa0ff534feefd1..0000000000000000000000000000000000000000
--- a/src/certificates/key.pem
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMUm+AKPwOsMRP2u
-MPWDpB2Pps5pzvZ2qhPww2rCWEDufjIC56Q4DnErUKI30yRx7vFdqNE6kmnWGbmO
-+XOgNaI4tJBuQnKWDsobaSnSo7xENd1j7frwTglN5pi9Vu6UtUYjct3/4N8Qu6jx
-L1up2WaJ2nwjuX/XnbqTbAX24Eg1AgMBAAECgYAiN0cnuqcyo+h9VnPsyDH9Z2b9
-v+NJZwLRfyGLL7t9WWbRayuklo37Ghdeb+3XD2b2wNiBp3ato5jHWYb1iEKGXPGg
-biF4gYAasjB3HiauOeG3UNLOM27+yI04K6XQZSV3s6CrM+C1ILWGHU0S7LQxjeBA
-hsMdH18jVjUP1RS6QQJBAOI8pJ4x5fCp7KbnBY6lwBMn5Q2KxAqQHqCL6brrgeqh
-Bzp1fR/OnzsXcn6Cb5BMs4cMWxeV3DyfBTFCwO51wu0CQQDfFssAl84TcRrNyriq
-fuZBth5z9auGmS38FdbrDqXPzgDa2MM4e4/LUYBvF7FQtneiekHXKis5fJlxoytT
-fQlpAkAwSKcNiDK9+VYjjNy3xBJJRFNzX3FVm8qdkx7QIOE6VSG4zUhmGHANaYSr
-EWWEE4qhQPbUAszdN0cha1DH0+RFAkAKz6f212R9PLX30yMv4AZ4mMLRC87MLxAz
-bzuDGKqgb3NLJ8YOLq7BQ6nduGA3cSBLF3GpY7nEh21IPIgU+7JBAkBjyMupNQHW
-HHll7Fa4YtBfEXK2sIB/wvdtroT05s2YM1F2XUwLfLyepSSniyLMVnd+gOZwr4c/
-KRbIBmqaBrh9
------END PRIVATE KEY-----
diff --git a/src/public_html/script.js b/src/public_html/script.js
deleted file mode 100644
index c9528ffec56e9541058fad1714d860dc1e253880..0000000000000000000000000000000000000000
--- a/src/public_html/script.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Keep the service worker up to date
-navigator.serviceWorker.register('/service-worker.js', { type: 'module' }).then((registration) => {
-  registration.update();
-});
-
-// Subscribe to notifications when the user wishes to do so
-const subscribeButton = document.getElementById('subscribe-button');
-subscribeButton.addEventListener('click', async () => {
-  const serviceWorkerRegistration = await navigator.serviceWorker.ready;
-  const pushSubscription = await serviceWorkerRegistration.pushManager.subscribe({
-    userVisibleOnly: true,
-    applicationServerKey:
-      'BP1ZvYiUs2YDFtbJu2weWZdBS4DFA0kKw3pFK6iMVV7zue-fmg_gJM8lEshHkbJO5KkiO8wYh15Xn8y0BZNpRCs',
-  });
-  console.log(pushSubscription.toJSON());
-});
diff --git a/src/public_html/icon-192.avif b/website/icon-192.avif
similarity index 100%
rename from src/public_html/icon-192.avif
rename to website/icon-192.avif
diff --git a/src/public_html/icon-512.avif b/website/icon-512.avif
similarity index 100%
rename from src/public_html/icon-512.avif
rename to website/icon-512.avif
diff --git a/src/public_html/index.html b/website/index.html
similarity index 100%
rename from src/public_html/index.html
rename to website/index.html
diff --git a/src/public_html/manifest.webmanifest b/website/manifest.webmanifest
similarity index 100%
rename from src/public_html/manifest.webmanifest
rename to website/manifest.webmanifest
diff --git a/website/script.js b/website/script.js
new file mode 100644
index 0000000000000000000000000000000000000000..128a4195f7732007bd2639488e8a0de9ec8ae405
--- /dev/null
+++ b/website/script.js
@@ -0,0 +1,42 @@
+const vapidPublicKey =
+  'BP1ZvYiUs2YDFtbJu2weWZdBS4DFA0kKw3pFK6iMVV7zue-fmg_gJM8lEshHkbJO5KkiO8wYh15Xn8y0BZNpRCs';
+
+// Keep the service worker up to date
+navigator.serviceWorker.register('/service-worker.js', { type: 'module' }).then((registration) => {
+  registration.update();
+});
+
+// Subscribe to notifications when the user wishes to do so
+const subscribeButton = document.getElementById('subscribe-button');
+subscribeButton.addEventListener('click', async () => {
+  const subscriptionURL = getSensorSubscriptionURL();
+  if (!subscriptionURL) {
+    return;  
+  }
+
+  const serviceWorkerRegistration = await navigator.serviceWorker.ready;
+  const pushSubscription = await serviceWorkerRegistration.pushManager.subscribe({
+    userVisibleOnly: true,
+    applicationServerKey: vapidPublicKey,
+  });
+
+  await fetch(subscriptionURL, {
+    method: 'post',
+    headers: { 'content-type': 'application/json' },
+    body: JSON.stringify(pushSubscription.toJSON()),
+  });
+});
+
+
+function getSensorSubscriptionURL() {
+  const queryParameters = new URLSearchParams(location.search);
+  const subscriptionURLString = queryParameters.get('sensor_subscription_url');
+  if (subscriptionURLString) {
+    try {
+      return new URL(subscriptionURLString);
+    } catch (error) {
+      console.error(`Malformed sensor subscription URL: ${subscriptionURLString}`);
+    }
+  }
+  return null;
+}
diff --git a/src/public_html/service-worker.js b/website/service-worker.js
similarity index 76%
rename from src/public_html/service-worker.js
rename to website/service-worker.js
index b1e2819cad3bd5f593af46ea2f27fc577aa2645d..f13431f7f69d5b452311b7426b3db9e2c0f74bf6 100644
--- a/src/public_html/service-worker.js
+++ b/website/service-worker.js
@@ -8,7 +8,6 @@ self.addEventListener('install', (event) => {
 
 self.addEventListener('push', (event) => {
   const message = event.data.json();
-  console.log(message);
   event.waitUntil(
     self.registration.showNotification(message.title, {
       body: message.body,
@@ -19,4 +18,6 @@ self.addEventListener('push', (event) => {
   );
 });
 
-self.addEventListener('pushsubscriptionchange', (event) => {});
+// TODO: handle changes to the push subscription, such as when the user disables push notifications
+// through the system settings or when the browser cycles the push subscription
+// self.addEventListener('pushsubscriptionchange', (event) => {});
diff --git a/src/public_html/style.css b/website/style.css
similarity index 100%
rename from src/public_html/style.css
rename to website/style.css