Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ IP_HASH_SECRET=
# BESZEL_AGENT_TOKEN=
# COMPOSE_PROFILES=monitoring

# Monitoring Basic Auth (generate hash with: caddy hash-password)
# MONITORING_USER=admin
# MONITORING_PASSWORD_HASH=
# Beszel login, created on the first start only (change it in Beszel afterwards)
# BESZEL_ADMIN_EMAIL=
# BESZEL_ADMIN_PASSWORD=

# -----------------------------------------------------------------------------
# Quick Start
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ The installer will:
- Configure PostgreSQL, Redis, Caddy, and monitoring
- Set up Beszel monitoring (host and container stats, alerts)

> **Monitoring**: After installation, open `https://monitoring.your-domain.com` right away. It is protected by basic auth (user `admin`, password shown at the end of the install); behind it, the first visitor creates the Beszel admin account.
> **Monitoring**: After installation, open `https://monitoring.your-domain.com` and log in with the monitoring login shown at the end of the install (email and password, also in `.env` as `BESZEL_ADMIN_EMAIL` / `BESZEL_ADMIN_PASSWORD`).
>
> Then pair the agent once: in Beszel, click **Add system** with host `/beszel_socket/beszel.sock`, then run `sudo ./scripts/pair-monitoring.sh` on the server and paste the public key and token it shows. Step by step in the [Monitoring guide](https://florianjs.github.io/trackarr/guide/monitoring#pairing-the-agent).
>
Expand Down
4 changes: 1 addition & 3 deletions doc/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,7 @@ announce.{$DOMAIN} {
}

{$MONITORING_DOMAIN} {
basicauth {
{$MONITORING_USER:admin} {$MONITORING_PASSWORD_HASH}
}
respond /api/beszel/create-user 403
reverse_proxy trackarr-beszel:8090
}
```
Expand Down
14 changes: 11 additions & 3 deletions doc/guide/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ sudo DOMAIN=example.com ACME_EMAIL=admin@example.com ./install.sh --yes

`./install.sh --help` lists every option.

After installation, open `https://monitoring.your-domain.com` right away: it is protected by basic auth (user `admin`, password shown at the end of the install), and the first visitor creates the Beszel admin account. Then [pair the agent](/guide/monitoring#pairing-the-agent).
After installation, open `https://monitoring.your-domain.com` and log in with the monitoring login shown at the end of the install (also in `.env`: `BESZEL_ADMIN_EMAIL` / `BESZEL_ADMIN_PASSWORD`). Then [pair the agent](/guide/monitoring#pairing-the-agent).

### Option 2: Docker Setup (Interactive)

Expand Down Expand Up @@ -161,7 +161,15 @@ Swarms refill as clients re-announce (up to 10 minutes). Upload/download transfe
:::

::: warning Upgrading: monitoring moved to Beszel
Prometheus, Grafana and the exporters are replaced by [Beszel](/guide/monitoring). After pulling, remove the old monitoring containers:
Prometheus, Grafana and the exporters are replaced by [Beszel](/guide/monitoring). After pulling, first add the Beszel login to `.env`: Beszel creates its account from it on its first start, and nobody can create one from the browser.

```bash
echo "BESZEL_ADMIN_EMAIL=you@example.com" >> .env
echo "BESZEL_ADMIN_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=')" >> .env
grep BESZEL_ADMIN .env # your monitoring login
```

Then start Beszel and remove the old monitoring containers:

```bash
docker compose -f docker-compose.prod.yml up -d --remove-orphans
Expand All @@ -174,7 +182,7 @@ docker volume ls
docker volume rm <project>_prometheus_data <project>_grafana_data
```

Then [pair the Beszel agent](/guide/monitoring#pairing-the-agent). `GRAFANA_ADMIN_USER` and `GRAFANA_ADMIN_PASSWORD` can be removed from `.env`.
Log in to `https://monitoring.your-domain.com` and [pair the Beszel agent](/guide/monitoring#pairing-the-agent). `GRAFANA_ADMIN_USER` and `GRAFANA_ADMIN_PASSWORD` can be removed from `.env`.
:::

## Next Steps
Expand Down
23 changes: 17 additions & 6 deletions doc/guide/monitoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,31 @@ The hub and the agent talk through a shared unix socket (`/beszel_socket/beszel.
| Production (`docker-compose.prod.yml`) | `https://$MONITORING_DOMAIN` |
| Local production (`docker-compose.local.yml`) | `http://localhost:3001` |

In production, Caddy puts basic auth in front of Beszel (`MONITORING_USER` / `MONITORING_PASSWORD_HASH`, generated by the installer and by `setup.sh`), then Beszel asks for its own login.
Log in with the Beszel account: the email and password in `.env` (`BESZEL_ADMIN_EMAIL` / `BESZEL_ADMIN_PASSWORD`), shown at the end of the install. Beszel creates this account on its first start, so nobody can claim the UI before you; Caddy also refuses the "create the first account" request from outside. On the local production stack (`localhost` only), you create the account on your first visit instead.

::: info Why there is no browser login prompt
Earlier versions put Caddy basic auth in front of Beszel. The Beszel UI sends its own token in the same `Authorization` header, which basic auth rejects: the browser kept asking for the password. Beszel's own login now protects it.
:::

::: details Forgot the password, or no Beszel account yet
`BESZEL_ADMIN_*` only apply on Beszel's first start: changing them later does nothing. Instead, create a Beszel superuser from the server:

```bash
docker exec trackarr-beszel /beszel superuser upsert you@example.com 'a-long-password'
```

Then open `https://monitoring.your-domain.com/_/`, log in with it, open the **users** collection, and edit your account's password (or create the account).
:::

### Pairing the agent

Do this once, after the first install (or after upgrading from Grafana). It connects the agent, which collects the stats, to the Beszel web UI. Until then, Beszel shows no system.

You need two windows: a **browser** for Beszel, and a **terminal on the server** for the agent.

#### 1. Create the Beszel admin account

Open `https://monitoring.your-domain.com` **right away**: the first visitor creates the Beszel admin account.
#### 1. Log in to Beszel

1. The browser first asks for the basic auth login: user `admin`, and the monitoring password shown at the end of the install.
2. Beszel then asks you to create its own admin account (email and password). Keep them: this is your Beszel login from now on.
Open `https://monitoring.your-domain.com` and log in with the monitoring login shown at the end of the install (also in `.env`: `BESZEL_ADMIN_EMAIL` / `BESZEL_ADMIN_PASSWORD`).

#### 2. Add the server in Beszel

Expand Down
23 changes: 19 additions & 4 deletions doc/guide/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,17 +339,32 @@ e21V5@postgres:5432/trackarr = host=postgres port=5432 auth_user=tracker

---

### Forgot Monitoring Basic Auth Password
### Monitoring Keeps Asking for a Login

**Solutions:**
**Cause:** an install from before this fix still has Caddy basic auth in front of Beszel. The Beszel UI sends its own token in the `Authorization` header, basic auth rejects it, and the browser asks again.

Generate a new hash and put it in `.env` as `MONITORING_PASSWORD_HASH`, doubling every `$` (`$$`) for Docker Compose:
**Solution:** update (`git pull`, or re-run `install.sh`), then restart Caddy:

```bash
printf '%s\n' '<new-password>' | docker run --rm -i caddy:2-alpine caddy hash-password
docker compose -f docker-compose.prod.yml up -d caddy
```

Then log in with your Beszel account only. `MONITORING_USER` and `MONITORING_PASSWORD_HASH` can be removed from `.env`.

---

### Forgot the Monitoring Password

**Solutions:**

`BESZEL_ADMIN_PASSWORD` is only read on Beszel's first start: changing it does nothing afterwards. Create a Beszel superuser instead:

```bash
docker exec trackarr-beszel /beszel superuser upsert you@example.com 'a-long-password'
```

Open `https://monitoring.your-domain.com/_/`, log in with it, open the **users** collection and set a new password on your account.

---

## Performance Issues
Expand Down
4 changes: 2 additions & 2 deletions doc/reference/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ Production only. See [Monitoring](/guide/monitoring).
| Variable | Description | Default |
| -------------------------- | ----------------------------------------------------------------------------------------------- | ------- |
| `MONITORING_DOMAIN` | Domain serving Beszel through Caddy | `monitoring.localhost` |
| `MONITORING_USER` | Caddy basic auth user in front of Beszel | `admin` |
| `MONITORING_PASSWORD_HASH` | Caddy basic auth password hash (`caddy hash-password`, every `$` doubled as `$$` in `.env`) | — |
| `BESZEL_ADMIN_EMAIL` | Beszel login email, account created on Beszel's first start only | — |
| `BESZEL_ADMIN_PASSWORD` | Beszel login password (8+ characters), first start only: change it in Beszel afterwards | — |
| `BESZEL_AGENT_KEY` | Public key shown by Beszel when adding the system (host `/beszel_socket/beszel.sock`) | — |
| `BESZEL_AGENT_TOKEN` | Token shown by Beszel with the key | — |
| `COMPOSE_PROFILES` | Set to `monitoring` once paired, so the Beszel agent starts | — |
Expand Down
5 changes: 3 additions & 2 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ services:
TRACKER_DOMAIN: ${TRACKER_DOMAIN:-tracker.localhost}
MONITORING_DOMAIN: ${MONITORING_DOMAIN:-monitoring.localhost}
ACME_EMAIL: ${ACME_EMAIL:-admin@example.com}
MONITORING_USER: ${MONITORING_USER:-admin}
MONITORING_PASSWORD_HASH: ${MONITORING_PASSWORD_HASH:-}
volumes:
- ./docker/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
Expand Down Expand Up @@ -352,6 +350,9 @@ services:
restart: always
environment:
APP_URL: https://${MONITORING_DOMAIN:-monitoring.localhost}
# Account created on the first start only (empty data); ignored after
USER_EMAIL: ${BESZEL_ADMIN_EMAIL:-}
USER_PASSWORD: ${BESZEL_ADMIN_PASSWORD:-}
volumes:
- beszel_data:/beszel_data
- beszel_socket:/beszel_socket
Expand Down
13 changes: 7 additions & 6 deletions docker/caddy/Caddyfile
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,14 @@
}
}

# Monitoring (internal access only - restrict in production)
# Monitoring: Beszel (host and container monitoring, alerts)
{$MONITORING_DOMAIN:monitoring.localhost} {
# Basic auth for monitoring endpoints
basicauth {
{$MONITORING_USER:admin} {$MONITORING_PASSWORD_HASH}
}
# No basic auth: the Beszel UI sends its own token in the Authorization
# header, which basic auth rejects, so the browser asks again and again.
# Beszel's login protects it; its account is created from .env on the
# first start (BESZEL_ADMIN_EMAIL / BESZEL_ADMIN_PASSWORD).
# Never let a visitor create the first account
respond /api/beszel/create-user 403

# Beszel (host and container monitoring, alerts)
reverse_proxy trackarr-beszel:8090
}
96 changes: 58 additions & 38 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -241,15 +241,23 @@ prompt_configuration() {
step "Configuration"

# Re-run: the previous answers are the defaults
KEEP_MONITORING_HASH=""
KEEP_MONITORING_PASSWORD=""
LEGACY_MONITORING=false
BESZEL_ADMIN_EMAIL=""
if [[ -f "$INSTALL_DIR/.env" ]]; then
log_info "Existing install in $INSTALL_DIR: its settings are the defaults"
DOMAIN=${DOMAIN:-$(existing_value DOMAIN)}
TRACKER_DOMAIN=${TRACKER_DOMAIN:-$(existing_value TRACKER_DOMAIN)}
MONITORING_DOMAIN=${MONITORING_DOMAIN:-$(existing_value MONITORING_DOMAIN)}
ACME_EMAIL=${ACME_EMAIL:-$(existing_value ACME_EMAIL)}
# Stored with $ doubled for Docker Compose
KEEP_MONITORING_HASH=$(existing_value MONITORING_PASSWORD_HASH | sed 's/\$\$/$/g')
# Beszel only reads its login on the first start: keep it as is
KEEP_MONITORING_PASSWORD=$(existing_value BESZEL_ADMIN_PASSWORD)
BESZEL_ADMIN_EMAIL=$(existing_value BESZEL_ADMIN_EMAIL)
# Installed before the Beszel login moved to .env: its account was
# created in the Beszel UI, behind the old basic auth
if [[ -z $KEEP_MONITORING_PASSWORD && -n $(existing_value MONITORING_PASSWORD_HASH) ]]; then
LEGACY_MONITORING=true
fi
fi

if [[ $ASSUME_YES == true ]]; then
Expand All @@ -271,22 +279,27 @@ prompt_configuration() {
ask TRACKER_DOMAIN "Tracker (announce) domain" "${TRACKER_DOMAIN:-announce.$DOMAIN}" is_domain "Not a valid domain name"
ask MONITORING_DOMAIN "Monitoring domain" "${MONITORING_DOMAIN:-monitoring.$DOMAIN}" is_domain "Not a valid domain name"
ask ACME_EMAIL "Email for Let's Encrypt (expiry notices)" "$ACME_EMAIL" is_email "Not a valid email address"
if [[ -z $MONITORING_PASSWORD ]]; then
if [[ -n $KEEP_MONITORING_HASH ]]; then
read -rsp " Monitoring password (Enter to keep the current one): " MONITORING_PASSWORD
else
read -rsp " Monitoring password (Enter to generate one): " MONITORING_PASSWORD
fi
echo ""
if [[ -z $MONITORING_PASSWORD && -z $KEEP_MONITORING_PASSWORD && $LEGACY_MONITORING != true ]]; then
while true; do
read -rsp " Monitoring login password, 8+ characters (Enter to generate one): " MONITORING_PASSWORD
echo ""
[[ -z $MONITORING_PASSWORD || ${#MONITORING_PASSWORD} -ge 8 ]] && break
log_error "At least 8 characters"
done
fi
fi

BESZEL_ADMIN_EMAIL=${BESZEL_ADMIN_EMAIL:-$ACME_EMAIL}
GENERATED_MONITORING_PASSWORD=false
if [[ -n $MONITORING_PASSWORD ]]; then
KEEP_MONITORING_HASH=""
elif [[ -z $KEEP_MONITORING_HASH ]]; then
if [[ -n $KEEP_MONITORING_PASSWORD ]]; then
MONITORING_PASSWORD=$KEEP_MONITORING_PASSWORD
elif [[ $LEGACY_MONITORING == true ]]; then
MONITORING_PASSWORD=""
elif [[ -z $MONITORING_PASSWORD ]]; then
MONITORING_PASSWORD=$(random_string 16)
GENERATED_MONITORING_PASSWORD=true
elif [[ ${#MONITORING_PASSWORD} -lt 8 ]]; then
die "MONITORING_PASSWORD needs at least 8 characters"
fi

check_dns
Expand Down Expand Up @@ -321,13 +334,19 @@ check_dns() {
confirm_plan() {
local secrets="generated" password="generated (shown at the end)"
[[ -f "$INSTALL_DIR/.env" ]] && secrets="kept from the existing .env"
[[ -n $KEEP_MONITORING_HASH ]] && password="unchanged"
[[ $GENERATED_MONITORING_PASSWORD != true && -n $MONITORING_PASSWORD ]] && password="the one you entered"
if [[ -n $KEEP_MONITORING_PASSWORD ]]; then
password="unchanged"
elif [[ $LEGACY_MONITORING == true ]]; then
password="your existing Beszel account"
elif [[ $GENERATED_MONITORING_PASSWORD != true ]]; then
password="the one you entered"
fi
echo ""
echo -e " ${BOLD}Summary${NC}"
echo -e " Website ${CYAN}https://${DOMAIN}${NC}"
echo -e " Announce URL ${CYAN}https://${TRACKER_DOMAIN}/announce${NC}"
echo -e " Monitoring ${CYAN}https://${MONITORING_DOMAIN}${NC} (password: ${password})"
echo -e " Monitoring ${CYAN}https://${MONITORING_DOMAIN}${NC}"
echo -e " Monitoring login ${BESZEL_ADMIN_EMAIL} (password: ${password})"
echo -e " Let's Encrypt email ${ACME_EMAIL}"
echo -e " Directory ${INSTALL_DIR}"
echo -e " Secrets ${secrets}"
Expand Down Expand Up @@ -515,16 +534,6 @@ generate_secrets() {
log_success "Secrets generated in $SECRETS_DIR"
fi

# Caddy's basic auth hash, the password going through stdin (never in
# the process list)
if [[ -n $KEEP_MONITORING_HASH ]]; then
MONITORING_PASSWORD_HASH=$KEEP_MONITORING_HASH
else
run "Downloading Caddy" docker pull -q caddy:2-alpine
MONITORING_PASSWORD_HASH=$(printf '%s\n' "$MONITORING_PASSWORD" | docker run --rm -i caddy:2-alpine caddy hash-password 2>>"$LOG_FILE") \
|| die "Could not hash the monitoring password (see $LOG_FILE)"
fi

create_env_file
}

Expand All @@ -543,6 +552,13 @@ create_env_file() {
BESZEL_ENV=$(printf '# BESZEL_AGENT_KEY=\n# BESZEL_AGENT_TOKEN=\n# COMPOSE_PROFILES=monitoring')
fi

# Beszel login, created on its first start only
if [[ $LEGACY_MONITORING == true ]]; then
BESZEL_LOGIN=$(printf '# Account created in the Beszel UI: these only apply to a new Beszel\n# BESZEL_ADMIN_EMAIL=\n# BESZEL_ADMIN_PASSWORD=')
else
BESZEL_LOGIN=$(printf 'BESZEL_ADMIN_EMAIL=%s\nBESZEL_ADMIN_PASSWORD=%s' "$BESZEL_ADMIN_EMAIL" "$MONITORING_PASSWORD")
fi

cat > "$ENV_FILE" << EOF
# =============================================================================
# Trackarr Production Environment Configuration
Expand Down Expand Up @@ -581,10 +597,9 @@ ACME_EMAIL=${ACME_EMAIL}
# Tracker Announce URLs (displayed in admin dashboard)
TRACKER_HTTP_URL=https://${TRACKER_DOMAIN}/announce

# Monitoring
MONITORING_USER=admin
# Note: $ escaped as $$ for Docker Compose compatibility
MONITORING_PASSWORD_HASH=$(echo "${MONITORING_PASSWORD_HASH}" | sed 's/\$/\$\$/g')
# Monitoring (Beszel): login read on its first start only, change the
# password in Beszel afterwards
${BESZEL_LOGIN}
# Beszel agent, once paired in the monitoring UI (see the Monitoring guide)
${BESZEL_ENV}
EOF
Expand Down Expand Up @@ -716,12 +731,16 @@ print_summary() {
echo -e " Announce URL ${CYAN}https://${TRACKER_DOMAIN}/announce${NC}"
echo -e " Monitoring ${CYAN}https://${MONITORING_DOMAIN}${NC}"
echo ""
echo -e " ${BOLD}Monitoring login${NC} (browser prompt)"
echo -e " User ${CYAN}admin${NC}"
if [[ -n $KEEP_MONITORING_HASH ]]; then
echo -e " Password unchanged"
echo -e " ${BOLD}Monitoring login${NC} (Beszel)"
if [[ $LEGACY_MONITORING == true ]]; then
echo -e " Your existing Beszel account (the browser login prompt is gone)"
else
echo -e " Password ${CYAN}${MONITORING_PASSWORD}${NC}"
echo -e " Email ${CYAN}${BESZEL_ADMIN_EMAIL}${NC}"
if [[ -n $KEEP_MONITORING_PASSWORD ]]; then
echo -e " Password unchanged (BESZEL_ADMIN_PASSWORD in .env)"
else
echo -e " Password ${CYAN}${MONITORING_PASSWORD}${NC}"
fi
fi
echo ""
echo -e " ${BOLD}Next steps${NC}"
Expand All @@ -733,8 +752,8 @@ print_summary() {
if [[ $MONITORING_PAIRED == true ]]; then
echo -e " 2. Monitoring is paired and running."
else
echo -e " 2. Open ${CYAN}https://${MONITORING_DOMAIN}${NC} now: the first visitor creates the"
echo -e " Beszel admin. Click Add system, host ${CYAN}/beszel_socket/beszel.sock${NC}, then run"
echo -e " 2. Open ${CYAN}https://${MONITORING_DOMAIN}${NC} and log in with the monitoring login."
echo -e " Click Add system, host ${CYAN}/beszel_socket/beszel.sock${NC}, then run"
echo -e " ${CYAN}sudo ${INSTALL_DIR}/scripts/pair-monitoring.sh${NC} and paste the key and token."
echo -e " Step by step: ${CYAN}${DOCS_URL}/guide/monitoring#pairing-the-agent${NC}"
fi
Expand Down Expand Up @@ -846,7 +865,8 @@ Environment variables:
TRACKER_DOMAIN Tracker announce domain (default: announce.DOMAIN)
MONITORING_DOMAIN Monitoring domain (default: monitoring.DOMAIN)
ACME_EMAIL Email for Let's Encrypt
MONITORING_PASSWORD Monitoring password (default: kept, or generated)
MONITORING_PASSWORD Monitoring (Beszel) password for a new install,
8+ characters (default: generated)
INSTALL_DIR Installation directory (default: /opt/trackarr)
REPO_URL Git repository URL
BRANCH Git branch to check out (default: main)
Expand Down
Loading