Ubuntu 26.04 Boot Services Done Right: Let systemd Run frp and EasyTier for You
Short version
If you want
frp,EasyTier, a sync agent, a collector, a bot, or a proxy daemon to start automatically on Ubuntu 26.04, the key is not “where can I hide this command?” The key is “which native service manager owns its lifecycle?” This article is about unattended background services, not ordinary desktop login apps.On Ubuntu 26.04, the standard answer for a background daemon is not a shell startup hack. It is a systemd unit. systemd can wait for the network, start the process before login, collect logs, restart on failure, and stop it in order during shutdown.
I will show two paths: manual configuration, for understanding every moving part, and agent / one-click automation, for cases where you already know where the binary and config file live. The scripts are self-contained, use built-in OS mechanisms, do not download third-party wrappers, and do not include real addresses, hostnames, private domains, or secrets.

AI-generated cover: background services are started during system boot.
1. Background: A Daemon Is Not a Login App
Homelab machines, small office servers, developer workstations, and edge nodes often run small services that must keep working even when nobody is looking at them. frp, EasyTier, reverse proxies, metrics collectors, file sync agents, notification bots, and polling workers all belong to this family. Their user interface is irrelevant. Their lifetime is everything.
The early version of this setup is usually a terminal command:
/opt/frp/frpc -c /etc/frp/frpc.toml
That proves the binary and config are roughly correct, but it does not prove boot reliability. The terminal may close. The user may never log in. The process may crash. The network may not be ready during boot. A real background service needs a manager.
Think of a tunnel service as the water pump of a building. You do not want the first resident who wakes up to walk downstairs and start the pump. Power comes on, the building systems come up, and the pump starts as part of the infrastructure. That is the mental model for boot services.
Diagram: the lifecycle from boot, network readiness, daemon start, to supervision.
2. Symptoms: “It Runs” Is Not the Same as “It Starts at Boot”
Autostart problems often appear as small annoyances instead of one dramatic error:
- The tunnel disappears after reboot, but returns when you run the command manually.
- Closing the SSH session or terminal kills the daemon.
- A configuration change appears to be ignored because an old process is still running.
- The daemon exits once and never comes back.
- Shutdown becomes slow because the process does not stop cleanly.
The most common false conclusion is “the command works, so autostart should work.” A boot service runs in a different environment: different working directory, different user, fewer environment variables, earlier network timing, and stricter permissions.
3. Root Cause: You Need Lifecycle Management
A daemon needs lifecycle management: when to start, which identity to run as, which working directory to use, what it depends on, how to restart, where logs go, and how to stop.
On Ubuntu 26.04, the native mechanism is systemd service unit. You can think of it as the duty manager. Instead of asking a worker to appear whenever they feel like it, you give the manager a card: name, tool path, schedule, restart policy, and shutdown behavior.
For frp and EasyTier, ask four questions:
- Must it run before user login? For tunnels, usually yes.
- Does it need the network? Almost always.
- Does it need elevated privileges? It depends on routes, virtual interfaces, and ports.
- Should it be restarted automatically? Long-running daemons usually should.

Real screenshot 1: systemd.service documentation, the reference for Type, ExecStart, Restart, and service behavior.
4. Manual Configuration
Manual configuration is not about typing more commands. It is about understanding what the automation will change.
Use this sequence:
- Check the binary with an absolute path. Do not rely on
PATH. - Check the config file. Keep real endpoints and secrets out of screenshots and posts.
- Write the service definition. Include command, working directory, restart policy, and logging.
- Enable and start it. Enable means next boot. Start means right now.
For frp, the important part is not just the frpc command. It is the surrounding contract: start after the system can reach the network, run under a deliberate identity, restart on failure, and leave logs where you can inspect them.
For EasyTier, the same model applies. Only the binary and arguments change. If it creates a virtual interface or changes routes, the privilege model must match that requirement.
Diagram: manual configuration should follow check, write, enable, and verify.
5. Agent Automation: Give the Agent Boundaries
Here is the prompt I would give an agent:
On this Ubuntu 26.04 machine, configure the given background program as a boot-started service. Use
<SERVICE_NAME>as the service name,<BINARY_PATH>as the executable path, and<CONFIG_PATH>as the config path. First validate paths and permissions. Then write the native service configuration, enable boot autostart, start it now, and print status, logs, and rollback commands. Do not download third-party wrappers. Do not expose real IP addresses, hostnames, private domains, tokens, or secrets in output.
The important parts are “validate first” and “verify last.” Agent automation is not magic. It is a fast operator. You still need to define the guardrails.
Diagram: agent automation is not magic; it scripts the same checks and writes.
The following one-click script template is designed to be repeatable, fail early, and end with evidence.
#!/usr/bin/env bash
set -euo pipefail
# Usage:
# sudo SERVICE_NAME=frpc BINARY_PATH=/opt/frp/frpc CONFIG_PATH=/etc/frp/frpc.toml ./install-systemd-service.sh
# sudo SERVICE_NAME=easytier BINARY_PATH=/opt/easytier/easytier-core CONFIG_PATH=/etc/easytier/easytier.toml EXTRA_ARGS="--config-file /etc/easytier/easytier.toml" ./install-systemd-service.sh
SERVICE_NAME="${SERVICE_NAME:-frpc}"
BINARY_PATH="${BINARY_PATH:-/opt/frp/frpc}"
CONFIG_PATH="${CONFIG_PATH:-/etc/frp/frpc.toml}"
RUN_USER="${RUN_USER:-$SERVICE_NAME}"
EXTRA_ARGS="${EXTRA_ARGS:--c $CONFIG_PATH}"
WORK_DIR="${WORK_DIR:-$(dirname "$BINARY_PATH")}"
LOG_DIR="${LOG_DIR:-/var/log/$SERVICE_NAME}"
STATE_DIR="${STATE_DIR:-/var/lib/$SERVICE_NAME}"
if [[ $EUID -ne 0 ]]; then
echo "Please run as root." >&2
exit 1
fi
if [[ ! -x "$BINARY_PATH" ]]; then
echo "Binary is not executable: $BINARY_PATH" >&2
exit 1
fi
if [[ ! -f "$CONFIG_PATH" ]]; then
echo "Config file not found: $CONFIG_PATH" >&2
exit 1
fi
id "$RUN_USER" >/dev/null 2>&1 || useradd --system --home "$STATE_DIR" --shell /usr/sbin/nologin "$RUN_USER"
install -d -o "$RUN_USER" -g "$RUN_USER" "$LOG_DIR" "$STATE_DIR"
chown -R "$RUN_USER:$RUN_USER" "$WORK_DIR" "$STATE_DIR" "$LOG_DIR" || true
cat > "/etc/systemd/system/${SERVICE_NAME}.service" <<UNIT
[Unit]
Description=${SERVICE_NAME} background tunnel service
Documentation=https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=${RUN_USER}
Group=${RUN_USER}
WorkingDirectory=${WORK_DIR}
ExecStart=${BINARY_PATH} ${EXTRA_ARGS}
Restart=on-failure
RestartSec=5s
TimeoutStopSec=20s
KillSignal=SIGTERM
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=${LOG_DIR} ${STATE_DIR}
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable --now "${SERVICE_NAME}.service"
systemctl --no-pager --full status "${SERVICE_NAME}.service"
systemctl is-enabled "${SERVICE_NAME}.service"

Real screenshot 2: systemctl documentation, the command surface for enable, start, status, and disable.
6. Applying It to frp and EasyTier
For frp, use a service name such as frpc, point the binary to your frpc executable, and point the config path to your TOML file. The service manager then owns the process from boot onward.
For EasyTier, use a service name such as easytier, point the binary to easytier-core, and pass the config file argument expected by your version. If your setup needs a virtual network interface or route changes, confirm the privilege requirement before reducing permissions.
The two tools have different jobs, but the service pattern is identical. One is a tunnel worker; the other is a network road builder. Both need an employee badge, not a daily verbal reminder.
7. Verification Checklist
Do not stop at “the command returned successfully.” Verify:
- Autostart state: the service or task is registered for boot.
- Current state: it is running now.
- Logs: no repeated crash loop.
- Reboot: after a controlled reboot, it starts without a user session.
- Business behavior: the tunnel or mesh works, while public notes still use placeholders.
Verification is like signing for a package. The courier saying “delivered” is not enough. You still open the door and check that the box is there.
8. Common Traps
Relative paths. Manual shells hide this problem. Boot services expose it. Use absolute paths.
Depending on login. Login items, shell profiles, and open terminals are not reliable daemon managers.
Network timing. Tunnel services often fail if launched too early. Tell the native manager about the network dependency where the OS supports it.
Secrets in command lines. Process lists and task definitions can leak arguments. Prefer permission-controlled config files.
No restart policy. A daemon is allowed to fail once. It should not stay dead forever.
Diagram: when autostart fails, debug permissions, paths, network, and logs.
9. Rollback
Rollback should be as deliberate as installation: stop the service, disable autostart, remove the service definition, and reload the service manager if the OS requires it. Do not delete binaries and configs unless you are sure no other unit uses them.
If installation is onboarding an employee, rollback is offboarding. You return the badge; you do not burn down the office.
10. Q&A
Can I keep using tmux, screen, or nohup?
For debugging, yes. For unattended boot services, no. They are tents, not houses.
Is a one-click script always safe?
No. It is safe only when it is readable, auditable, and reversible. Review variables and write paths before running.
Why avoid third-party wrappers?
Wrappers are sometimes useful, but this article prioritizes native OS mechanisms. Fewer dependencies mean fewer upgrade and supply-chain risks.
What if the real config requires a real server address?
Production configs do, but posts and screenshots should not. Keep the real config on the machine and use placeholders such as <SERVER_ENDPOINT> in shared material.

Real screenshot 3: Ubuntu manpage for systemd units, covering dependencies and install targets.