10

I need to get the IP of the machine and use it inside my service:

[Unit]
Description=Redmine server
After=syslog.target
After=network.target

[Service]
Type=simple
User=redmine
Group=redmine
ip="$(/sbin/ip -o -4 addr list eno16777736 | awk '{print $4}' | cut -d/ -f1)"
ExecStart=/usr/bin/ruby /home/redmine/redmine/bin/rails server webrick -e production -b $ip -p 3000

# Give a reasonable amount of time for the server to start up/shut down
TimeoutSec=300

[Install]
WantedBy=multi-user.target

How can I execute this command inside the systemd service file and get its result:

ip=$(/sbin/ip -o -4 addr list eno16777736 | awk '{print $4}' | cut -d/ -f1)

in order to use its result infor xxx.xxx.xxx.xxx, sth like this:

ExecStart=/usr/bin/ruby /home/redmine/redmine/bin/rails server webrick -e production -p 3000 -b $ip
11

Getting machine hostname with systemd.

While I am not deeply familiar with systemd looking over this tutorial website as well as the official systemd man pages, what you seem to be looking for is a “specifier” value:

Many settings resolve specifiers which may be used to write generic unit files referring to runtime or unit parameters that are replaced when the unit files are loaded.

And the specific specifier I believe would work here is %H which is for “Host name” and described as:

The hostname of the running system at the point in time the unit configuration is loaded.

So checking your example systemd script, change your [Service] chunk to be this:

[Service]
Type=simple
User=redmine
Group=redmine
ExecStart=/usr/bin/ruby /home/redmine/redmine/bin/rails server webrick -e production -b %H -p 3000

Note the line with the ip=() assignment is gone and the ExecStart command now uses %H instead of $ip.

An idea for getting an IP address with systemd.

That said, it seems that systemd only provides a hostname via the %H “specifier.” Which is odd if you ask me. So while I have no deep experience with systemd, I believe I understand what could be done to achieve the goal of this post.

The key would be to setup an EnvironmentFile for systemd to read. Read up on how to use an EnvironmentFile over here on this site.

So let’s say you created a simple Bash script like this; let’s name it write_ip_to_file.sh and feel free to change the IP address fetching logic of ip=$() to match what works on your setup:

#!/bin/bash
ip=$(/sbin/ifconfig eth0 | awk '/inet addr/ {split ($2,A,":"); print A[2]}');
echo IP=$ip > ~/ip.txt;

All that would do is output the IP address of eth0 to a text file named ip.txt in your home directory. The format would be something like this:

IP=123.456.789.0

Got that? Good. Now in your systemd script, change your [Service] chunk to be something like this; be sure to set [your username] to match the username of the directory where ip.txt is saved:

[Service]
Type=simple
User=redmine
Group=redmine
EnvironmentFile=/home/[your username]/ip.txt
ExecStart=/usr/bin/ruby /home/redmine/redmine/bin/rails server webrick -e production -b $IP -p 3000

And what that would do is load the config in ip.txt and assign $IP the value of 123.456.789.0. I believe that is what you are looking for.

The key factor here is to get write_ip_to_file.sh to run on boot or perhaps even by the systemd script itself.

Another idea for getting an IP address with systemd.

But with that said, I have a better idea (if it works): Move that whole ExecStart command into the Bash file called redmine_start.sh and make sure the system can read and execute it. The contents of redmine_start.sh would be as follows; feel free to change the IP address fetching logic of ip=$() to match what works on your setup:

#!/bin/bash
ip=$(/sbin/ifconfig eth0 | awk '/inet addr/ {split ($2,A,":"); print A[2]}');
/usr/bin/ruby /home/redmine/redmine/bin/rails server webrick -e production -b $IP -p 3000

And then change your [Service] chunk to be something like this; be sure to set [your username] to match the username of the directory where redmine_start.sh is saved:

[Service]
Type=simple
User=redmine
Group=redmine
ExecStart=/home/[your username]/redmine_start.sh

If you follow the logic, if all of the logic of ExecStart is contained in redmine_start.sh then you can use that Bash trick to get the IP address, assign it to a variable and then start Redmine there. The systemd script would just be managing when/how to start that.

Getting machine IP address with init.d.

And for the reference of init.d users, I use Ubuntu and when I need to grab a current working system IP address in a Bash or an init.d startup script I run something like this:

ip=$(/sbin/ifconfig eth0 | awk '/inet addr/ {split ($2,A,":"); print A[2]}')

Of course you need to change /sbin/ifconfig to match the location of ifconfig on your system, and then also change eth0 to match the network interface you want to get the IP address of.

But once adjusted to match your setup and needs, that successfully gets an interface’s IP address and assigns it to the variable ip which can then be accessed as $ip in your script.

| improve this answer | |
  • 1
    This is for a normal script. But my question was how to do it in a sth.service file in order to supply the current IP address of that interface. – elekgeek Sep 5 '15 at 12:03
  • @elekgeek I use the same exact format in a few init.d startup service scripts I have created and the syntax/format works fine. – Giacomo1968 Sep 5 '15 at 17:16
  • 1
    but this is not working, look at the service code in the first post, this is not working.. – elekgeek Sep 6 '15 at 19:57
  • 1
    btw, this is a service, and when I view the status, it shows that $ip is not returning any results, and hence the ip is empty and the service fails to start.. – elekgeek Sep 6 '15 at 20:44
  • @elekgeek Check my latest edit. I did some digging and found some info on how systemd handles variables; they call them “specifiers.” – Giacomo1968 Sep 6 '15 at 22:37
6

Maybe this construction will work. Try it:

[Service]
Type=simple
User=redmine
Group=redmine
PermissionsStartOnly=true
ExecStartPre=/bin/bash -c "/bin/systemctl set-environment ip=$(/sbin/ip -o -4 addr list eno16777736 | awk '{print $4}' | cut -d/ -f1)"
ExecStart=/usr/bin/ruby /home/redmine/redmine/bin/rails server webrick -e production -b ${ip} -p 3000
| improve this answer | |
  • Confirmed working with systemd 228 – mleu Dec 21 '17 at 13:15
  • thanks. works like a charm. – Stelios Apr 11 '19 at 8:03
6

Use host IP addresses and EnvironmentFile

You can write your host IP addresses into /etc/network-environment file using setup-network-environment utility. Then you can run your app following way:

[Unit]
Requires=setup-network-environment.service
After=setup-network-environment.service

[Service]
EnvironmentFile=/etc/network-environment
ExecStart=/opt/bin/kubelet --hostname_override=${DEFAULT_IPV4}

Source: https://coreos.com/os/docs/latest/using-environment-variables-in-systemd-units.html

| improve this answer | |
1

Use hostname -i to get your (first) IP address and save it in SystemD's environment. You can access this variable with ${HOST_IP}.

Documentation:

  • man hostname for parameters -i and -I
  • man systemctl for set-environment
  • man systemd.service for ExecStartPre

Example

[Service]
ExecStartPre=/bin/sh -c "systemctl set-environment HOST_IP=$(hostname -i)"
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.