Skip to main content

Daemon Mode

Moat supports running as a daemon (background service) with proper privilege dropping and process management.

Features

  • Background execution - Runs as a detached background process
  • PID file management - Creates and manages PID files for process control
  • Privilege dropping - Can drop privileges to a specified user and group after initialization
  • Output redirection - Redirects stdout and stderr to configurable log files
  • Working directory - Configurable working directory for the daemon
  • Signal handling - Proper signal handling for graceful shutdown

Configuration

YAML Configuration

daemon:
enabled: false
pid_file: "/var/run/moat.pid"
working_directory: "/"
stdout: "/var/log/moat.out"
stderr: "/var/log/moat.err"
user: "nobody"
group: "daemon"
chown_pid_file: true

Command Line

moat --daemon \
--daemon-pid-file /var/run/moat.pid \
--daemon-working-dir / \
--daemon-stdout /var/log/moat.out \
--daemon-stderr /var/log/moat.err \
--daemon-user nobody \
--daemon-group daemon \
--iface eth0 --upstream "http://127.0.0.1:8081" --arxignis-api-key "your-key"

Environment Variables

export AX_DAEMON_ENABLED="true"
export AX_DAEMON_PID_FILE="/var/run/moat.pid"
export AX_DAEMON_WORKING_DIRECTORY="/"
export AX_DAEMON_STDOUT="/var/log/moat.out"
export AX_DAEMON_STDERR="/var/log/moat.err"
export AX_DAEMON_USER="nobody"
export AX_DAEMON_GROUP="daemon"
export AX_DAEMON_CHOWN_PID_FILE="true"

Process Management

Starting the Daemon

moat --daemon --config /etc/moat/config.yaml

Stopping the Daemon

# Using PID file
kill $(cat /var/run/moat.pid)

# Or send SIGTERM
kill -TERM $(cat /var/run/moat.pid)

# Graceful shutdown with SIGINT
kill -INT $(cat /var/run/moat.pid)

Checking Status

# Check if process is running
ps aux | grep moat

# Or check PID file
if [ -f /var/run/moat.pid ]; then
pid=$(cat /var/run/moat.pid)
if ps -p $pid > /dev/null; then
echo "Moat is running (PID: $pid)"
else
echo "Moat is not running (stale PID file)"
fi
else
echo "Moat is not running"
fi

Viewing Logs

In daemon mode, logs are split:

  • stdout (/var/log/moat.out) - Application logs (info, debug, warn, error)
  • stderr (/var/log/moat.err) - Panic messages and system errors
# Tail application logs
tail -f /var/log/moat.out

# Tail error output
tail -f /var/log/moat.err

# View both logs simultaneously
tail -f /var/log/moat.out /var/log/moat.err

Security Considerations

Privilege Dropping

When running as daemon with a privileged user (e.g., root) to bind to ports < 1024 or attach XDP programs, it's recommended to drop privileges after initialization:

moat --daemon \
--daemon-user nobody \
--daemon-group daemon \
--iface eth0 --upstream "http://127.0.0.1:8081" --arxignis-api-key "your-key"

This will:

  1. Start as root (or privileged user)
  2. Bind to privileged ports (80, 443)
  3. Attach XDP programs to network interfaces
  4. Drop privileges to nobody:daemon
  5. Continue running as unprivileged user

File Permissions

Ensure proper permissions for daemon files:

# Create log directory
sudo mkdir -p /var/log/moat
sudo chown nobody:daemon /var/log/moat
sudo chmod 755 /var/log/moat

# Create PID directory
sudo mkdir -p /var/run
sudo chmod 755 /var/run

# Set up log files
sudo touch /var/log/moat.out /var/log/moat.err
sudo chown nobody:daemon /var/log/moat.out /var/log/moat.err
sudo chmod 644 /var/log/moat.out /var/log/moat.err

Systemd Integration

Create a systemd service file for easier management:

# /etc/systemd/system/moat.service
[Unit]
Description=Moat Reverse Proxy and Firewall
After=network-online.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/var/run/moat.pid
ExecStart=/usr/local/bin/moat --daemon --config /etc/moat/config.yaml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s

# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/log/moat /var/run

[Install]
WantedBy=multi-user.target

Manage with systemd:

# Enable service
sudo systemctl enable moat

# Start service
sudo systemctl start moat

# Stop service
sudo systemctl stop moat

# Restart service
sudo systemctl restart moat

# View status
sudo systemctl status moat

# View logs
sudo journalctl -u moat -f

Troubleshooting

Daemon Won't Start

Check:

  1. Log files for errors: cat /var/log/moat.err
  2. Permissions on log directory and PID file location
  3. User/group exists: id nobody
  4. Configuration file is valid: moat --config /etc/moat/config.yaml (without --daemon)

Permission Denied Errors

If you see permission errors:

  • Ensure log directory is writable by daemon user
  • Ensure PID file location is writable
  • Check that user/group specified exists
  • Verify file system permissions

Stale PID File

If daemon won't start due to existing PID file:

# Check if process is actually running
ps -p $(cat /var/run/moat.pid)

# If not running, remove stale PID file
sudo rm /var/run/moat.pid

# Then start daemon
moat --daemon --config /etc/moat/config.yaml

Usage Examples

Basic Daemon

moat --daemon --iface eth0 --upstream "http://127.0.0.1:8081" --arxignis-api-key "your-key"

Custom Settings

moat --daemon \
--daemon-pid-file /var/run/moat.pid \
--daemon-working-dir / \
--daemon-stdout /var/log/moat.out \
--daemon-stderr /var/log/moat.err \
--daemon-user nobody \
--daemon-group daemon \
--iface eth0 --upstream "http://127.0.0.1:8081" --arxignis-api-key "your-key"

With Configuration File

moat --config /path/to/config.yaml

Example config.yaml:

daemon:
enabled: true
pid_file: "/var/run/moat.pid"
working_directory: "/"
stdout: "/var/log/moat.out"
stderr: "/var/log/moat.err"
user: "nobody"
group: "daemon"
chown_pid_file: true

server:
upstream: "http://127.0.0.1:8081"

network:
iface: "eth0"

arxignis:
api_key: "your-key"

Next Steps