systemd Service
The C daemon ships with a systemd service unit and environment file for production deployment on Linux systems.
Installation
This installs:
| File | Destination |
|---|---|
timenow-daemon | /usr/local/bin/timenow-daemon |
timenow-daemon.service | /lib/systemd/system/timenow-daemon.service |
timenow-daemon.conf | /etc/timenow/timenow-daemon.conf |
Configuration
Edit the environment file with your location:
| Variable | Description | Example |
|---|---|---|
LATITUDE | Decimal degrees (-90 to 90) | 48.2082 (Vienna) |
LONGITUDE | Decimal degrees (-180 to 180) | 16.3738 (Vienna) |
INTERVAL | Update interval in seconds | 1 |
Service Management
# Enable and start
sudo systemctl enable --now timenow-daemon
# Check status
sudo systemctl status timenow-daemon
# View logs
journalctl -u timenow-daemon -f
# Restart after config change
sudo systemctl restart timenow-daemon
# Stop
sudo systemctl stop timenow-daemon
Unit File
The service unit (timenow-daemon.service) is configured as follows:
[Unit]
Description=TimeNow Solar Time Daemon
After=network.target gpsd.service
Wants=gpsd.service
[Service]
Type=forking
EnvironmentFile=/etc/timenow/timenow-daemon.conf
ExecStart=/usr/local/bin/timenow-daemon --lat=${LATITUDE} --lng=${LONGITUDE} --interval=${INTERVAL}
PIDFile=/run/timenow/timenow.pid
RuntimeDirectory=timenow
Restart=on-failure
RestartSec=5
# Security hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/run/timenow /dev/shm
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
Security Hardening
The service unit includes several systemd security features:
| Directive | Effect |
|---|---|
NoNewPrivileges=yes | Prevents privilege escalation |
ProtectSystem=strict | Mounts /usr, /boot, /efi read-only |
ProtectHome=yes | Makes /home, /root, /run/user inaccessible |
ReadWritePaths=/run/timenow /dev/shm | Only these paths are writable |
PrivateTmp=yes | Isolates /tmp and /var/tmp |
RuntimeDirectory=timenow | Creates /run/timenow with correct ownership |
Additional Hardening (Optional)
For maximum isolation, add these directives to the [Service] section:
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictNamespaces=yes
RestrictRealtime=yes
MemoryDenyWriteExecute=yes
SystemCallFilter=@system-service
Rust Daemon with systemd
The Rust daemon runs in the foreground and does not include a service file. Create one manually:
[Unit]
Description=TimeNow Solar Time Daemon (Rust)
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/timenow-daemon-rs --lat=48.2082 --lng=16.3738 --interval=60
RuntimeDirectory=timenow
Restart=on-failure
RestartSec=5
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/run/timenow /dev/shm
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
Note
The Rust daemon uses Type=simple (not forking) because it runs in the foreground.
Then enable it:
Logs
C Daemon
The C daemon is silent by default when running as a service. Use --foreground during development to see output.
Rust Daemon
The Rust daemon always logs to stderr, which systemd captures in the journal:
Example output:
[timenow] 2025-01-15 12:30:00 UTC | elev=18.45° az=192.34° offset=-1054.23s
[timenow] 2025-01-15 12:31:00 UTC | elev=18.52° az=192.78° offset=-1050.12s
Troubleshooting
Service fails to start
# Check for errors
journalctl -u timenow-daemon -e --no-pager
# Verify config file
cat /etc/timenow/timenow-daemon.conf
# Test manually
/usr/local/bin/timenow-daemon --lat=48.2 --lng=16.37 --foreground
Permission denied on /run/timenow
Ensure the RuntimeDirectory=timenow directive is present in the service file. This tells systemd to create /run/timenow with the correct permissions before starting the daemon.
GPS Integration
The service includes Wants=gpsd.service and After=gpsd.service so it starts after GPS is available. Future versions may read coordinates directly from gpsd.