diff --git a/files/nftables.conf b/files/nftables.conf
new file mode 100644
index 0000000000000000000000000000000000000000..44f3cf9cf8a291d8e36843796e5ff5bb6e58fdc2
--- /dev/null
+++ b/files/nftables.conf
@@ -0,0 +1,27 @@
+table inet firewall {
+	chain input {
+		type filter hook input priority 0; policy drop;
+
+		ct state established,related accept
+		iifname lo accept
+		ip protocol icmp accept
+		ip6 nexthdr icmpv6 accept
+
+		# Allow all access from Lysator's nets.
+		ip6 saddr 2001:6b0:17:f0a0::/64 accept
+		ip saddr 130.236.254.0/24 accept
+
+		# Allow NTP connection from everyone.
+		udp dport 123 accept
+	}
+
+	chain output {
+		type filter hook output priority 0; policy accept;
+	}
+
+
+	chain forward {
+		type filter hook forward priority 0; policy drop;
+	}
+
+}
diff --git a/manifests/firewall.pp b/manifests/firewall.pp
new file mode 100644
index 0000000000000000000000000000000000000000..88bebc22eb0ab363ce59a4209bbfe5ccef9cee3b
--- /dev/null
+++ b/manifests/firewall.pp
@@ -0,0 +1,20 @@
+# Install an nftable firewall.
+class timehost::firewall {
+  package { 'nftables':
+    ensure => present,
+  }
+
+  service { 'nftables':
+    ensure => running,
+    enable => true,
+  }
+
+  file { '/etc/nftables.conf':
+    ensure => present,
+    source => 'puppet:///modules/timehost/nftables.conf',
+    owner  => 'root',
+    group  => 'root',
+    mode   => '0644',
+    notify => Service['nftables'],
+  }
+}