1672 lines
85 KiB
Elixir
1672 lines
85 KiB
Elixir
defmodule ToweropsWeb.HelpLive.Index do
|
|
@moduledoc false
|
|
use ToweropsWeb, :live_view
|
|
|
|
alias Towerops.Accounts
|
|
alias Towerops.Accounts.Scope
|
|
alias Towerops.Organizations
|
|
|
|
@impl true
|
|
def mount(_params, session, socket) do
|
|
# Check if user is logged in via session
|
|
current_user = get_current_user(socket, session)
|
|
is_authenticated = !is_nil(current_user)
|
|
|
|
# Load user's default organization if authenticated
|
|
current_organization =
|
|
if current_user do
|
|
case Organizations.list_user_organizations(current_user.id) do
|
|
[first_org | _] -> first_org
|
|
[] -> nil
|
|
end
|
|
end
|
|
|
|
# Build current_scope if authenticated
|
|
current_scope =
|
|
if current_user do
|
|
current_user
|
|
|> Scope.for_user()
|
|
|> Scope.put_organization(current_organization)
|
|
end
|
|
|
|
socket =
|
|
socket
|
|
|> assign(:page_title, "Help")
|
|
|> assign(:current_user, current_user)
|
|
|> assign(:is_authenticated, is_authenticated)
|
|
|> assign(:current_scope, current_scope)
|
|
|> assign(:timezone, if(current_user, do: current_user.timezone, else: "UTC"))
|
|
|> assign(:generated_password, nil)
|
|
|> assign(:password_generating, false)
|
|
|
|
# Generate initial password
|
|
if connected?(socket) do
|
|
send(self(), :fetch_random_password)
|
|
end
|
|
|
|
{:ok, socket}
|
|
end
|
|
|
|
@impl true
|
|
def handle_params(params, _url, socket) do
|
|
section = Map.get(params, "section", "about")
|
|
|
|
socket =
|
|
socket
|
|
|> assign(:active_section, section)
|
|
|> assign(:generated_password, nil)
|
|
|> assign(:password_generating, false)
|
|
|
|
{:noreply, socket}
|
|
end
|
|
|
|
@impl true
|
|
def handle_event("generate_password", _params, socket) do
|
|
socket = assign(socket, :password_generating, true)
|
|
send(self(), :fetch_random_password)
|
|
{:noreply, socket}
|
|
end
|
|
|
|
@impl true
|
|
def handle_info(:fetch_random_password, socket) do
|
|
case generate_random_password() do
|
|
{:ok, password} ->
|
|
{:noreply,
|
|
socket
|
|
|> assign(:generated_password, password)
|
|
|> assign(:password_generating, false)
|
|
|> put_flash(:info, "Password generated successfully from random.org")}
|
|
|
|
{:error, reason} ->
|
|
{:noreply,
|
|
socket
|
|
|> assign(:password_generating, false)
|
|
|> put_flash(:error, "Failed to generate password: #{reason}")}
|
|
end
|
|
end
|
|
|
|
defp generate_random_password do
|
|
# Generate a 24-character truly random password from random.org
|
|
# Format: uppercase, lowercase, and digits
|
|
url =
|
|
"https://www.random.org/strings/?num=1&len=24&digits=on&upperalpha=on&loweralpha=on&unique=on&format=plain&rnd=new"
|
|
|
|
case Req.get(url) do
|
|
{:ok, %{status: 200, body: body}} ->
|
|
password = String.trim(body)
|
|
{:ok, password}
|
|
|
|
{:ok, %{status: status}} ->
|
|
{:error, "random.org returned status #{status}"}
|
|
|
|
{:error, error} ->
|
|
{:error, Exception.message(error)}
|
|
end
|
|
end
|
|
|
|
defp get_current_user(socket, session) do
|
|
# Try to get current_user from socket assigns (if already set by on_mount)
|
|
with nil <- Map.get(socket.assigns, :current_user),
|
|
token when not is_nil(token) <- session["user_token"],
|
|
{user, _authenticated_at} <- Accounts.get_user_by_session_token(token) do
|
|
user
|
|
else
|
|
%Towerops.Accounts.User{} = user -> user
|
|
_ -> nil
|
|
end
|
|
end
|
|
|
|
slot :inner_block, required: true
|
|
|
|
defp code(assigns) do
|
|
~H"""
|
|
<span class="font-mono bg-gray-100 dark:bg-gray-800 px-1 py-0.5 rounded">
|
|
{render_slot(@inner_block)}
|
|
</span>
|
|
"""
|
|
end
|
|
|
|
attr :active_section, :string, required: true
|
|
attr :generated_password, :string, default: nil
|
|
attr :password_generating, :boolean, default: false
|
|
|
|
defp help_content(assigns) do
|
|
~H"""
|
|
<div class="w-full">
|
|
<div class="mb-6">
|
|
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Help & Documentation</h1>
|
|
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
|
Learn how to use Towerops to monitor your network infrastructure
|
|
</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
|
|
<!-- Sidebar Navigation -->
|
|
<div class="lg:col-span-1">
|
|
<nav class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-4 sticky top-4">
|
|
<h3 class="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-3">
|
|
Sections
|
|
</h3>
|
|
<ul class="space-y-1">
|
|
<li>
|
|
<.link
|
|
patch={~p"/help?section=about"}
|
|
class={[
|
|
"block px-3 py-2 rounded-md text-sm font-medium transition-colors",
|
|
if @active_section == "about" do
|
|
"bg-blue-50 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"
|
|
else
|
|
"text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-800"
|
|
end
|
|
]}
|
|
>
|
|
About Towerops
|
|
</.link>
|
|
</li>
|
|
<li>
|
|
<.link
|
|
patch={~p"/help?section=getting-started"}
|
|
class={[
|
|
"block px-3 py-2 rounded-md text-sm font-medium transition-colors",
|
|
if @active_section == "getting-started" do
|
|
"bg-blue-50 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"
|
|
else
|
|
"text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-800"
|
|
end
|
|
]}
|
|
>
|
|
Getting Started
|
|
</.link>
|
|
</li>
|
|
<li>
|
|
<.link
|
|
patch={~p"/help?section=sites"}
|
|
class={[
|
|
"block px-3 py-2 rounded-md text-sm font-medium transition-colors",
|
|
if @active_section == "sites" do
|
|
"bg-blue-50 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"
|
|
else
|
|
"text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-800"
|
|
end
|
|
]}
|
|
>
|
|
Sites
|
|
</.link>
|
|
</li>
|
|
<li>
|
|
<.link
|
|
patch={~p"/help?section=cloud-pollers"}
|
|
class={[
|
|
"block px-3 py-2 rounded-md text-sm font-medium transition-colors",
|
|
if @active_section == "cloud-pollers" do
|
|
"bg-blue-50 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"
|
|
else
|
|
"text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-800"
|
|
end
|
|
]}
|
|
>
|
|
Cloud Pollers
|
|
</.link>
|
|
</li>
|
|
<li>
|
|
<.link
|
|
patch={~p"/help?section=agents"}
|
|
class={[
|
|
"block px-3 py-2 rounded-md text-sm font-medium transition-colors",
|
|
if @active_section == "agents" do
|
|
"bg-blue-50 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"
|
|
else
|
|
"text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-800"
|
|
end
|
|
]}
|
|
>
|
|
Remote Pollers
|
|
</.link>
|
|
</li>
|
|
<li>
|
|
<.link
|
|
patch={~p"/help?section=mikrotik"}
|
|
class={[
|
|
"block px-3 py-2 rounded-md text-sm font-medium transition-colors",
|
|
if @active_section == "mikrotik" do
|
|
"bg-blue-50 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"
|
|
else
|
|
"text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-800"
|
|
end
|
|
]}
|
|
>
|
|
MikroTik
|
|
</.link>
|
|
</li>
|
|
<li>
|
|
<.link
|
|
patch={~p"/help?section=graphs"}
|
|
class={[
|
|
"block px-3 py-2 rounded-md text-sm font-medium transition-colors",
|
|
if @active_section == "graphs" do
|
|
"bg-blue-50 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"
|
|
else
|
|
"text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-800"
|
|
end
|
|
]}
|
|
>
|
|
Graphs & Live Polling
|
|
</.link>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
<!-- Content Area -->
|
|
<div class="lg:col-span-3">
|
|
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10">
|
|
<%= case @active_section do %>
|
|
<% "about" -> %>
|
|
<div class="p-6">
|
|
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-4">
|
|
About Towerops
|
|
</h2>
|
|
|
|
<div class="prose prose-sm dark:prose-invert max-w-none">
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Towerops is a modern network monitoring and management platform designed to provide
|
|
comprehensive visibility into your network infrastructure. It came out of a need to simplify
|
|
network monitoring and alerting while running a wireless ISP.
|
|
</p>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Our promise to you:
|
|
<ul class="list-disc list-inside">
|
|
<li>No random marketing emails or sign up for our newsletter popups.</li>
|
|
<li>No trackers EVER, no external libraries used.</li>
|
|
<li>No ads or sponsored content.</li>
|
|
<li>No data collection or sharing.</li>
|
|
<li>
|
|
Our remote agent is
|
|
<a href="https://github.com/towerops-app/towerops-agent/">
|
|
fully open source
|
|
</a>
|
|
and ONLY collects monitoring jobs from the server and WILL NEVER allow us to access any part of your internal network.
|
|
</li>
|
|
</ul>
|
|
</p>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400 mt-4">
|
|
Think of Towerops as combining the best of LibreNMS, Icinga2/Nagios, and PagerDuty into
|
|
a single, unified platform. You get deep network device monitoring with SNMP auto-discovery,
|
|
flexible health checks and alerting, and intelligent incident management—all with a modern
|
|
interface that makes complex monitoring workflows simple and accessible.
|
|
</p>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400 mt-4">
|
|
Towerops is not and has no plans to be a replacement for a full WISP/network billing system.
|
|
</p>
|
|
|
|
<div class="mt-6 grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
Network Monitoring
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Like LibreNMS, discover and monitor network devices via SNMP with support for
|
|
multi-vendor equipment, interface statistics, and topology mapping.
|
|
</p>
|
|
</div>
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
Health Checks & Alerting
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Like Icinga2/Nagios, configure flexible monitoring checks with customizable thresholds
|
|
and alert conditions for any metric or device state.
|
|
</p>
|
|
</div>
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
Incident Management
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Like PagerDuty, manage incidents with intelligent alerting, escalation policies,
|
|
and notification routing to keep your team informed.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-6 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-information-circle"
|
|
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<p class="text-sm text-blue-800 dark:text-blue-300">
|
|
Ready to get started? Check out the
|
|
<.link
|
|
patch={~p"/help?section=getting-started"}
|
|
class="underline hover:text-blue-900 dark:hover:text-blue-200"
|
|
>
|
|
Getting Started
|
|
</.link>
|
|
guide to begin monitoring your network infrastructure.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% "getting-started" -> %>
|
|
<div class="p-6">
|
|
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-4">
|
|
Getting Started with Towerops
|
|
</h2>
|
|
|
|
<div class="prose prose-sm dark:prose-invert max-w-none">
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Towerops is a network monitoring platform that helps you keep track of your network devices,
|
|
monitor their health, and get alerts when issues occur.
|
|
</p>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
|
|
Quick Start Guide
|
|
</h3>
|
|
|
|
<div class="space-y-6">
|
|
<!-- Step 1 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
1
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Create a Site
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Sites represent physical or logical locations where your network devices are located.
|
|
Start by creating a site for your office, data center, or any location where you have equipment.
|
|
</p>
|
|
<p class="text-sm text-gray-500 dark:text-gray-500 mt-2">
|
|
Navigate to
|
|
<.code>Sites</.code>
|
|
→
|
|
<.code>Add Site</.code>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
2
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Add Your First Device
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Add network devices like routers, switches, access points, or servers. You'll need the device's
|
|
IP address or hostname, and SNMP community string (for SNMP-enabled devices).
|
|
</p>
|
|
<p class="text-sm text-gray-500 dark:text-gray-500 mt-2">
|
|
Navigate to
|
|
<.code>Devices</.code>
|
|
→
|
|
<.code>Add Device</.code>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 3 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
3
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
View Device Metrics
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Click on any device to view real-time metrics including CPU usage, memory, temperature,
|
|
interface traffic, and more. Explore the different tabs to see network topology, port status,
|
|
and historical performance data.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-8 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-light-bulb"
|
|
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
|
|
Pro Tip
|
|
</h4>
|
|
<p class="text-sm text-blue-800 dark:text-blue-300">
|
|
For devices behind firewalls or in remote locations, you can deploy a remote poller
|
|
to monitor devices locally without exposing them to the internet. See the
|
|
<.link
|
|
patch={~p"/help?section=agents"}
|
|
class="underline hover:text-blue-900 dark:hover:text-blue-200"
|
|
>
|
|
Remote Pollers
|
|
</.link>
|
|
section for more information.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% "sites" -> %>
|
|
<div class="p-6">
|
|
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-4">
|
|
Sites
|
|
</h2>
|
|
|
|
<div class="prose prose-sm dark:prose-invert max-w-none">
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Sites are an optional organizational feature that lets you group devices by physical or logical
|
|
locations such as offices, datacenters, customer locations, or network zones. Sites are disabled
|
|
by default to keep things simple for single-location deployments.
|
|
</p>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
|
|
When to Enable Sites
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Consider enabling sites if you:
|
|
</p>
|
|
|
|
<ul class="space-y-2 text-gray-600 dark:text-gray-400 list-disc list-inside mt-3">
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">
|
|
Manage multiple physical locations
|
|
</strong>
|
|
- Offices, datacenters, retail stores, etc.
|
|
</li>
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">
|
|
Want to group credentials by location
|
|
</strong>
|
|
- Different SNMP communities or credentials per site
|
|
</li>
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">
|
|
Need location-based monitoring
|
|
</strong>
|
|
- Assign different remote pollers to different sites
|
|
</li>
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">
|
|
Organize by customer or department
|
|
</strong>
|
|
- Logical groupings for multi-tenant or large networks
|
|
</li>
|
|
</ul>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
|
|
When to Skip Sites
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
You can skip enabling sites if you:
|
|
</p>
|
|
|
|
<ul class="space-y-2 text-gray-600 dark:text-gray-400 list-disc list-inside mt-3">
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">Have a single location</strong>
|
|
- All devices in one office or datacenter
|
|
</li>
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">Want a simpler setup</strong>
|
|
- Devices belong directly to your organization without extra grouping
|
|
</li>
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">
|
|
Don't need location-based credentials
|
|
</strong>
|
|
- Organization-level credentials work for all devices
|
|
</li>
|
|
</ul>
|
|
|
|
<div class="mt-6 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-information-circle"
|
|
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
|
|
Note
|
|
</h4>
|
|
<p class="text-sm text-blue-800 dark:text-blue-300">
|
|
Sites are optional and disabled by default. You can start without sites and enable them
|
|
later if your needs change. When sites are disabled, all devices belong directly to
|
|
your organization.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
|
|
How Sites Work
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
When sites are enabled, devices can be organized into sites, and credentials (SNMP communities,
|
|
usernames, passwords) can be set at three levels:
|
|
</p>
|
|
|
|
<div class="mt-4 space-y-3">
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
1. Organization Level
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Default credentials that apply to all devices across all sites in your organization.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
2. Site Level (when sites enabled)
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Override organization defaults for all devices at a specific site. Useful when different
|
|
locations have different network configurations.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
3. Device Level
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Override organization or site credentials for a specific device. Useful for devices with
|
|
unique configurations.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
|
|
Enabling Sites
|
|
</h3>
|
|
|
|
<div class="space-y-4">
|
|
<!-- Step 1 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
1
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Navigate to Organization Settings
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Go to
|
|
<.code>Settings</.code>
|
|
→
|
|
<.code>Organization</.code>
|
|
and scroll to the "Site Organization" section.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
2
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Enable the "Use Sites" Toggle
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Check the box for "Use sites to organize devices" and save your settings.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 3 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
3
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Create Your First Site
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Navigate to
|
|
<.code>Sites</.code>
|
|
→
|
|
<.code>Add Site</.code>
|
|
to create your first site. Give it a descriptive name like "Main Office" or "Dallas Datacenter".
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 4 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
4
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Assign Devices to Sites
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
When creating or editing devices, you can now assign them to specific sites. The site
|
|
selector will appear in the device form.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-8 p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-exclamation-triangle"
|
|
class="h-5 w-5 text-yellow-600 dark:text-yellow-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-yellow-900 dark:text-yellow-300 mb-1">
|
|
Disabling Sites
|
|
</h4>
|
|
<p class="text-sm text-yellow-800 dark:text-yellow-300">
|
|
If you disable sites after enabling them, all devices will be removed from their sites
|
|
and assigned directly to the organization. Site assignments will be lost, but devices
|
|
will remain in your organization and continue to be monitored.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% "cloud-pollers" -> %>
|
|
<div class="p-6">
|
|
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-4">
|
|
Cloud Pollers
|
|
</h2>
|
|
|
|
<div class="prose prose-sm dark:prose-invert max-w-none">
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
If you have publicly reachable devices, they will be automatically polled from one of our cloud pollers unless overridden by your settings.
|
|
Our cloud infrastructure monitors your devices without requiring any additional setup or agent installation.
|
|
</p>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
|
|
Active Cloud Pollers
|
|
</h3>
|
|
|
|
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 overflow-hidden">
|
|
<table class="min-w-full divide-y divide-gray-200 dark:divide-white/10">
|
|
<thead class="bg-gray-50 dark:bg-gray-800/75">
|
|
<tr>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
Location
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
IPv4 Address
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
IPv6 Address
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-200 dark:divide-white/10">
|
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800">
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">
|
|
DFW (Dallas-Fort Worth)
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-600 dark:text-gray-400">
|
|
144.202.64.79
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-600 dark:text-gray-400">
|
|
2001:19f0:6401:0af2:5400:05ff:fee7:1bfb
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="mt-6 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-information-circle"
|
|
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
|
|
Firewall Configuration
|
|
</h4>
|
|
<p class="text-sm text-blue-800 dark:text-blue-300">
|
|
If your devices are behind a firewall, make sure to allow SNMP traffic (UDP port 161) and ICMP (for ping monitoring) from these IP addresses.
|
|
For devices not accessible from the public internet, consider using a
|
|
<.link
|
|
patch={~p"/help?section=agents"}
|
|
class="underline hover:text-blue-900 dark:hover:text-blue-200"
|
|
>
|
|
Remote Poller
|
|
</.link>
|
|
instead.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% "agents" -> %>
|
|
<div class="p-6">
|
|
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-4">
|
|
Remote Pollers
|
|
</h2>
|
|
|
|
<div class="prose prose-sm dark:prose-invert max-w-none">
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Remote pollers allow you to monitor devices that are not accessible from the public internet,
|
|
such as devices behind firewalls, in private networks, or at remote locations. A remote poller
|
|
runs on your network and securely communicates with Towerops to poll your devices locally.
|
|
</p>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
|
|
Requirements
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Remote pollers can run on any system that supports Docker Compose, including:
|
|
</p>
|
|
|
|
<ul class="space-y-2 text-gray-600 dark:text-gray-400 list-disc list-inside">
|
|
<li>Linux servers (Ubuntu, Debian, CentOS, RHEL, etc.)</li>
|
|
<li>Windows Server with Docker Desktop</li>
|
|
<li>macOS with Docker Desktop</li>
|
|
<li>Raspberry Pi or other ARM-based systems</li>
|
|
<li>Virtual machines (VMware, Hyper-V, Proxmox, etc.)</li>
|
|
</ul>
|
|
|
|
<div class="mt-4 p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
<strong class="text-gray-900 dark:text-white">Minimum requirements:</strong>
|
|
1 CPU core, 512 MB RAM, and network access to your devices
|
|
</p>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
|
|
Getting Started
|
|
</h3>
|
|
|
|
<div class="space-y-6">
|
|
<!-- Step 1 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
1
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Create an Agent Token
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Navigate to the
|
|
<.code>Agents</.code>
|
|
page in Towerops and create a new agent token. This token authenticates your remote poller with the Towerops platform.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
2
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Get Docker Compose Configuration
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
On the Agents page, add a new remote agent. Copy the
|
|
<.code>docker-compose.yml</.code>
|
|
file contents from the agent details, which includes your authentication token pre-configured.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 3 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
3
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Deploy the Remote Poller
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Transfer the
|
|
<.code>docker-compose.yml</.code>
|
|
file to your server and run:
|
|
</p>
|
|
<div class="mt-3 p-4 bg-black rounded-lg not-prose">
|
|
<span class="text-sm text-white font-mono">docker compose up -d</span>
|
|
</div>
|
|
<p class="text-gray-600 dark:text-gray-400 mt-3">
|
|
The remote poller will start automatically and connect to Towerops.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 4 -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
4
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Assign Devices to Remote Poller
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
You can assign devices to your remote poller in several ways:
|
|
</p>
|
|
<ul class="space-y-2 text-gray-600 dark:text-gray-400 list-disc list-inside mt-2">
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">Per Organization:</strong>
|
|
Set a default agent for all devices in your organization
|
|
</li>
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">Per Site:</strong>
|
|
Set a default agent for all devices at a specific site
|
|
</li>
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">Per Device:</strong>
|
|
Select the remote poller when creating or editing individual devices
|
|
</li>
|
|
</ul>
|
|
<p class="text-gray-600 dark:text-gray-400 mt-3">
|
|
Devices assigned to a remote poller will be monitored from your local network instead
|
|
of from the cloud.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-8 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-shield-check"
|
|
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
|
|
Security Note
|
|
</h4>
|
|
<p class="text-sm text-blue-800 dark:text-blue-300">
|
|
Remote pollers use secure WebSocket connections to communicate with Towerops.
|
|
Your agent token is encrypted and should be kept confidential. The remote poller
|
|
only needs outbound HTTPS access (port 443) to connect to Towerops - no inbound
|
|
ports need to be opened on your firewall.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
|
|
Managing Remote Pollers
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
You can view the status of your remote pollers on the Agents page. The page shows:
|
|
</p>
|
|
|
|
<ul class="space-y-2 text-gray-600 dark:text-gray-400 list-disc list-inside mt-3">
|
|
<li>Last connection time</li>
|
|
<li>Number of devices assigned to each poller</li>
|
|
<li>Connection status (online/offline)</li>
|
|
</ul>
|
|
|
|
<div class="mt-6 p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-exclamation-triangle"
|
|
class="h-5 w-5 text-yellow-600 dark:text-yellow-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-yellow-900 dark:text-yellow-300 mb-1">
|
|
Important
|
|
</h4>
|
|
<p class="text-sm text-yellow-800 dark:text-yellow-300">
|
|
If a remote poller goes offline, devices assigned to it will not be monitored until
|
|
the poller comes back online. Consider setting up monitoring alerts for your remote
|
|
pollers to be notified if they disconnect.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% "graphs" -> %>
|
|
<div class="p-6">
|
|
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-4">
|
|
Graphs & Live Polling
|
|
</h2>
|
|
|
|
<div class="prose prose-sm dark:prose-invert max-w-none">
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Towerops provides powerful visualization capabilities for all monitored metrics. Every sensor,
|
|
interface, and metric can be viewed as a time-series graph with multiple time ranges and a
|
|
real-time live polling mode for instant feedback.
|
|
</p>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
|
|
Accessing Graphs
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Graphs are available throughout Towerops wherever metrics are displayed:
|
|
</p>
|
|
|
|
<ul class="space-y-2 text-gray-600 dark:text-gray-400 list-disc list-inside mt-3">
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">Device Overview:</strong>
|
|
Click any metric tile (CPU, Memory, Temperature, etc.) to view its graph
|
|
</li>
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">Sensors Tab:</strong>
|
|
Click the graph icon next to any sensor reading
|
|
</li>
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">Interfaces Tab:</strong>
|
|
Click the graph icon next to any interface to view traffic graphs
|
|
</li>
|
|
<li>
|
|
<strong class="text-gray-900 dark:text-white">Storage Tab:</strong>
|
|
Click any storage volume to view usage over time
|
|
</li>
|
|
</ul>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
|
|
Time Ranges
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
All graphs support multiple time ranges for analyzing trends at different scales:
|
|
</p>
|
|
|
|
<div class="mt-4 grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1">
|
|
1 Hour
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Recent activity with high detail
|
|
</p>
|
|
</div>
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1">
|
|
6 Hours
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Half-day trends and patterns
|
|
</p>
|
|
</div>
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1">
|
|
12 Hours
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Business day overview
|
|
</p>
|
|
</div>
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1">
|
|
24 Hours (Default)
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Full day of activity
|
|
</p>
|
|
</div>
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1">
|
|
7 Days
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Weekly trends and patterns
|
|
</p>
|
|
</div>
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1">
|
|
30 Days
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Monthly overview and capacity planning
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
|
|
Live Polling Mode
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Live mode provides real-time sensor monitoring with data updating every second. This is perfect for:
|
|
</p>
|
|
|
|
<ul class="space-y-2 text-gray-600 dark:text-gray-400 list-disc list-inside mt-3">
|
|
<li>Testing configuration changes and seeing immediate effects</li>
|
|
<li>Monitoring system load during maintenance or upgrades</li>
|
|
<li>Watching temperature changes during thermal testing</li>
|
|
<li>Observing traffic patterns during load testing</li>
|
|
<li>Real-time troubleshooting of performance issues</li>
|
|
</ul>
|
|
|
|
<div class="mt-6 p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-signal"
|
|
class="h-5 w-5 text-green-600 dark:text-green-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-green-900 dark:text-green-300 mb-1">
|
|
How Live Mode Works
|
|
</h4>
|
|
<ul class="text-sm text-green-800 dark:text-green-300 space-y-1 list-disc list-inside">
|
|
<li>Polls sensors directly via SNMP every 1 second</li>
|
|
<li>Displays a rolling 5-minute window (300 data points)</li>
|
|
<li>Updates chart in real-time as new data arrives</li>
|
|
<li>Automatically stops when you switch to another time range</li>
|
|
<li>Works with remote pollers - polling happens on the agent</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
|
|
Using Live Mode
|
|
</h3>
|
|
|
|
<div class="space-y-4">
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
1
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Open Any Graph
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Navigate to any device and click on a metric graph (CPU, Memory, Temperature, Traffic, etc.)
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
2
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Click the "Live" Button
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
The Live button has a distinctive green gradient style and will pulse when active
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
3
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Watch Real-Time Updates
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
The graph will start updating every second with fresh data. A pulsing green indicator
|
|
shows that live polling is active.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-semibold">
|
|
4
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h4 class="text-base font-semibold text-gray-900 dark:text-white mb-2">
|
|
Switch Back to Historical Data
|
|
</h4>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Click any other time range button to stop live polling and view historical data
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
|
|
Supported Metrics in Live Mode
|
|
</h3>
|
|
|
|
<div class="mt-4 grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1 flex items-center gap-2">
|
|
<.icon name="hero-cpu-chip" class="h-4 w-4 text-blue-500" />
|
|
CPU / Processors
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Real-time CPU load and utilization
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1 flex items-center gap-2">
|
|
<.icon name="hero-circle-stack" class="h-4 w-4 text-blue-500" />
|
|
Memory Usage
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
RAM utilization percentage
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1 flex items-center gap-2">
|
|
<.icon name="hero-fire" class="h-4 w-4 text-orange-500" /> Temperature
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Device and component temperatures
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1 flex items-center gap-2">
|
|
<.icon name="hero-bolt" class="h-4 w-4 text-yellow-500" /> Voltage
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Power supply voltages
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1 flex items-center gap-2">
|
|
<.icon name="hero-server-stack" class="h-4 w-4 text-purple-500" /> Storage
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Disk usage and capacity
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-1 flex items-center gap-2">
|
|
<.icon name="hero-hashtag" class="h-4 w-4 text-green-500" /> Custom Metrics
|
|
</h4>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400">
|
|
Sessions, connections, and counts
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-6 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-information-circle"
|
|
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
|
|
Note About Traffic Graphs
|
|
</h4>
|
|
<p class="text-sm text-blue-800 dark:text-blue-300">
|
|
Live mode is currently only available for sensor metrics (CPU, memory, temperature, etc.).
|
|
Interface traffic graphs use historical data only, as traffic calculations require
|
|
comparing multiple SNMP polls over time.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
|
|
Tips for Using Graphs
|
|
</h3>
|
|
|
|
<div class="space-y-3">
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
Multiple Sensors on One Graph
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
When viewing aggregate metrics (like "Temperature" for all sensors), the graph
|
|
automatically displays all sensors of that type with different colors for easy comparison.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
Max and Min Values
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Historical graphs (non-live) display the maximum and minimum values for the selected
|
|
time range at the bottom of the chart for quick reference.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
Traffic Graph Direction
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Interface traffic graphs show outbound traffic as positive values (above zero) and
|
|
inbound traffic as negative values (below zero) for easy visualization of bidirectional flow.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
Automatic Unit Scaling
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Traffic graphs automatically scale units (bps, Kbps, Mbps, Gbps) based on the data
|
|
range for optimal readability. Hover over data points to see exact values.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-8 p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-light-bulb"
|
|
class="h-5 w-5 text-yellow-600 dark:text-yellow-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-yellow-900 dark:text-yellow-300 mb-1">
|
|
Performance Tip
|
|
</h4>
|
|
<p class="text-sm text-yellow-800 dark:text-yellow-300">
|
|
Live polling makes direct SNMP requests every second. While this provides instant
|
|
feedback, keeping many live graphs open simultaneously may impact device performance.
|
|
Use live mode for troubleshooting and testing, then switch back to historical ranges
|
|
for routine monitoring.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% "mikrotik" -> %>
|
|
<div class="p-6">
|
|
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-4">
|
|
MikroTik Configuration
|
|
</h2>
|
|
|
|
<div class="prose prose-sm dark:prose-invert max-w-none">
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Towerops supports read-only monitoring of MikroTik RouterOS devices via SSH.
|
|
In addition to SNMP polling, SSH access allows Towerops to retrieve detailed system information
|
|
and create configuration backups of your MikroTik devices for disaster recovery and audit purposes.
|
|
</p>
|
|
|
|
<div class="mt-4 space-y-4">
|
|
<div class="p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-information-circle"
|
|
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
|
|
Read-Only Access
|
|
</h4>
|
|
<p class="text-sm text-blue-800 dark:text-blue-300">
|
|
Towerops currently operates in read-only mode for MikroTik devices. Configuration changes,
|
|
reboots, and other administrative actions are not supported. This ensures your device
|
|
configurations remain unchanged by monitoring operations.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-server"
|
|
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
|
|
Cloud or Agent-Based Connections
|
|
</h4>
|
|
<p class="text-sm text-blue-800 dark:text-blue-300">
|
|
Both SNMP polling and SSH connections to MikroTik devices can be performed from either
|
|
Towerops cloud infrastructure or your remote poller (agent). For publicly accessible devices,
|
|
cloud polling is the simplest option. For devices on private networks or when you prefer
|
|
to keep SSH credentials on your local network, deploy a remote poller. The device assignment
|
|
determines which poller handles both SNMP and SSH operations.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
|
|
Security Best Practices
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
For security purposes, it is strongly recommended to create a dedicated read-only user account
|
|
for Towerops rather than using an administrator account. This follows the principle of least
|
|
privilege and minimizes potential security risks. Even though Towerops only performs read-only
|
|
operations, limiting the account permissions provides defense in depth.
|
|
</p>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
|
|
Creating a Read-Only User
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Connect to your MikroTik device via SSH or terminal and execute the following commands to
|
|
create a read-only user named <.code>towerops</.code>:
|
|
</p>
|
|
|
|
<div class="mt-4 space-y-3">
|
|
<div>
|
|
<p class="text-sm text-gray-700 dark:text-gray-300 mb-2 font-medium">
|
|
Step 1: Create a new user group with read-only permissions
|
|
</p>
|
|
<div class="p-4 bg-black rounded-lg not-prose">
|
|
<div class="flex items-start gap-2">
|
|
<code class="text-sm text-white font-mono break-all flex-1">
|
|
/user group add name=readonly policy=ssh,read,test,api
|
|
</code>
|
|
<button
|
|
type="button"
|
|
phx-click={JS.dispatch("phx:copy", to: "#step1-command")}
|
|
class="flex-shrink-0 p-1 text-blue-400 hover:text-blue-300"
|
|
title="Copy to clipboard"
|
|
>
|
|
<.icon name="hero-clipboard-document" class="h-4 w-4" />
|
|
</button>
|
|
<input
|
|
type="hidden"
|
|
id="step1-command"
|
|
value="/user group add name=readonly policy=ssh,read,test,api"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<p class="text-sm text-gray-700 dark:text-gray-300 mb-2 font-medium">
|
|
Step 2: Create the monitoring user with a strong password
|
|
</p>
|
|
<div class="p-4 bg-black rounded-lg not-prose">
|
|
<div class="flex items-start gap-2">
|
|
<code class="text-sm text-white font-mono break-all flex-1">
|
|
/user add name=towerops password={if @generated_password,
|
|
do: @generated_password,
|
|
else: "YOUR_STRONG_PASSWORD"} group=readonly
|
|
</code>
|
|
<%= if @generated_password do %>
|
|
<button
|
|
type="button"
|
|
phx-click={JS.dispatch("phx:copy", to: "#generated-password-value")}
|
|
class="flex-shrink-0 p-1 text-blue-400 hover:text-blue-300"
|
|
title="Copy to clipboard"
|
|
>
|
|
<.icon name="hero-clipboard-document" class="h-4 w-4" />
|
|
</button>
|
|
<input
|
|
type="hidden"
|
|
id="generated-password-value"
|
|
value={@generated_password}
|
|
/>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<div class="mt-3 flex items-start gap-3">
|
|
<.button
|
|
type="button"
|
|
phx-click="generate_password"
|
|
disabled={@password_generating}
|
|
>
|
|
<%= if @password_generating do %>
|
|
<.icon name="hero-arrow-path" class="h-4 w-4 mr-1 animate-spin" />
|
|
Generating...
|
|
<% else %>
|
|
<.icon name="hero-sparkles" class="h-4 w-4 mr-1" />
|
|
Regenerate Random Password
|
|
<% end %>
|
|
</.button>
|
|
<%= if @generated_password do %>
|
|
<p class="text-xs text-yellow-600 dark:text-yellow-400 font-medium mt-1.5">
|
|
⚠️ This truly random password from random.org will only be shown once!
|
|
</p>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<p class="text-sm text-gray-700 dark:text-gray-300 mb-2 font-medium">
|
|
Step 3: Verify the user was created successfully
|
|
</p>
|
|
<div class="p-4 bg-black rounded-lg not-prose">
|
|
<div class="flex items-start gap-2">
|
|
<code class="text-sm text-white font-mono break-all flex-1">
|
|
/user print detail where name=towerops
|
|
</code>
|
|
<button
|
|
type="button"
|
|
phx-click={JS.dispatch("phx:copy", to: "#step3-command")}
|
|
class="flex-shrink-0 p-1 text-blue-400 hover:text-blue-300"
|
|
title="Copy to clipboard"
|
|
>
|
|
<.icon name="hero-clipboard-document" class="h-4 w-4" />
|
|
</button>
|
|
<input
|
|
type="hidden"
|
|
id="step3-command"
|
|
value="/user print detail where name=towerops"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
|
|
Permissions Explained
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
The
|
|
<.code>readonly</.code>
|
|
group includes the following permissions. Note that while these
|
|
permissions are granted to the user account, Towerops only performs read operations and does
|
|
not make any configuration changes:
|
|
</p>
|
|
|
|
<div class="mt-4 bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 overflow-hidden">
|
|
<table class="min-w-full divide-y divide-gray-200 dark:divide-white/10">
|
|
<thead class="bg-gray-50 dark:bg-gray-800/75">
|
|
<tr>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
Permission
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
|
Description
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-200 dark:divide-white/10">
|
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800">
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900 dark:text-white">
|
|
ssh
|
|
</td>
|
|
<td class="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
|
|
Allow SSH access to the device
|
|
</td>
|
|
</tr>
|
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800">
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900 dark:text-white">
|
|
read
|
|
</td>
|
|
<td class="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
|
|
Allow viewing configuration and status (read-only)
|
|
</td>
|
|
</tr>
|
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800">
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900 dark:text-white">
|
|
test
|
|
</td>
|
|
<td class="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
|
|
Allow executing diagnostic commands (ping, traceroute, etc.)
|
|
</td>
|
|
</tr>
|
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800">
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900 dark:text-white">
|
|
api
|
|
</td>
|
|
<td class="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
|
|
Allow API access for automated monitoring
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="mt-6 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-information-circle"
|
|
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
|
|
Important Notes
|
|
</h4>
|
|
<ul class="text-sm text-blue-800 dark:text-blue-300 space-y-1 list-disc list-inside">
|
|
<li>The read-only user cannot modify device configuration</li>
|
|
<li>No write, reboot, or sensitive permissions are granted</li>
|
|
<li>Use a strong, unique password for the monitoring account</li>
|
|
<li>Consider restricting SSH access by source IP if possible</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
|
|
Configuring in Towerops
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
After creating the read-only user, configure SSH credentials in Towerops:
|
|
</p>
|
|
|
|
<div class="mt-4 space-y-4">
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
Organization-Level Configuration
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Navigate to
|
|
<.code>Settings</.code>
|
|
→
|
|
<.code>Organization</.code>
|
|
to set default
|
|
SSH credentials for all MikroTik devices in your organization.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
Site-Level Configuration
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Navigate to
|
|
<.code>Sites</.code>
|
|
→ select a site →
|
|
<.code>Edit</.code>
|
|
to override
|
|
credentials for all devices at a specific location.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
|
|
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
|
|
Device-Level Configuration
|
|
</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
When editing a MikroTik device, you can specify unique SSH credentials that override
|
|
organization and site defaults.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-6 p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
|
|
<div class="flex gap-3">
|
|
<.icon
|
|
name="hero-shield-check"
|
|
class="h-5 w-5 text-yellow-600 dark:text-yellow-400 flex-shrink-0 mt-0.5"
|
|
/>
|
|
<div>
|
|
<h4 class="text-sm font-semibold text-yellow-900 dark:text-yellow-300 mb-1">
|
|
Security Recommendations
|
|
</h4>
|
|
<ul class="text-sm text-yellow-800 dark:text-yellow-300 space-y-1 list-disc list-inside">
|
|
<li>Always use SSL/TLS for SSH connections (API-SSL on port 8729)</li>
|
|
<li>Store credentials at the organization or site level when possible</li>
|
|
<li>Rotate passwords periodically following your security policies</li>
|
|
<li>Monitor access logs for unauthorized SSH connection attempts</li>
|
|
<li>
|
|
Consider using SSH keys instead of passwords (if supported by your setup)
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% _ -> %>
|
|
<div class="p-6">
|
|
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-4">
|
|
Section Not Found
|
|
</h2>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
The requested help section could not be found.
|
|
</p>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
"""
|
|
end
|
|
end
|