How can I execute command on startup (rc.local alternative) on Ubuntu 16.10

Intro

I think you should not create a new service as suggested in the link by George. The rc-local.service already exists in systemd and the service file suggests that the rc.local, if it exists and is executable, gets pulled automatically into multi-user.target. So no need to recreate or force something that is just done in another way by the systemd-rc-local-generator.

One solution

A quick solution (I don't know if that's the canonical way):

In a terminal do:

printf '%s\n' '#!/bin/bash' 'exit 0' | sudo tee -a /etc/rc.local
sudo chmod +x /etc/rc.local
sudo reboot

After that the rc.local will be called upon system startup. Insert what you like.

Background

If you do in a terminal:

sudo systemctl edit --full rc-local

You can see that the head comment contains lines such as:

# This unit gets pulled automatically into multi-user.target by
# systemd-rc-local-generator if /etc/rc.local is executable.

This indicates, that in this system, if there is a file called /etc/rc.local which is executable, then it will be pulled into multi-user.target automatically. So you just create the according file (sudo touch...) and make it executable (sudo chmod +x ...).


I saw this solution suggested which involves use of systemd here:

  1. Create a service:

    sudo vi /etc/systemd/system/rc-local.service
    
  2. Add your code there:

    [Unit]
    Description=/etc/rc.local Compatibility
    ConditionPathExists=/etc/rc.local
    
    [Service]
    Type=forking
    ExecStart=/etc/rc.local start
    TimeoutSec=0
    StandardOutput=tty
    RemainAfterExit=yes
    SysVStartPriority=99
    
    [Install]
    WantedBy=multi-user.target
    
  3. Create and make sure /etc/rc.local is executable and add this code inside it:

    sudo chmod +x /etc/rc.local

    #!/bin/sh -e
    #
    # rc.local
    #
    # This script is executed at the end of each multiuser runlevel.
    # Make sure that the script will "exit 0" on success or any other
    # value on error.
    #
    # In order to enable or disable this script just change the execution
    # bits.
    #
    # By default this script does nothing.
    
    exit 0
    
  4. Enable the service:

    sudo systemctl enable rc-local
    
  5. Start service and check status:

    sudo systemctl start rc-local.service
    sudo systemctl status rc-local.service
    
  6. If all goes well you can add your code to the /etc/rc.local file then restart it.

Note: Tested on Lubuntu 16.10.

Source:

https://www.linuxbabe.com/linux-server/how-to-enable-etcrc-local-with-systemd


To add to Jan's answer that, unlike the usual rc.localfile, rc-local service is executed not after all services have been started, but after the network goes online.

In some cases you may want to run commands from rc.local later. For example, I wanted it to be executed after lxd start.

In this case you can edit rc-local service startup dependencies by creating a drop-in conf file: /etc/systemd/system/rc-local.service.d/override.conf with contents:

[Unit]
After=network.target lxd.service

Where you can add a needed unit name (like I added lxd.service)

Do not forget to systemctl daemon-reload after that.

Tags:

Systemd

16.10