By default most of the systemd services are configured to run by root user but there is also an option to create a custom systemd service unit file and run it as a speciic user or group or both. So in this article we will check and verify the steps to run systemd service as specific user and group using CentOS/RHEL 7/8 Linux environment.
I have installed Oracle VirtualBox on a Linux server, where I will use a Virtual Machine with RHEL/CentOS 7/8 to verify the steps from this article.
Step 1: Overview on systemd
If you are a beginner to systemd then I would recommend you to also read Overview on systemd and how it is different from legacy SysV scripts before starting with this tutorial.
Step 2: Create user and Group
Now this is an optional steps assuming you already have your user and group ready for next steps. But if you do not then you can follow this article to create a new user and assign a custom group (primary or secondary) to the respective user.
- How to create a new user without using useradd command in Linux
- Steps to add a user to a group or remove a user from a group (primary or secondary) in Linux or Unix
Here I have already created a user deepak
who is part of deepak
and admin group
[root@centos-8 ~]# useradd deepak [root@centos-8 ~]# passwd deepak <-- Here the screen will prompt to assign a new password
To verify the groups of any user
[root@centos-8 ~]# id deepak uid=1000(deepak) gid=1000(deepak) groups=1000(deepak),1001(admin)
So we wish to create a systemd service unit file and run systemd service as specific user and group which for us will be deepak
user part of admin
group
Step 3: Create Sample Script
Create a directory to store your script:
mkdir -p /opt/golinuxcloud
We will use our startup_script.sh
from older articles with some tweaks to check and run systemd service as specific user and group in Linux
#!/bin/bash
if [[ `id -nu` != "deepak" ]];then
echo "Not deepak user, exiting.."
exit 1
fi
SCRIPT_NAME=$(basename -- "$0")
z=0
for i in {1..3}; do
sleep 1m
((z++))
echo "$SCRIPT_NAME: finished minute ${z}" >> /opt/golinuxcloud/file
done
echo "$SCRIPT_NAME: COMPLETELY FINISHED" >> /opt/golinuxcloud/file
So in this script we have added an explicit check for user, so unless the user executing the script is "deepak
", the script will fail to execute. If successful the script will continue to write in /opt/golinuxcloud/file
for 3 minutes with 1 minute interval. This will also help us make sure that the script does not exits before completing it's defined task
Change the ownership of the script file to deepak
chown deepak:deepak /opt/golinuxcloud/startup_script.sh
Provide executable permission to the script using chmod command
chmod u+x /opt/golinuxcloud/startup_script.sh
ls -l /opt/golinuxcloud/startup_script.sh
-r-xr--r-- 1 deepak deepak 304 Jan 17 01:58 /opt/golinuxcloud/startup_script.sh
We will execute the script manually to make sure it works as expected
[root@centos-8 ~]# /opt/golinuxcloud/startup_script.sh
Not deepak user, exiting..
Step 4: Create unit file to run systemd service as specific user and group
Now as highlighted under step 1, I have already written another article with the steps to create a new systemd unit file. Here we will name our systemd unit file as run-as-user.service
under /etc/systemd/system
. Below is the content of run-as-user.service
[root@centos-8 ~]# cat /etc/systemd/system/run-as-user.service [Unit] Description=Run service as user deepak DefaultDependencies=no After=network.target [Service] Type=simple User=deepak Group=admin ExecStart=/opt/golinuxcloud/startup_script.sh TimeoutStartSec=0 RemainAfterExit=yes [Install] WantedBy=default.target
Here we have defined User=deepak
and Group=admin
to make sure the script will be executed only as user deepak
which is part of admin
group.
You can also use many other directives if required in your environment such as WorkingDirectory
, EnvironmentFile
etc. For more information check man page of systemd.exec
Refresh the systemd configuration files
systemctl daemon-reload
Next enable the service (if required) to start automatically at boot
systemctl enable run-as-user.service
If the service was not in enabled status then you should see below message:
Created symlink /etc/systemd/system/shutdown.target.wants/run-as-user.service → /etc/systemd/system/run-as-user.service.
Step 5: Verify the systemd unit file configuration
Now since we are done with the setting up of systemd. Let us verify our configuration. Before starting I have cleared the content of /opt/golinuxcloud/file
which is where our script /opt/golinuxcloud/startup_script.sh
will place dummy content every minutes for 3 minutes.
We will only start the run-as-user.service
runtime as a reboot is not required to validate the configuration here:
systemctl restart run-as-user.service
Next check the status of the service
[root@centos-8 ~]# systemctl status run-as-user.service
● run-as-user.service - Run service as user deepak
Loaded: loaded (/etc/systemd/system/run-as-user.service; enabled; vendor preset: disabled)
Active: active (exited) since Fri 2020-01-17 02:09:32 IST; 2h 31min ago
Process: 24113 ExecStart=/opt/golinuxcloud/startup_script.sh (code=exited, status=0/SUCCESS)
Main PID: 24113 (code=exited, status=0/SUCCESS)
Jan 17 02:09:32 centos-8.example.com systemd[1]: Started Run service as user deepak.
Well looks like everything was good as we were able to run systemd service as specific user and group, you can check the ps
status to make sure our script is running using below command:
[root@centos-8 ~]# ps -ef | grep startup
deepak 26877 1 0 04:42 ? 00:00:00 /bin/bash /opt/golinuxcloud/startup_script.sh
root 26890 7625 0 04:42 pts/0 00:00:00 grep --color=auto startup
Now you can monitor the content of /opt/golinuxcloud/file
for couple of minutes as configured in the script
[root@centos-8 ~]# cat /opt/golinuxcloud/file startup_script.sh: finished minute 1 startup_script.sh: finished minute 2 startup_script.sh: finished minute 3 startup_script.sh: COMPLETELY FINISHED
Lastly I hope the steps from the article to run systemd service as specific user and group in CentOS/RHEL 7/8 Linux was helpful. So, let me know your suggestions and feedback using the comment section.
Related Searches: run service as user linux. systemd allow user to start service. systemd start service as user on boot. linux systemd service run as root. Restarting systemd service only as a specific user? systemd services fail with User= in service file. Start process as a specific user. how to run a service a non-root user completely?
Hi admin
I tried to create my customer.service like:
====
I have disabled selinux, but still see the selinux preventing systemd from execute access to the script in home directory:
SELinux is preventing
/usr/lib/systemd/systemd
from execute access on the file/home/deepak/startup_script.sh
.***** Plugin catchall (100. confidence) suggests **************************
that is weird. Have you disabled selinux or is it in Permissive mode?
Is the node rebooted after disabling selinux?
Can you share output of
getenforce
?That’s a horrible place to put the example script, in
/tmp
On many systems like fedora,
tmp
is atmpfs
file system and the script will disappear on reboot.Even on “normal” /tmp’s not on
tmpfs
, files that don’t change in a certain time will be removed from/tmp
viasystemd-tmpfiles-clean.service
Yes, that makes sense. With later releases of RHEL, CentOS I realized by default tmp will be either
tmpfs
or thetmpfiles-clean
service will clean up/tmp
frequently. I have updated the path.How can I check whether we have systemd privileges or not ?
By default non root users don’t have privilege to use systemd to restart/start/stop services but they should have permission to check the status. You may try to restart any service such as sshd and if you don’t have privilege then the same should fail
Can the service use a domain user instead of the local user when running.
E.g We have a domain user that will have access to the MSSQL DB on some server
Our client machine is redhat linux on which tomcat is running as a service.
Our client machine is already added to the same domain as the MSSQL DB
The servlet in our tomcat needs to access the MSSQL DB
Instead of SQL Authentication, we want to use windows authentication for this purpose
Now how can we run the tomcat as the same domain user that has access to the MSSQL DB ?
You can just place the username in the
User=USERNAME
field without any domain details. For ex if yourmysqldb
user isdbadmin
then just placeUser=dbadmin
and it should work. Unless you also have a local user namesdbadmin
in which case there can be conflict so you will have to delete the local user.First, Thanks a lot for this nice tutorial. This is what i am looking for.
But I faced a problem. In my one test VM, it works fine and then I have tried to do the same procedure in another machine (important vm) but the service has not started. I have tried to start the application manually it works fine (owner of statsup.sh is non-root user).
Then I commented out the User and Group in a Unit file under systemd and it works again. So I guess the problem is with the systemd service file. Kindly give me some idea what to do?
Thank you for your feedback.
Does if work if you try to start the application using the systemd service manually?
Did you checked “journalctl -b” logs for any hint?
One hint from Journalctl >> catalina.sh said permission denied (as my application call catalina.sh)
In my VM no tomcat service and owner of catalina.sh is root
but in my target machine (where i have problem) there is a tomcat service and its stopped and owner of catalina.sh is tomcat
And What does it mean to start the application using the systemd service manually? (i am a newbie)
Can you please give me any idea what to do?
I am not sure if I understand the scenario completely. On your target VM if your service is supposed to be started as root then you can remove the User and Group argument in the systemd unit file. The idea is to understand the requirement first, you mentioned that systemd service fails to start the service automatically so does that mean the service ends up being ‘dead’ or the service is not started at all.
Thanks for the response and for taking a look at this, to answer your questions:
– Just running the service after I log in, everything works, I can write to the shared folder with the service.
– the really weird thing is that I have echo statements showing that when I run as root:
– I can write to the shared folder
– the script sees the files and directories via ls right after creation
– they go away at some point. there is no delete for these files anywhere, but some of them are accessed
by a java program that the script is calling. some are not. but they all disappear by the time I can log in
and look.
Thanks for sharing the additional information, I will not approve the script as that may be confidential.
Give me time till tomorrow, let me try to replicate this and come back. I am also little occupied with my office work.
I assume you are using samba for file sharing.
We can further communicate using your mail address. You can send mail to admin@golinuxcloud.com
This is really helpful, thank you. It is also rather timely as I’m trying to get a service to work with a little twist and maybe you have some insight to this.
I’m running VirtualBox with a Ubuntu 20.04 guest and a Windows 10 host. The VM is defined with a shared folder on the host.
I need to run the service as my user and it has to create some files and directories in the shared folder.
There are some really weird things happening.
– I am unable to write anything to the shared folder when I run the script as a service. I always get “Permission Denied” errors.
No problem if I run the service as “sudo service xxx start”, only when it is started on system init. I specifically have an
“After=.mount” in the Init section.
– If I run using “+” before the script name on ExecStart, it runs as root and creates files, but then they just disappear. Actually,
they show up only in the script (e.g. if I issue an “ls” command) but by the time I get to log in, they are gone.
Anyway, I’m tearing what little hair I have out on this and can’t get anywhere. Any insight would be greatly appreciated.
Thanks
Alan
Sorry, I didn’t realize I couldn’t use angle brackets. My “After=.mount” should have been “After=shared-folder-dir.mount”, copied from the systemctl list-units list.
Hi Alan,
If there is a requirement for a certain file system then instead of
After=
you should useRequiresMountsFor=/path/to/fs
.Few questions:
If you just run the script as the user, is the script able to perform write operations in the shared folder? – I assume yes?
Because if this works, there is no reason it will fail as systemctl service.
Or do you see problems writing at reboot stage?
If I have more information, I may try to replicate the behaviour in my environment.
I see there are lot of comments. Can you please consolidate and send me a mail
Man you really helped me thanks a lot dude!
Loved! Very well explained!
Shouldn’t systemd’s “–user” feature be used to allow non-root accounts run their own services — without bothering the root-wielding admin every time they want to change something?
I’d love an actual example of that…
Any application level service is executed by normal user such as apache
what is the “admin” group? I have a “root” group, but not an admin group.
admin group used here is an example