f92c2247a0
Elixir + Phoenix dashboard displaying public and internal homelab services. Internal services are shown only when the request originates from the local network, detected server-side via conn.remote_ip with Traefik trusted as a proxy (RemoteIp plug). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
96 lines
2.5 KiB
Elixir
96 lines
2.5 KiB
Elixir
defmodule HomelabDashboardWeb.PageController do
|
|
use HomelabDashboardWeb, :controller
|
|
import Bitwise
|
|
|
|
@public_services [
|
|
%{
|
|
name: "MTG",
|
|
url: "https://adyrem.duckdns.org/mtg",
|
|
description: "Magic: The Gathering collection",
|
|
icon: "hero-puzzle-piece"
|
|
},
|
|
%{
|
|
name: "Gitea",
|
|
url: "https://adyrem.duckdns.org/git",
|
|
description: "Git repository hosting",
|
|
icon: "hero-code-bracket"
|
|
}
|
|
]
|
|
|
|
@internal_services [
|
|
%{
|
|
name: "Proxmox",
|
|
url: "https://proxmox.homelab",
|
|
description: "Virtualization & container management",
|
|
icon: "hero-server"
|
|
},
|
|
%{
|
|
name: "Grafana",
|
|
url: "https://grafana.homelab",
|
|
description: "Metrics & monitoring dashboards",
|
|
icon: "hero-chart-bar"
|
|
},
|
|
%{
|
|
name: "Pi-hole",
|
|
url: "https://pihole.homelab/admin",
|
|
description: "Network-wide DNS ad blocker",
|
|
icon: "hero-shield-check"
|
|
},
|
|
%{
|
|
name: "Jellyfin",
|
|
url: "https://jellyfin.homelab",
|
|
description: "Media server",
|
|
icon: "hero-film"
|
|
},
|
|
%{
|
|
name: "Jellyseerr",
|
|
url: "https://jellyseerr.homelab",
|
|
description: "Media request management",
|
|
icon: "hero-ticket"
|
|
},
|
|
%{
|
|
name: "Radarr",
|
|
url: "https://radarr.homelab",
|
|
description: "Movie collection manager",
|
|
icon: "hero-video-camera"
|
|
},
|
|
%{
|
|
name: "Sonarr",
|
|
url: "https://sonarr.homelab",
|
|
description: "TV series collection manager",
|
|
icon: "hero-tv"
|
|
},
|
|
%{
|
|
name: "Prowlarr",
|
|
url: "https://prowlarr.homelab",
|
|
description: "Indexer manager",
|
|
icon: "hero-magnifying-glass"
|
|
},
|
|
%{
|
|
name: "qBittorrent",
|
|
url: "https://qbittorrent.homelab",
|
|
description: "Torrent client",
|
|
icon: "hero-arrow-down-tray"
|
|
}
|
|
]
|
|
|
|
def home(conn, _params) do
|
|
render(conn, :home,
|
|
public_services: @public_services,
|
|
internal_services: @internal_services,
|
|
show_internal: internal_network?(conn.remote_ip)
|
|
)
|
|
end
|
|
|
|
defp internal_network?({127, _, _, _}), do: true
|
|
defp internal_network?({10, _, _, _}), do: true
|
|
defp internal_network?({192, 168, _, _}), do: true
|
|
defp internal_network?({172, b, _, _}) when b in 16..31, do: true
|
|
defp internal_network?({0, 0, 0, 0, 0, 0, 0, 1}), do: true
|
|
# IPv6-mapped IPv4: ::ffff:x.x.x.x — decode and re-check
|
|
defp internal_network?({0, 0, 0, 0, 0, 65535, ab, cd}) do
|
|
internal_network?({ab >>> 8, ab &&& 0xFF, cd >>> 8, cd &&& 0xFF})
|
|
end
|
|
defp internal_network?(_), do: false
|
|
end
|