Single-binary self-hosted uptime monitoring and status pages on Rust axum: HTTP probes, Lighthouse audits, SEO crawler, and PDF reports.
axumdockerrustself-hostedsqlitestatus-pageuptime-monitoringvite
1use axum::{
2 extract::State,
3 http::{header, HeaderMap, StatusCode},
4 response::{IntoResponse, Response},
5 routing::get,
6 Router,
7};
8
9use crate::AppState;
10
11pub fn router() -> Router<AppState> {
12 Router::new()
13 .route("/favicon.ico", get(favicon))
14 .route("/robots.txt", get(robots))
15 .route("/sitemap.xml", get(sitemap))
16}
17
18async fn favicon() -> Response {
19 let mut h = HeaderMap::new();
20 h.insert(header::CONTENT_TYPE, "image/svg+xml".parse().unwrap());
21 let svg = r##"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
22<polyline points="2,34 18,34 24,28 30,14 36,52 42,20 48,34 62,34" fill="none" stroke="#6b9e78" stroke-width="6" stroke-linejoin="round" stroke-linecap="round"/>
23<circle cx="30" cy="14" r="3.5" fill="#c9a84c"/>
24</svg>"##;
25 (StatusCode::OK, h, svg).into_response()
26}
27
28async fn robots() -> Response {
29 let mut h = HeaderMap::new();
30 h.insert(header::CONTENT_TYPE, "text/plain".parse().unwrap());
31 (StatusCode::OK, h, "User-agent: *\nAllow: /\n").into_response()
32}
33
34async fn sitemap(State(state): State<AppState>) -> Response {
35 let mut h = HeaderMap::new();
36 h.insert(header::CONTENT_TYPE, "application/xml".parse().unwrap());
37 let base = if state.config.base_url.is_empty() {
38 "/".to_string()
39 } else {
40 format!("{}/", state.config.base_url.trim_end_matches('/'))
41 };
42 let now = chrono::Utc::now().format("%Y-%m-%d");
43 let body = format!(
44 r##"<?xml version="1.0" encoding="UTF-8"?>
45<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
46 <url><loc>{base}</loc><lastmod>{now}</lastmod></url>
47 <url><loc>{base}changelog</loc><lastmod>{now}</lastmod></url>
48</urlset>
49"##
50 );
51 (StatusCode::OK, h, body).into_response()
52}