diff --git a/.yamllint.yaml b/.yamllint.yaml
new file mode 100644
index 0000000..d932357
--- /dev/null
+++ b/.yamllint.yaml
@@ -0,0 +1,17 @@
+---
+
+extends: relaxed
+
+rules:
+  # 80 chars should be enough, but don't fail if a line is longer
+  line-length:
+    max: 200
+    level: warning
+  empty-lines:
+    max: 2
+    max-start: 1
+    max-end: 1
+  colons:
+    max-spaces-after: -1
+  commas:
+    max-spaces-after: -1
diff --git a/roles/common/tasks/main.yaml b/roles/common/tasks/main.yaml
index 865de63..29f7744 100644
--- a/roles/common/tasks/main.yaml
+++ b/roles/common/tasks/main.yaml
@@ -15,6 +15,8 @@
     group: "{{ item.group | default('root') }}"
   with_items:
     - { src: "apt.conf.j2", dest: "/etc/apt/apt.conf" }
+    - { src: "apt-defaultrelease.j2", dest: "/etc/apt/apt.conf.d/09defaultrelease" }
+    - { src: "apt-preferences-stable.j2", dest: "/etc/apt/preferences.d/stableonly" }
     - { src: "sources.list.j2", dest: "/etc/apt/sources.list" }
     - { src: "apt-auto-upgrades.j2", dest: "/etc/apt/apt.conf.d/20auto-upgrades" }
     - { src: "apt-unattended-upgrades.j2", dest: "/etc/apt/apt.conf.d/50unattended-upgrades" }
diff --git a/roles/common/templates/apt-defaultrelease.j2 b/roles/common/templates/apt-defaultrelease.j2
new file mode 100644
index 0000000..1bab7c5
--- /dev/null
+++ b/roles/common/templates/apt-defaultrelease.j2
@@ -0,0 +1 @@
+APT::Default-Release "{{ ansible_distribution_release }}";
diff --git a/roles/common/templates/apt-preferences-stable.j2 b/roles/common/templates/apt-preferences-stable.j2
new file mode 100644
index 0000000..8fc3cd0
--- /dev/null
+++ b/roles/common/templates/apt-preferences-stable.j2
@@ -0,0 +1,19 @@
+# Prefer packages from our release
+# Prevent auto-installation from testing/unstable/sid/whatever
+
+Package: *
+Pin: release n={{ ansible_distribution_release }}
+Pin-Priority: 900
+
+Package: *
+Pin: release n=sid
+Pin-Priority: -10
+
+Package: *
+Pin: release n=testing
+Pin-Priority: -10
+
+Package: *
+Pin: release n=unstable
+Pin-Priority: -10
+
diff --git a/roles/common/templates/sources.list.j2 b/roles/common/templates/sources.list.j2
index 3945e1d..2722b8f 100644
--- a/roles/common/templates/sources.list.j2
+++ b/roles/common/templates/sources.list.j2
@@ -20,5 +20,8 @@ deb {{ debian_repourl }} {{ ansible_distribution_release }}-backports {{ compone
 #
 # Security patches
 deb {{ debian_securityurl }} {{ ansible_distribution_release }}-security {{ components }}
-{{ SRC }}deb-src {{ debian_securityurl }} {{ ansible_distribution_release }}-security main contrib non-  free
+{{ SRC }}deb-src {{ debian_securityurl }} {{ ansible_distribution_release }}-security {{ components }}
 
+# Testing/Unstable repos
+deb {{ debian_repourl }} testing {{ components }}
+deb {{ debian_repourl }} sid {{ components }}
diff --git a/roles/nginx/templates/site.conf.j2 b/roles/nginx/templates/site.conf.j2
index d48f46f..786f7da 100644
--- a/roles/nginx/templates/site.conf.j2
+++ b/roles/nginx/templates/site.conf.j2
@@ -10,6 +10,7 @@ server {
     ssl_certificate        /var/lib/dehydrated/certs/{{ site.server_name }}/fullchain.pem;
     ssl_certificate_key    /var/lib/dehydrated/certs/{{ site.server_name }}/privkey.pem;
 
+    index {{ nginx_index | default('index.php index.html index.htm') }};
     client_max_body_size {{ nginx_client_max_body_size }};
 
     location ~ /\.ht {
diff --git a/roles/photos/tasks/photos2mqtt.yaml b/roles/photos/tasks/photos2mqtt.yaml
index 755a4ec..d9f2e05 100644
--- a/roles/photos/tasks/photos2mqtt.yaml
+++ b/roles/photos/tasks/photos2mqtt.yaml
@@ -6,8 +6,9 @@
       - liblinux-inotify2-perl
 
 - name: Install mqtt-simple
-  ansible.builtin.command:
-    cmd: cpan Net::MQTT::Simple
+  ansible.builtin.apt:
+    pkg: libnet-mqtt-simple-perl
+    default_release: testing
 
 - name: Install photos2mqtt
   ansible.builtin.template:
diff --git a/roles/services/tasks/power_mqtt.yaml b/roles/services/tasks/power_mqtt.yaml
index 406a274..1042844 100644
--- a/roles/services/tasks/power_mqtt.yaml
+++ b/roles/services/tasks/power_mqtt.yaml
@@ -27,7 +27,7 @@
   vars:
     description: "SMD630 to MQTT Probe"
     exec: "/var/lib/power-mqtt.py %i"
-  notify: Restart power-mqtt@
+  notify: Restart power-mqtt
 
 - name: Enable power-mqtt
   ansible.builtin.systemd:
@@ -40,3 +40,4 @@
       ip: 0.0.0.0
     - net: unicorndept
       ip: 0.0.0.0
+  ignore_errors: true  # FIXME
diff --git a/roles/services/tasks/spacestated.yaml b/roles/services/tasks/spacestated.yaml
index 3cff5bb..92a0ace 100644
--- a/roles/services/tasks/spacestated.yaml
+++ b/roles/services/tasks/spacestated.yaml
@@ -8,8 +8,9 @@
       - make
 
 - name: Install mqtt-simple
-  ansible.builtin.command:
-    cmd: cpan Net::MQTT::Simple
+  ansible.builtin.apt:
+    pkg: libnet-mqtt-simple-perl
+    default_release: testing
 
 - name: Add user
   ansible.builtin.user:
diff --git a/roles/www/tasks/mqtt.yaml b/roles/www/tasks/mqtt.yaml
index f96fadd..63d1dee 100644
--- a/roles/www/tasks/mqtt.yaml
+++ b/roles/www/tasks/mqtt.yaml
@@ -8,8 +8,9 @@
       - mosquitto
 
 - name: Install mqtt-simple
-  community.general.cpanm:
-    name: Net::MQTT::Simple
+  ansible.builtin.apt:
+    pkg: libnet-mqtt-simple-perl
+    default_release: testing
 
 - name: Clone mqtt2web source
   ansible.builtin.git: