diff --git a/.editorconfig b/.editorconfig
index 72c884f6834ed9d62dca398f9102448fd0841087..ac0853078d268ca1754c049f78c60e3cabefb118 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -21,6 +21,8 @@ indent_size = unset
 indent_style = space
 indent_size = 2
 
+[*.html]
+
 [*.js]
 
 [*{.json,.ecrc}]
diff --git a/package/gluon-config-mode-theme/files/lib/gluon/config-mode/view/theme/layout.html b/package/gluon-config-mode-theme/files/lib/gluon/config-mode/view/theme/layout.html
index 865ec2aa8504af7c5f3b3d5c917ea3959214bcf6..9633531a0185a3b81eff601aaf4e384eadb278c2 100644
--- a/package/gluon-config-mode-theme/files/lib/gluon/config-mode/view/theme/layout.html
+++ b/package/gluon-config-mode-theme/files/lib/gluon/config-mode/view/theme/layout.html
@@ -1,12 +1,7 @@
 <%#
-Copyright 2008 Steven Barth <steven@midlink.org>
-Copyright 2008-2010 Jo-Philipp Wich <xm@subsignal.org>
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-	http://www.apache.org/licenses/LICENSE-2.0
+SPDX-License-Identifier: Apache-2.0
+SPDX-FileCopyrightText: 2008 Steven Barth <steven@midlink.org>
+SPDX-FileCopyrightText: 2008-2010 Jo-Philipp Wich <xm@subsignal.org>
 -%>
 <%
 	local pretty_hostname = require "pretty_hostname"
@@ -43,7 +38,7 @@ You may obtain a copy of the License at
 		table.sort(ret,
 			function(a, b)
 				return (node.nodes[a].order or 100)
-				     < (node.nodes[b].order or 100)
+					< (node.nodes[b].order or 100)
 			end
 		)
 		return ret
@@ -125,7 +120,7 @@ You may obtain a copy of the License at
 	</div>
 
 	<div id="maincontainer">
-	  <%
+		<%
 			if not hidenav then
 				menutree(unpack(request))
 			end
diff --git a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html
index b45012efc4ba8b8869ed3692fdb18da6aff0cb9f..d61ed462af1d24ba5bd64f3d615c60374e21fc49 100644
--- a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html
+++ b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html
@@ -1,18 +1,13 @@
 <%#
-Copyright 2008 Steven Barth <steven@midlink.org>
-Copyright 2008-2009 Jo-Philipp Wich <xm@subsignal.org>
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-	http://www.apache.org/licenses/LICENSE-2.0
+SPDX-FileCopyrightText: 2008 Steven Barth <steven@midlink.org>
+SPDX-FileCopyrightText: 2008-2009 Jo-Philipp Wich <xm@subsignal.org>
+SPDX-License-Identifier: Apache-2.0
 -%>
 
 <h2><%:Upgrade firmware%></h2>
 
 <p>
-  <%:The firmware image has been transmitted. Please ensure the SHA-256 checksum and image size are correct and click "continue".%>
+	<%:The firmware image has been transmitted. Please ensure the SHA-256 checksum and image size are correct and click "continue".%>
 </p>
 
 <% if flashsize > 0 and filesize > flashsize then %>
@@ -20,40 +15,40 @@ You may obtain a copy of the License at
 <% end %>
 
 <p>
-  <ul>
-    <li>sha256sum: <code><%=checksum%></code></li>
-    <li><%:Size%>: <%
-      function byte_format(byte)
-        local suff = {"B", "KB", "MB", "GB", "TB"}
-        for i=1, 5 do
-          if byte > 1024 and i < 5 then
-            byte = byte / 1024
-          else
-            return string.format("%.2f %s", byte, suff[i])
-          end
-        end
-      end
-
-      write(byte_format(filesize))
-
-      if flashsize > 0 then
-        write(translatef(
-          " (%s available)",
-          byte_format(flashsize)
-        ))
-      end
-    %></li>
-  </ul>
+	<ul>
+		<li>sha256sum: <code><%=checksum%></code></li>
+		<li><%:Size%>: <%
+			function byte_format(byte)
+				local suff = {"B", "KB", "MB", "GB", "TB"}
+				for i=1, 5 do
+					if byte > 1024 and i < 5 then
+						byte = byte / 1024
+					else
+						return string.format("%.2f %s", byte, suff[i])
+					end
+				end
+			end
+
+			write(byte_format(filesize))
+
+			if flashsize > 0 then
+				write(translatef(
+					" (%s available)",
+					byte_format(flashsize)
+				))
+			end
+		%></li>
+	</ul>
 </p>
 <div class="gluon-page-actions">
-  <form method="post" enctype="multipart/form-data" action="<%|url(request)%>" style="display:inline">
-    <input type="hidden" name="step" value="3">
-    <input type="hidden" name="keepcfg" value="<%=keepconfig and "1" or "0"%>">
-    <input class="gluon-button gluon-button-submit" type="submit" value="<%:Continue%>">
-  </form>
-  <form method="post" enctype="multipart/form-data" action="<%|url(request)%>" style="display:inline">
-    <input type="hidden" name="step" value="1">
-    <input type="hidden" name="keepcfg" value="<%=keepconfig and "1" or "0"%>">
-    <input class="gluon-button gluon-button-reset" type="submit" value="<%:Cancel%>">
-  </form>
+	<form method="post" enctype="multipart/form-data" action="<%|url(request)%>" style="display:inline">
+		<input type="hidden" name="step" value="3">
+		<input type="hidden" name="keepcfg" value="<%=keepconfig and "1" or "0"%>">
+		<input class="gluon-button gluon-button-submit" type="submit" value="<%:Continue%>">
+	</form>
+	<form method="post" enctype="multipart/form-data" action="<%|url(request)%>" style="display:inline">
+		<input type="hidden" name="step" value="1">
+		<input type="hidden" name="keepcfg" value="<%=keepconfig and "1" or "0"%>">
+		<input class="gluon-button gluon-button-reset" type="submit" value="<%:Cancel%>">
+	</form>
 </div>
diff --git a/package/gluon-web-mesh-vpn-fastd/files/lib/gluon/config-mode/view/mesh-vpn-fastd.html b/package/gluon-web-mesh-vpn-fastd/files/lib/gluon/config-mode/view/mesh-vpn-fastd.html
index e0ef55dd4909c8062672df30edc341b2ae1b19b3..3e815de4053a8ec14493825498ccbc7b90965089 100644
--- a/package/gluon-web-mesh-vpn-fastd/files/lib/gluon/config-mode/view/mesh-vpn-fastd.html
+++ b/package/gluon-web-mesh-vpn-fastd/files/lib/gluon/config-mode/view/mesh-vpn-fastd.html
@@ -1,34 +1,34 @@
 <div class="gluon-value">
-  <div class="gluon-value-title">
-    <input data-update="change" type="radio" value="security"<%= attr("id", id..'.1') .. attr("name", id) .. attr("checked", ((self:cfgvalue() or self.default) == "security") and "checked") %>>
-    <label<%= attr("for", id..'.1')%>></label>
-  </div>
-  <div class="gluon-value-field-long">
-    <label<%= attr("for", id..'.1') %> class="gluon-value-title"><%:Security mode%></label>
-    <br>
-    <%| translate(
-        'In security mode, the mesh VPN uses an encrypted tunnel to connect to the VPN servers. ' ..
-        'The encryption ensures that it is impossible for your internet access provider to see what ' ..
-        'data is exchanged over your node.'
-    ) %>
-    <br>
-  </div>
-  <div class="gluon-value-field-long-after"></div>
+	<div class="gluon-value-title">
+		<input data-update="change" type="radio" value="security"<%= attr("id", id..'.1') .. attr("name", id) .. attr("checked", ((self:cfgvalue() or self.default) == "security") and "checked") %>>
+		<label<%= attr("for", id..'.1')%>></label>
+	</div>
+	<div class="gluon-value-field-long">
+		<label<%= attr("for", id..'.1') %> class="gluon-value-title"><%:Security mode%></label>
+		<br>
+		<%| translate(
+			'In security mode, the mesh VPN uses an encrypted tunnel to connect to the VPN servers. ' ..
+			'The encryption ensures that it is impossible for your internet access provider to see what ' ..
+			'data is exchanged over your node.'
+		) %>
+		<br>
+	</div>
+	<div class="gluon-value-field-long-after"></div>
 </div>
 
 <div class="gluon-value gluon-value-last">
-  <div class="gluon-value-title">
-    <input data-update="change" type="radio" value="performance"<%= attr("id", id..'.2') .. attr("name", id) .. attr("checked", ((self:cfgvalue() or self.default) == "performance") and "checked") %>>
-    <label<%= attr("for", id..'.2')%>></label>
-  </div>
-  <div class="gluon-value-field-long">
-    <label<%= attr("for", id..'.2') %> class="gluon-value-title"><%:Performance mode%></label>
-    <br>
-    <%| translate(
-        'In performance mode, no encryption is used. This usually allows for higher throughput, but the data exchanged over your node is not ' ..
-        'protected against eavesdropping.'
-    ) %>
-    <br>
-  </div>
-  <div class="gluon-value-field-long-after"></div>
+	<div class="gluon-value-title">
+		<input data-update="change" type="radio" value="performance"<%= attr("id", id..'.2') .. attr("name", id) .. attr("checked", ((self:cfgvalue() or self.default) == "performance") and "checked") %>>
+		<label<%= attr("for", id..'.2')%>></label>
+	</div>
+	<div class="gluon-value-field-long">
+		<label<%= attr("for", id..'.2') %> class="gluon-value-title"><%:Performance mode%></label>
+		<br>
+		<%| translate(
+			'In performance mode, no encryption is used. This usually allows for higher throughput, but the data exchanged over your node is not ' ..
+			'protected against eavesdropping.'
+		) %>
+		<br>
+	</div>
+	<div class="gluon-value-field-long-after"></div>
 </div>
diff --git a/package/gluon-web-model/files/lib/gluon/web/view/model/warning.html b/package/gluon-web-model/files/lib/gluon/web/view/model/warning.html
index 41688b77fab7d3d2d3710e2d89f12ac4840e1617..af063ec50d3d79628ad8ca4696c5a6fe20c3e7ae 100644
--- a/package/gluon-web-model/files/lib/gluon/web/view/model/warning.html
+++ b/package/gluon-web-model/files/lib/gluon/web/view/model/warning.html
@@ -1,14 +1,14 @@
 <%- if self.title or self.content then -%>
 <div class="gluon-warning"<%=
-  attr("id", id) ..
-  attr("data-index", self.index) ..
-  attr("data-depends", self:deplist(self.deps))
+	attr("id", id) ..
+	attr("data-index", self.index) ..
+	attr("data-depends", self:deplist(self.deps))
 %>>
-  <%- if self.content then -%>
-  <%=self.content%>
-  <%- else -%>
-  <b><%=self.title%></b><br>
-  <%=self.description%>
-  <%- end -%>
+	<%- if self.content then -%>
+	<%=self.content%>
+	<%- else -%>
+	<b><%=self.title%></b><br>
+	<%=self.description%>
+	<%- end -%>
 </div>
 <%- end -%>
diff --git a/package/gluon-web/files/lib/gluon/web/view/error/404.html b/package/gluon-web/files/lib/gluon/web/view/error/404.html
index b2db7d0f15d6d883e97910126b3f65328254f9d6..f865ecc071634aa4e9201c65d1004d06b33fd6ba 100644
--- a/package/gluon-web/files/lib/gluon/web/view/error/404.html
+++ b/package/gluon-web/files/lib/gluon/web/view/error/404.html
@@ -1,7 +1,7 @@
 <%#
- Copyright 2008 Steven Barth <steven@midlink.org>
- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
- Licensed to the public under the Apache License 2.0.
+SPDX-FileCopyrightText: 2008 Steven Barth <steven@midlink.org>
+SPDX-FileCopyrightText: 2008 Jo-Philipp Wich <jow@openwrt.org>
+SPDX-License-Identifier: Apache-2.0
 -%>
 
 <h2 name="content">404 <%:Not Found%></h2>
diff --git a/package/gluon-web/files/lib/gluon/web/view/error/500.html b/package/gluon-web/files/lib/gluon/web/view/error/500.html
index 8f1532bebdd8671aede2e9e9c93218fee0315fdd..b09219bfe89106c45b400ba1abb564e04ce1a902 100644
--- a/package/gluon-web/files/lib/gluon/web/view/error/500.html
+++ b/package/gluon-web/files/lib/gluon/web/view/error/500.html
@@ -1,7 +1,7 @@
 <%#
- Copyright 2008 Steven Barth <steven@midlink.org>
- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
- Licensed to the public under the Apache License 2.0.
+SPDX-FileCopyrightText: 2008 Steven Barth <steven@midlink.org>
+SPDX-FileCopyrightText: 2008 Jo-Philipp Wich <jow@openwrt.org>
+SPDX-License-Identifier: Apache-2.0
 -%>
 
 <h2 name="content">500 <%:Internal Server Error%></h2>