75

I have a Java program that I'd like to daemonize on a linux system. In other words, I want to start running it in a shell and have it continue running after I've logged out. I also want to be able to stop the program cleanly.

I found this article which uses a combination of shell scripting and Java code to do the trick. It looks good, but I'd like something simpler, if possible.

What's your preferred method to daemonize a Java program on a Linux system?

Rich Apodaca
  • 28,316
  • 16
  • 103
  • 129

11 Answers11

37

Apache Commons Daemon will run your Java program as Linux daemon or WinNT Service.

Verhagen
  • 3,885
  • 26
  • 36
Bahaa Zaid
  • 1,449
  • 2
  • 16
  • 22
31

If you can't rely on Java Service Wrapper cited elsewhere (for instance, if you are running on Ubuntu, which has no packaged version of SW) you probably want to do it the old fashioned way: have your program write its PID in /var/run/$progname.pid, and write a standard SysV init script (use for instance the one for ntpd as an example, it's simple) around it. Preferably, make it LSB-compliant, too.

Essentially, the start function tests if the program is already running (by testing if /var/run/$progname.pid exists, and the contents of that file is the PID of a running process), and if not run

logfile=/var/log/$progname.log
pidfile=/var/run/$progname.pid
nohup java -Dpidfile=$pidfile $jopts $mainClass </dev/null > $logfile 2>&1

The stop function checks on /var/run/$progname.pid, tests if that file is the PID of a running process, verifies that it is a Java VM (so as not to kill a process that simply reused the PID from a dead instance of my Java daemon) and then kills that process.

When called, my main() method will start by writing its PID in the file defined in System.getProperty("pidfile").

One major hurdle, though: in Java, there is no simple and standard way to get the PID of the process the JVM runs in.

Here is what I have come up with:

private static String getPid() {
    File proc_self = new File("/proc/self");
    if(proc_self.exists()) try {
        return proc_self.getCanonicalFile().getName();
    }
    catch(Exception e) {
        /// Continue on fall-back
    }
    File bash = new File("/bin/bash");
    if(bash.exists()) {
        ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","echo $PPID");
        try {
            Process p = pb.start();
            BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream()));
            return rd.readLine();
        }
        catch(IOException e) {
            return String.valueOf(Thread.currentThread().getId());
        }
    }
    // This is a cop-out to return something when we don't have BASH
    return String.valueOf(Thread.currentThread().getId());
}
agweber
  • 1,295
  • 2
  • 17
  • 26
Varkhan
  • 16,601
  • 5
  • 31
  • 24
  • 9
    No need for the Java to write the PID, the script can do it as well (echo $! > /var/run/my.pid) Also, since usually only root can write to /var/run you can have the shell script running as root and the daemon run as another user. – David Rabinowitz Apr 06 '09 at 10:58
  • Except you can't change uid or euid in java, so you have to do it from the shell, with sudo... it's a bit of a pain if you ask me. It's easier to have /var/run and var/log writable to the user you run as... – Varkhan Apr 06 '09 at 17:01
  • 3
    Also, the rationale for having Java write the pid file / lock file is to have a mean to know whether the initialization phase of the daemon completed successfully (by writing at the end of that phase). – Varkhan Apr 06 '09 at 17:41
  • 1
    This answer is useless. You want to do the fork AFTER the sockets are created. This just detaches the process from the shell, it's a different thing altogether. – LtWorf Jul 21 '17 at 09:10
  • The cop-out option won't work -- the thread id is almost certainly not the same as the process id. – Luke Hutchison Aug 06 '20 at 07:15
  • Using `nohup` in this context is a very bad idea. – symcbean Jun 29 '22 at 16:28
25

I frequently find myself writing scripts or command lines which essentially look like this, if I want to:

  1. Run a program that is immune to sighups
  2. That is completely disconnected from the shell which spawns it, and
  3. Produces a log file from stderr and stdout the contents of which are displayed as well, but
  4. Allows me to stop viewing the log in progress and do other stuff without disrupting the running process

Enjoy.

nohup java com.me.MyProgram </dev/null 2>&1 | tee logfile.log &
Ben Hardy
  • 1,739
  • 14
  • 16
14

I prefer the nohup command. The blog post says there are better ways, but I don't think they're enough better.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • It is not completely daemonizing .. What if the OS is rebooted ?.Here is the cleaner solution with daemontools http://stackoverflow.com/a/35569052/1840774 – Velu Apr 15 '16 at 02:16
  • 1
    this will not bring up the service once the system goes down or restarted ! – Velu Apr 15 '16 at 02:17
5

My preferred way on Ubuntu is to use the libslack 'daemon' utility. This is what Jenkins uses on Ubuntu (which is where I got the idea.) I've used it for my Jetty-based server applications and it works well.

When you stop the daemon process it will signal the JVM to shutdown. You can execute shutdown/cleanup code at this point by registering a shutdown hook with Runtime.addShutdownHook().

colini
  • 736
  • 8
  • 11
5

You could try Java Service Wrapper, the community edition is free and meets your needs.

John T
  • 23,735
  • 11
  • 56
  • 82
  • 3
    How do you know it meets his needs? The Java Service Wrapper is not free for commercial use according to its license: http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html – Jared May 21 '14 at 14:31
4

That depends. If it's just a one-time thing, I want to daemonize it and then go home, but usually I wait for the results, I might do:

nohup java com.me.MyProgram &

at the command line. To kill it cleanly, you have a lot of options. You might have a listener for SIGKILL, or listen on a port and shutdown when a connection is made, periodically check a file. Difference approaches have different weaknesses. If it's for use in production, I'd give it more thought, and probably throw a script into /etc/init.d that nohups it, and have a more sophisticated shutdown, such as what tomcat has.

Don Branson
  • 13,631
  • 10
  • 59
  • 101
  • Yeah, it is not completely daemonizing .. What if the OS is rebooted ?.Here is the cleaner solution with daemontools http://stackoverflow.com/a/35569052/1840774 – Velu Apr 15 '16 at 02:16
3

DaemonTools :- A cleaner way to manage services at UNIX https://cr.yp.to/daemontools.html

  1. Install daemon tools from the url https://cr.yp.to/daemontools/install.html follow the instruction mentioned there,for any issues please try instructions https://gist.github.com/rizkyabdilah/8516303

  2. Create a file at /etc/init/svscan.conf and add the below lines.(only required for cent-os-6.7)

 start on runlevel [12345]
 stop on runlevel [^12345]
 respawn
 exec /command/svscanboot
  1. Create a new script named run inside /service/vm/ folder and add the below lines.
#!/bin/bash    
echo starting VM 
exec java -jar
/root/learning-/daemon-java/vm.jar

Note: replace the Jar with your own Jar file. or any java class file.

  1. Reboot the system

  2. svstat /service/vm should be up and running now !.

  3. svc -d /service/vm should bring vm down now !.
  4. svc -u /service/vm should bring vm up now !.
Velu
  • 1,681
  • 1
  • 22
  • 26
2

This question is about daemonizing an arbitrary program (not java-specific) so some of the answers may apply to your case:

Community
  • 1
  • 1
dreeves
  • 26,430
  • 45
  • 154
  • 229
0

Take a look here:

http://jnicookbook.owsiak.org/recipe-no-022/

for a sample code that is based on JNI. In this case you daemonize the code that was started as Java and main loop is executed in C. But it is also possible to put main, daemon's, service loop inside Java.

https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo029

Have fun with JNI!

Oo.oO
  • 12,464
  • 3
  • 23
  • 45
-1
nohup java -jar {{your-jar.jar}} > /dev/null &

This may do the trick.

Zoe
  • 27,060
  • 21
  • 118
  • 148
fifman
  • 369
  • 4
  • 4