Install & Compatibility
Where this runs
tested against v3.1.2 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.012s · 18MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 1.6s · import 0.012s · 19MB
16MB installed
● package 16MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
DaemonContext
✓ from daemon import DaemonContext
runner
✓ from daemon import runner
✗ from daemon.runner import DaemonRunner
`DaemonRunner` is deprecated; prefer using `DaemonContext` directly as a context manager. Older examples often show `daemon.runner` which is an older, less flexible API.
FileLock
✓ from lockfile import FileLock
Required if using the optional 'lockfile' package for PID file management.
This quickstart demonstrates how to use `DaemonContext` as a context manager to daemonize a simple Python script. It includes basic logging, optional PID file management using `lockfile.pidlockfile.TimeoutPIDLockFile`, and important configurations like `working_directory`, `umask`, and preserving open file descriptors for logging. Run this script and observe that it detaches from the terminal and continues to run, logging to `/tmp/my_daemon.log`.
import daemon
import time
import logging
import sys
import os
# Optional: for robust PID file management
try:
from lockfile import pidlockfile
except ImportError:
pidlockfile = None
LOG_FILE = '/tmp/my_daemon.log'
PID_FILE = '/tmp/my_daemon.pid'
def do_program_work():
logging.basicConfig(
filename=LOG_FILE,
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger()
logger.info("Daemon started.")
# Example: Keep track of open log file descriptor
# so daemon does not close it.
log_handler_file = None
for handler in logger.handlers:
if hasattr(handler, 'stream') and hasattr(handler.stream, 'fileno'):
log_handler_file = handler.stream.fileno()
break
while True:
logger.info(f"Daemon still running at {time.ctime()}")
time.sleep(5)
if __name__ == '__main__':
# Prepare a PID file object if lockfile is installed
pid_file = None
if pidlockfile:
pid_file = pidlockfile.TimeoutPIDLockFile(PID_FILE)
# Open the daemon context
# Explicitly keep stdout/stderr for debugging, typically redirect to /dev/null or log file
with daemon.DaemonContext(
working_directory='/',
umask=0o002, # Set umask explicitly; 0o022 or 0o027 are common
pidfile=pid_file,
stdout=sys.stdout, # For demonstration, usually redirect to a log file or /dev/null
stderr=sys.stderr, # For demonstration, usually redirect to a log file or /dev/null
files_preserve=[log_handler_file] if log_handler_file else [] # Preserve log file descriptor
):
do_program_work()
daemon --version
Debug
Known issues
deprecatedThe `daemon.runner.DaemonRunner` class is deprecated. Many older examples and tutorials might still use it. It's recommended to use `daemon.DaemonContext` directly as a context manager for a more modern and flexible approach.fixRewrite daemon logic to use `with daemon.DaemonContext():` pattern instead of instantiating `DaemonRunner` and calling its methods.
affects: <3.0 (usage still common in 3.x), deprecated in 2.x releases
gotchaBy default, `DaemonContext` closes all open file descriptors and redirects `stdin`, `stdout`, `stderr` to `/dev/null`. This means any `print()` statements or unhandled exceptions will not be visible, leading to silent failures or perceived 'lack of output'.fixExplicitly set `stdout` and `stderr` parameters in `DaemonContext` to a log file or `sys.stdout`/`sys.stderr` for debugging. For logging, ensure the file descriptor of your log handler's stream is included in the `files_preserve` list if the log file is opened before entering the daemon context. Example: `DaemonContext(stdout=open('/var/log/mydaemon.log', 'w+'), stderr=open('/var/log/mydaemon_err.log', 'w+'), files_preserve=[my_log_file_descriptor])`. affects: All versions
gotchaThe library is designed for Unix-like operating systems (Linux, macOS) and will not correctly daemonize a process on Windows. Attempts to use it on Windows will generally not result in a background daemon process.fixFor Windows, consider alternative approaches for running background services, such as Windows Services or using libraries specifically designed for Windows service management.
affects: All versions
gotchaBy default, `DaemonContext` sets the `umask` to `0` (0o000), which allows maximal file permissions. While this is done to ensure the daemon can create files with desired permissions, it might be too permissive for certain security contexts.fixExplicitly set a more restrictive `umask` value (e.g., `0o022` or `0o027`) within the `DaemonContext` constructor: `DaemonContext(umask=0o022, ...)`.
affects: All versions
gotchaPID file management (creating, locking, releasing, and cleaning up the PID file) is crucial for a well-behaved daemon to prevent multiple instances and allow graceful shutdown. Simply creating a file with the PID is not sufficient; a robust locking mechanism is needed.fixUtilize the `pidfile` argument of `DaemonContext` with a robust PID file lock implementation, such as `lockfile.pidlockfile.TimeoutPIDLockFile` from the optional `lockfile` package. Ensure that the PID file is automatically cleaned up on normal daemon exit.
affects: All versions
Errors
Common errors & fixes
OSError: [Errno 17] File exists: '/path/to/daemon.pid'
The daemon tried to create a PID file that already exists, typically because a previous instance did not terminate cleanly or is still running.
fixEnsure no other instance of the daemon is running; if you are certain none is, manually remove the specified PID file, then restart the daemon.
DaemonContextError: open('/path/to/pidfile.pid', 'w') failed: [Errno 13] Permission denied: '/path/to/pidfile.pid'
The user account attempting to run the daemon lacks the necessary write permissions for the directory specified for the PID file, or other redirected file descriptors like stdout/stderr.
fixChange the `pidfile` path (and `stdout`/`stderr` paths if applicable) to a directory where the daemon process has write permissions, or adjust directory permissions.
TypeError: an integer or file-like object is required
This error occurs when you pass a string filename directly to `stdout`, `stderr`, or `stdin` instead of an opened file-like object.
fixOpen the file using `open()` in the appropriate mode (e.g., 'w+' for stdout/stderr) and pass the resulting file object to the `DaemonContext`.
ModuleNotFoundError: No module named 'daemon'
The `python-daemon` library is not installed in the current Python environment, or there is a typo in the import statement.
fixInstall the library using `pip install python-daemon` and ensure the import statement is `from daemon import DaemonContext`.
Upgrade
Version history
3.1.2latest on PyPI · released Dec 3, 2024
Audit
Dependencies
lockfileoptionalCommonly used for robust PID file management, especially with `TimeoutPIDLockFile`.