How to Add Comments When Breaking Long ExecStart Commands in systemd Services


1 views

When configuring systemd services, we often encounter lengthy command lines in the ExecStart directive. The standard approach of using backslashes for line continuation conflicts with comment syntax:

# This WON'T work
ExecStart=/usr/bin/command --long-option1 value1 \
# Important security flag
    --security-flag \
# Debug output
    --verbose \
    destination

systemd's unit file parser treats the entire ExecStart value as a single logical line after concatenation. Comments are only permitted:

  1. At the beginning of physical lines (before any command content)
  2. On their own dedicated lines

Here are three effective solutions I've used in production environments:

1. Environment Variables + Comments

[Service]
# Security options
Environment=SEC_OPTS="-o ExitOnForwardFailure=yes -o ServerAliveInterval=60"
# Local forwarding
Environment=LOCAL_FWD="-L 172.16.12.34:10001:localhost:10001"
# Remote forwarding
Environment=REMOTE_FWD="-R3128:127.0.0.1:3128"

ExecStart=/bin/ssh -NT $SEC_OPTS $LOCAL_FWD $REMOTE_FWD someserver

2. External Script Solution

Create a wrapper script with full documentation:

#!/bin/bash
# SSH tunnel manager
# Local port forwarding for X service
LOCAL_FWD="-L 172.16.12.34:10001:localhost:10001"

# Remote SOCKS proxy
REMOTE_FWD="-R3128:127.0.0.1:3128"

exec /bin/ssh -NT \
    -o ExitOnForwardFailure=yes \
    -o ServerAliveInterval=60 \
    $LOCAL_FWD \
    $REMOTE_FWD \
    "$@"

3. Using Drop-In Snippets

For complex services, split configuration into multiple files:

# /etc/systemd/system/ssh-tunnel.d/10-security.conf
[Service]
# Security hardening parameters
ExecStart=
ExecStart=/bin/ssh -NT -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
# /etc/systemd/system/ssh-tunnel.d/20-forwarding.conf
[Service]
# Port forwarding rules
ExecStart=
ExecStart=/bin/ssh -NT -L 172.16.12.34:10001:localhost:10001 -R3128:127.0.0.1:3128

When neither approach perfectly fits:

  • Use the Description= field liberally
  • Create adjacent .README files in /etc/systemd/system/
  • Leverage systemctl cat servicename to view all merged configurations

Remember that systemd v240+ supports ExecStartComment= for some distributions, though this isn't universally available.


When working with lengthy systemd service configurations, we often encounter ExecStart commands that span multiple lines. While the backslash continuation character (\\) allows line breaking, systemd unit files don't support inline comments between continuation lines due to their parsing rules.

The following example demonstrates why inline comments break the command:

ExecStart=/bin/ssh -NT -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 \\
# This comment breaks the command
    -L 172.16.12.34:10001:localhost:10001 \\
    someserver

systemd interprets everything after \\ as part of the command, including what appears to be a comment line.

Here are three effective approaches to document complex ExecStart commands:

1. End-of-Line Comments

Place comments at the end of each parameter line:

ExecStart=/bin/ssh -NT \
    -o ExitOnForwardFailure=yes \ # Ensures failure detection
    -o ServerAliveInterval=60 \   # Keepalive interval
    -L 172.16.12.34:10001:localhost:10001 \ # Local tunnel
    someserver

2. Configuration Splitting

Use EnvironmentFile for complex parameters:

# In service file
EnvironmentFile=/etc/default/myservice
ExecStart=/bin/ssh -NT ${SSH_OPTIONS} ${TUNNEL_OPTIONS} someserver

# In /etc/default/myservice
# SSH connection options
SSH_OPTIONS="-o ExitOnForwardFailure=yes -o ServerAliveInterval=60"

# Tunnel configuration
TUNNEL_OPTIONS="-L 172.16.12.34:10001:localhost:10001"

3. External Script Solution

For extremely complex cases, move the logic to an external script:

# service file
ExecStart=/usr/local/bin/start_tunnel.sh

# start_tunnel.sh
#!/bin/bash
# Documentation for each parameter
/bin/ssh -NT \
    -o ExitOnForwardFailure=yes \
    -o ServerAliveInterval=60 \
    -L 172.16.12.34:10001:localhost:10001 \
    someserver
  • For simple cases: Use end-of-line comments
  • For medium complexity: Split into EnvironmentFile variables
  • For maximum flexibility: Use external scripts with proper documentation
  • Always test with systemd-analyze verify after changes