diff --git a/README.md b/README.md
index 6c779b71b30f608ea0de02e1eacd84705615641f..33ca634c76d155ea6801892f9d2801402bb3e21a 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,10 @@ attributes:
     client IP address
   * `max_inflight_requests`: maximum number of in-flight requests to
     allow before server-side throttling kicks in
+ * `site_name`: sting to be used as site `<title>`.
+ * `site_logo`: path to an image to be used as logo, placed above the
+    modal form.
+ * `site_favicon`: path to a favicon.
 
 ## Device tracking
 
diff --git a/server/bindata.go b/server/bindata.go
index 3b1a761c5f504fc2b7707e6907ef36b6781f1c29..77cfe4ed5e4ccbc204b006bc65030cf2da8784fa 100644
--- a/server/bindata.go
+++ b/server/bindata.go
@@ -74,7 +74,7 @@ func staticCssBootstrapMinCss() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "static/css/bootstrap.min.css", size: 140936, mode: os.FileMode(420), modTime: time.Unix(1550305824, 0)}
+	info := bindataFileInfo{name: "static/css/bootstrap.min.css", size: 140936, mode: os.FileMode(420), modTime: time.Unix(1561034381, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -147,7 +147,7 @@ func staticCssSigninCss() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "static/css/signin.css", size: 1009, mode: os.FileMode(420), modTime: time.Unix(1535013418, 0)}
+	info := bindataFileInfo{name: "static/css/signin.css", size: 1009, mode: os.FileMode(420), modTime: time.Unix(1561034381, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -170,7 +170,7 @@ func staticJsBootstrap413MinJs() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "static/js/bootstrap-4.1.3.min.js", size: 51039, mode: os.FileMode(420), modTime: time.Unix(1550305766, 0)}
+	info := bindataFileInfo{name: "static/js/bootstrap-4.1.3.min.js", size: 51039, mode: os.FileMode(420), modTime: time.Unix(1561034381, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -189,7 +189,7 @@ func staticJsJquery331MinJs() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "static/js/jquery-3.3.1.min.js", size: 86927, mode: os.FileMode(420), modTime: time.Unix(1516469204, 0)}
+	info := bindataFileInfo{name: "static/js/jquery-3.3.1.min.js", size: 86927, mode: os.FileMode(420), modTime: time.Unix(1561034381, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -243,7 +243,7 @@ func staticJsLogoutJs() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "static/js/logout.js", size: 1005, mode: os.FileMode(420), modTime: time.Unix(1535013418, 0)}
+	info := bindataFileInfo{name: "static/js/logout.js", size: 1005, mode: os.FileMode(420), modTime: time.Unix(1561034381, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -265,7 +265,7 @@ func staticJsPopper1143MinJs() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "static/js/popper-1.14.3.min.js", size: 20337, mode: os.FileMode(420), modTime: time.Unix(1526549114, 0)}
+	info := bindataFileInfo{name: "static/js/popper-1.14.3.min.js", size: 20337, mode: os.FileMode(420), modTime: time.Unix(1561034381, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -1030,7 +1030,7 @@ func staticJsU2fApiJs() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "static/js/u2f-api.js", size: 20880, mode: os.FileMode(420), modTime: time.Unix(1535013418, 0)}
+	info := bindataFileInfo{name: "static/js/u2f-api.js", size: 20880, mode: os.FileMode(420), modTime: time.Unix(1561034381, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -1099,7 +1099,7 @@ func staticJsU2fJs() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "static/js/u2f.js", size: 1274, mode: os.FileMode(420), modTime: time.Unix(1541228751, 0)}
+	info := bindataFileInfo{name: "static/js/u2f.js", size: 1274, mode: os.FileMode(420), modTime: time.Unix(1561034381, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -1109,7 +1109,16 @@ var _templatesLogin_otpHtml = []byte(`{{template "header" .}}
     <form class="form-signin" action="{{.URLPrefix}}/login" method="post">
       {{.CSRFField}}
 
-      <h1 class="form-signin-heading">Sign In / OTP</h1>
+      <div class="row">
+          {{if .SiteLogo}}
+          <div class="col-md1">
+            <img src="./img/site_logo">
+          </div>
+          {{end}}
+          <div class="col-md3">
+            <h1 class="form-signin-heading">Sign In / OTP</h1>
+          </div>
+      </div>
 
       {{if .Error}}
       <p class="error">
@@ -1145,7 +1154,7 @@ func templatesLogin_otpHtml() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "templates/login_otp.html", size: 711, mode: os.FileMode(420), modTime: time.Unix(1556965814, 0)}
+	info := bindataFileInfo{name: "templates/login_otp.html", size: 937, mode: os.FileMode(420), modTime: time.Unix(1561391872, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -1155,7 +1164,16 @@ var _templatesLogin_passwordHtml = []byte(`{{template "header" .}}
     <form class="form-signin" action="{{.URLPrefix}}/login" method="post">
       {{.CSRFField}}
 
-      <h1 class="form-signin-heading">Sign In</h1>
+      <div class="row">
+          {{if .SiteLogo}}
+          <div class="col-md1">
+            <img src="./img/site_logo">
+          </div>
+          {{end}}
+          <div class="col-md3">
+            <h1 class="form-signin-heading">Sign In</h1>
+          </div>
+      </div>
 
       {{if .Error}}
       <p class="error">
@@ -1207,7 +1225,7 @@ func templatesLogin_passwordHtml() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "templates/login_password.html", size: 1187, mode: os.FileMode(420), modTime: time.Unix(1550307045, 0)}
+	info := bindataFileInfo{name: "templates/login_password.html", size: 1413, mode: os.FileMode(420), modTime: time.Unix(1561391985, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -1218,7 +1236,16 @@ var _templatesLogin_u2fHtml = []byte(`{{template "header" .}}
       {{.CSRFField}}
       <input type="hidden" id="u2fResponseField" name="u2f_response" value="">
 
-      <h1 class="form-signin-heading">Sign In / U2F</h1>
+      <div class="row">
+          {{if .SiteLogo}}
+          <div class="col-md1">
+            <img src="./img/site_logo">
+          </div>
+          {{end}}
+          <div class="col-md3">
+            <h1 class="form-signin-heading">Sign In / U2F</h1>
+          </div>
+      </div>
 
       {{if .Error}}
       <p class="error">
@@ -1255,7 +1282,7 @@ func templatesLogin_u2fHtml() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "templates/login_u2f.html", size: 669, mode: os.FileMode(420), modTime: time.Unix(1556965831, 0)}
+	info := bindataFileInfo{name: "templates/login_u2f.html", size: 895, mode: os.FileMode(420), modTime: time.Unix(1561391993, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -1315,7 +1342,7 @@ func templatesLogoutHtml() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "templates/logout.html", size: 1063, mode: os.FileMode(420), modTime: time.Unix(1548600535, 0)}
+	info := bindataFileInfo{name: "templates/logout.html", size: 1063, mode: os.FileMode(420), modTime: time.Unix(1561034381, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -1364,7 +1391,7 @@ func templatesPageHtml() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "templates/page.html", size: 1865, mode: os.FileMode(420), modTime: time.Unix(1551041668, 0)}
+	info := bindataFileInfo{name: "templates/page.html", size: 1865, mode: os.FileMode(420), modTime: time.Unix(1561034381, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
diff --git a/server/templates/login_otp.html b/server/templates/login_otp.html
index 6918a13f3af467384f579c8b48a9b25688a5ae8c..a21084cc5a962565a570af312add31ff1df4fc44 100644
--- a/server/templates/login_otp.html
+++ b/server/templates/login_otp.html
@@ -3,7 +3,16 @@
     <form class="form-signin" action="{{.URLPrefix}}/login" method="post">
       {{.CSRFField}}
 
-      <h1 class="form-signin-heading">Sign In / OTP</h1>
+      <div class="row">
+          {{if .SiteLogo}}
+          <div class="col-md1">
+            <img src="./img/site_logo">
+          </div>
+          {{end}}
+          <div class="col-md3">
+            <h1 class="form-signin-heading">Sign In / OTP</h1>
+          </div>
+      </div>
 
       {{if .Error}}
       <p class="error">
diff --git a/server/templates/login_password.html b/server/templates/login_password.html
index f09b92d8ecac816a33079422533c28817b94621f..b2e8fdaf0f5d690ff5c9862190e2f353d3c41eb2 100644
--- a/server/templates/login_password.html
+++ b/server/templates/login_password.html
@@ -3,7 +3,16 @@
     <form class="form-signin" action="{{.URLPrefix}}/login" method="post">
       {{.CSRFField}}
 
-      <h1 class="form-signin-heading">Sign In</h1>
+      <div class="row">
+          {{if .SiteLogo}}
+          <div class="col-md1">
+            <img src="./img/site_logo">
+          </div>
+          {{end}}
+          <div class="col-md3">
+            <h1 class="form-signin-heading">Sign In</h1>
+          </div>
+      </div>
 
       {{if .Error}}
       <p class="error">
diff --git a/server/templates/login_u2f.html b/server/templates/login_u2f.html
index 1386f1ace3854cd8b0b45aeb8a2be199ea17bf75..6147232f3e5f631caa8a50b5cad2f02c64d8468d 100644
--- a/server/templates/login_u2f.html
+++ b/server/templates/login_u2f.html
@@ -4,7 +4,16 @@
       {{.CSRFField}}
       <input type="hidden" id="u2fResponseField" name="u2f_response" value="">
 
-      <h1 class="form-signin-heading">Sign In / U2F</h1>
+      <div class="row">
+          {{if .SiteLogo}}
+          <div class="col-md1">
+            <img src="./img/site_logo">
+          </div>
+          {{end}}
+          <div class="col-md3">
+            <h1 class="form-signin-heading">Sign In / U2F</h1>
+          </div>
+      </div>
 
       {{if .Error}}
       <p class="error">