1

So I want to run screen inside a systemd service so that I can give the process (inside the daemon) commands while it is running. See at the end of the question for examples of what I want be be able to do.

What I currently have: A java application that is started with
ExecStart=/usr/bin/java -someArguments -jar server.jar -running as a daemon with user:group set to "server":"server", along with "ProtectSystem=full" and similar hardening arguments. This runs fine, no problems.

However, I want: The same as above but with it running inside a screen instance. Something like this:
ExecStart=/usr/bin/screen -DmS aServer /usr/bin/java -someArguments -jar server.jar

This latter refuses to start, output from journalctl -xe tells me: "Failed to execute command: Permission denied". I can however start screen sessions from the same user (server:server) if I do it myself in the terminal (same command as in ExecStart).

I found a solution on the internet that said:
# Uncomment this to fix screen on RHEL 8
ExecStartPre=+/bin/sh -c 'chmod 777 /run/screen'

But I instinctively do not like the 777 part, also I do not understand why it needs to run every time the daemon starts.

What I am basically asking: How do you get screen working inside a systemd daemon? Is the above solution a good idea, or is there a better way?


Examples of what I want to be able to do:

  1. have a systemd timer that has a ExecStartPre=/screen -p 0 -S -X eval 'stuff "save-all"\\015' (or similar) in its sequence.
  2. A sequence of commands during ExecStop like the one above.
  3. Ability to interact with the process when I manually connect to the Linux server (connecting to the screen instance).
Rinkana
  • 11
  • 4
  • To start a script inside screen from a service [this](https://superuser.com/questions/1276775/systemd-service-python-script-inside-screen-on-boot) may help you – Kate Oct 12 '20 at 20:13
  • Thanks, great resource! However i already use the -Dm option like it mentions, my problem is: "Failed to execute command: Permission denied" -output from "journalctl -xe". I will clarify a bit in the post. – Rinkana Oct 14 '20 at 21:02

2 Answers2

0

To run a Java-based server as a daemon in Linux, you may want to look at how something like Apache Tomcat is configured.

It begins with a service, named /etc/systemd/system/tomcat.service

# Systemd unit file for tomcat
[Unit]
Description=Apache Tomcat Web Application Container
After=syslog.target network.target

[Service]
Type=forking

Environment=JAVA_HOME=/usr/lib/jvm/jre
Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
Environment=CATALINA_HOME=/opt/tomcat
Environment=CATALINA_BASE=/opt/tomcat
Environment='CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC'
Environment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom'

ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/bin/kill -15 $MAINPID

User=tomcat
Group=tomcat
UMask=0007
RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

Notice that your server will be started by a command in the script /opt/tomcat/bin/startup.sh

Then you can do commands like:

sudo systemctl daemon-reload

sudo systemctl start tomcat

sudo systemctl status tomcat
Bert
  • 2,863
  • 12
  • 13
  • Thanks for your reply! But I don't completely understand how your suggestions solves what I'm trying to do. As far as I understand, tomcat has more functions than I need; My java program already handles its connections and such (it is a game-server), and the tomcat web-gui does not let one do more than start, stop and restart things, right? All I want is to be able to send the running java program commands (not just standard SIG_TERM and such). I want to a): send the program commands if i manually log in to the server b): have a systemd timer that sends it commands and backups its files – Rinkana Oct 14 '20 at 21:00
0

Sorry for late reply, I have actually found and solved this issue.

This issue stems from SELinux configuration on RHEL8 based operating systems.

The screen inside a daemon is blocked by SELinux on centos8 (and likely Rocky Linux, or other derivatives from RHEL 8) because of its install location. There is some SEL policy blocking daemons executing programs in /usr/bin/ - if I have understood it correctly. Unfortunately I do not remember where I stumbled upon this information.


One solution is to after installing screen copying it to an other location like /usr/local/bin. After copying the executable there make sure to set its ownership to root:screen and the permissions to -rwxr-xr-x (chmod 755).

Then simply execute screen from the new location:

ExecStart=/usr/bin/screen -DmS aServer /usr/bin/java -someArguments -jar server.jar

No need for (don't do) any chmod 777 , ExecStartPre=+ ... or similar security lessening solutions.


An other solution would be to use audit2allow capabilities of SEL by first finding the report of screen being blocked in the /var/log/audit/audit.log and then using identifying name of the entry (like the name=something) and then sending that to audit2allow with something like this:

grep 'screen-or-other-name-found' /var/log/audit/audit.log | audit2allow -M screen-inside-daemon

semodule -i screen-inside-daemon.pp

This should create a SELinux policy that permits the setup to work. Verify by running: semodule -l | grep screen-inside-daemon and by testing the service.

I have not tested this latter approach and I do no longer have any instance that would have logs from this issue, hence the unspecified name of the audit.log entry.

Rinkana
  • 11
  • 4