Skip to content

Telegram setup silently fails to start the bot on non-systemd systems (Alpine/OpenRC) #129

Description

@rvalitov

Summary

On a system without systemd, mtproxymax telegram setup reports success and sends a test
message, but never starts the bot daemon and never schedules it. Unlike the two other
service-installing features in the same script, it fails silently — no warning, no hint,
no fallback.

The bot then stays dead, which also means no alerts are ever delivered.

Impact

Users on OpenRC/Alpine get a bot that looks configured but is not running. Because the wizard
prints [✓] Telegram bot configured! and [✓] Test message sent, there is no signal that
anything is wrong. The user loses the entire alert channel — including "proxy down"
notifications — without knowing.

The same blind spot makes the management commands lie as well:

  • mtproxymax telegram status prints Telegram: ● Enabled while the daemon is dead. It echoes
    the TELEGRAM_ENABLED setting and never checks whether the process exists.
  • mtproxymax telegram disable prints Telegram disabled and leaves the daemon running.

Both were reproduced on the test box with the bot service genuinely stopped.

Environment

  • MTProxyMax: v1.4.0-LTS (06ad79a)
  • OS: Alpine Linux, OpenRC 0.63.2 (unprivileged LXC container), no systemd
  • command -v systemctl → nothing; command -v rc-service/sbin/rc-service

Alpine is otherwise a supported platform: detect_os maps it (alpine), there are apk
package branches, and alpine:latest is used for QR generation. The README lists Alpine under
System Requirements. Line numbers below are for 06ad79a and will drift.

Steps to reproduce

  1. Run mtproxymax telegram setup — provide a bot token, send /start to the bot, accept the
    defaults.
  2. Observe the wizard complete successfully.
  3. pgrep -af mtproxymax-telegram → no process.
  4. ls /etc/init.d/ → no mtproxymax*; crontab -l → no entry (only stock run-parts).
  5. The Telegram bot never responds to any command.

Root cause

setup_telegram_service() (~line 12123) installs a systemd unit only, with no else branch:

setup_telegram_service() {
    telegram_generate_service_script

    # Create systemd service
    if command -v systemctl &>/dev/null; then
        cat > /etc/systemd/system/mtproxymax-telegram.service << 'SERVICE_EOF'
        ...
        SERVICE_EOF

        systemctl daemon-reload
        systemctl enable mtproxymax-telegram.service 2>/dev/null
        systemctl restart mtproxymax-telegram.service 2>/dev/null
        log_success "Telegram bot service started"
    fi
}

The log_success sits inside the if, so on OpenRC the function neither installs anything
nor reports anything. The daemon script itself (telegram_generate_service_script, line
~11106) is generated correctly, so the caller has nothing to notice: telegram_setup_wizard
invokes setup_telegram_service as a bare statement at line ~11101 and discards its exit
status.

The unconditional systemctl calls in telegram disable (~15553), telegram remove
(~15562) and the interactive menu toggle (~17239) behave the same way: 2>/dev/null || true
turns "no systemd here" into an invisible no-op, and the success message still prints.

The same bug in two more places

  • setup_autostart() (~13231) — the main mtproxymax.service autostart has the identical
    no-else bug, so "start on boot" is silently broken on the same hosts.
  • self_update() (~10039) — the post-update restart is gated on
    command -v systemctl && [ -f /etc/systemd/system/mtproxymax-telegram.service ], so on
    OpenRC the bot is silently never restarted after an update.

Inconsistency with sibling features

Two other places already avoid this, which is why it reads as an oversight rather than an
intentional limitation:

  1. Docker enable (~line 1062) — explicit OpenRC fallback:
systemctl enable docker 2>/dev/null || rc-update add docker default 2>/dev/null || true
systemctl start  docker 2>/dev/null || service docker start      2>/dev/null || true
  1. Replication sync (setup_replication_service, ~line 12555) — warns and prints the cron
    line, then return 1:
if ! command -v systemctl &>/dev/null; then
    log_warn "systemd not found. Add cron manually:"
    echo "  * * * * * /bin/bash ${INSTALL_DIR}/mtproxymax-sync.sh"
    return 1
fi

To be precise: that does not schedule anything on a non-systemd host — it only avoids the
silence. The Telegram path is the only one of the three that says nothing at all.

Suggested fix

Implement OpenRC support rather than just warning, since Alpine is documented as supported:

  1. Write /etc/init.d/mtproxymax-telegram using supervisor=supervise-daemon
    (respawn_delay=10, respawn_max=0) to mirror the systemd unit's Restart=on-failure /
    RestartSec=10, register it with rc-update add ... default, and start it via
    rc-service ... restart.
  2. Give setup_autostart the same treatment, with a plain start/stop script mirroring
    Type=oneshot + RemainAfterExit=yes.
  3. Route the update / disable / remove / uninstall paths through the same detection so they
    stop reporting work they did not do, and make telegram status inspect the service instead
    of the settings flag.
  4. Warn loudly when neither init system is present, the way setup_replication_service
    already does.

A PR implementing the above is coming shortly.

Workaround

Hand-write /etc/init.d/mtproxymax-telegram around supervise-daemon and enable it in the
default runlevel. Note that until this is fixed, telegram disable will not stop the daemon
and telegram status will not report it accurately.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions