Coder Perfect

How to make a Python script run like a service or daemon in Linux


I wrote a Python script that checks a specific e-mail address and forwards new messages to an external program. How can I make this script run continuously, such as by making it a daemon or service in Linux? Is it necessary to include a never-ending loop in the program, or can the code be re-executed several times?

Asked by adhanlon

Solution #1

Here you have two choices.

I wouldn’t advise you to go with option 2, because you’d be repeating cron functionality. The Linux system concept is to enable a number of simple tools work together to solve problems. Choose the other approach unless you have extra reasons to construct a daemon (other than to trigger periodically).

Also, if daemonize is used in a loop and a crash occurs, no one will check the mail after that (as pointed out by Ivan Nevostruev in comments to this answer). If the script is set up as a cron job, it will just run again.

Answered by P Shved

Solution #2

Here’s a useful class that was derived from this:

#!/usr/bin/env python

import sys, os, time, atexit
from signal import SIGTERM

class Daemon:
        A generic daemon class.

        Usage: subclass the Daemon class and override the run() method
        def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
                self.stdin = stdin
                self.stdout = stdout
                self.stderr = stderr
                self.pidfile = pidfile

        def daemonize(self):
                do the UNIX double-fork magic, see Stevens' "Advanced
                Programming in the UNIX Environment" for details (ISBN 0201563177)
                        pid = os.fork()
                        if pid > 0:
                                # exit first parent
                except OSError, e:
                        sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))

                # decouple from parent environment

                # do second fork
                        pid = os.fork()
                        if pid > 0:
                                # exit from second parent
                except OSError, e:
                        sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))

                # redirect standard file descriptors
                si = file(self.stdin, 'r')
                so = file(self.stdout, 'a+')
                se = file(self.stderr, 'a+', 0)
                os.dup2(si.fileno(), sys.stdin.fileno())
                os.dup2(so.fileno(), sys.stdout.fileno())
                os.dup2(se.fileno(), sys.stderr.fileno())

                # write pidfile
                pid = str(os.getpid())
                file(self.pidfile,'w+').write("%s\n" % pid)

        def delpid(self):

        def start(self):
                Start the daemon
                # Check for a pidfile to see if the daemon already runs
                        pf = file(self.pidfile,'r')
                        pid = int(
                except IOError:
                        pid = None

                if pid:
                        message = "pidfile %s already exist. Daemon already running?\n"
                        sys.stderr.write(message % self.pidfile)

                # Start the daemon

        def stop(self):
                Stop the daemon
                # Get the pid from the pidfile
                        pf = file(self.pidfile,'r')
                        pid = int(
                except IOError:
                        pid = None

                if not pid:
                        message = "pidfile %s does not exist. Daemon not running?\n"
                        sys.stderr.write(message % self.pidfile)
                        return # not an error in a restart

                # Try killing the daemon process       
                        while 1:
                                os.kill(pid, SIGTERM)
                except OSError, err:
                        err = str(err)
                        if err.find("No such process") > 0:
                                if os.path.exists(self.pidfile):
                                print str(err)

        def restart(self):
                Restart the daemon

        def run(self):
                You should override this method when you subclass Daemon. It will be called after the process has been
                daemonized by start() or restart().

Answered by the_drow

Solution #3

You should use the python-daemon library because it handles everything for you.

Library to create a well-behaved Unix daemon process, according to PyPI.

Answered by Prody

Solution #4

You can use fork() to separate your script from the tty and keep it running, as shown below:

import os, sys
fpid = os.fork()
if fpid!=0:
  # Running as daemon now. PID is fpid

Of course, you’ll also need to use an infinite loop, such as

while 1:

I hope this has helped you get started.

Answered by jhwist

Solution #5

Assuming you actually want your loop to run as a background service 24 hours a day, 7 days a week

Since you’re using linux, you can simply develop a service template for a solution that doesn’t entail injecting libraries into your code:

Description = <Your service description here>
After = # Assuming you want to start after network interfaces are made available

Type = simple
ExecStart = python <Path of the script you want to run>
User = # User to run the script as
Group = # Group to run the script as
Restart = on-failure # Restart when there are errors
SyslogIdentifier = <Name of logs for the service>
RestartSec = 5
TimeoutStartSec = infinity

WantedBy = # Make it accessible to other users

Place that file in your daemon service folder (usually /etc/systemd/system/), in a *.service file, and install it using the following systemctl commands (will likely require sudo privileges):

systemctl enable <service file name without .service extension>

systemctl daemon-reload

systemctl start <service file name without .service extension>

You can then use the command to see if your service is up and running:

systemctl | grep running

Answered by Heitor Castro

Post is based on