Is there an idiomatic way in Ubuntu to run a script only the first time a machine is booted? (EC2).
7 Answers
No. But you might want to place your script in /etc/init.d/script
, and self-delete it:
#!/bin/bash
echo "Bump! I'm your first-boot script."
Delete self
rm "${0}"

- 5,859
Combining the first two answers
Assuming you name your script /usr/local/bin/firstboot.sh
put it at the end of /etc/rc.local
(this scripts runs on every boot) the scripts goes like this
Update 2022: Put the script in crontab like this
@reboot /usr/local/bin/firstboot.sh
#!/bin/bash
FLAG="/var/log/firstboot.log"
if [[ ! -f $FLAG ]]; then
#Put here your initialization sentences
echo "This is the first boot"
#the next line creates an empty file so it won't run the next boot
touch "$FLAG"
else
echo "Do nothing"
fi
-
This is not necessarily working with sysmtemd. I need to add a sleep 20 to make sure it is the last script run. – mrossi Dec 02 '16 at 19:34
-
-
@JohnDavid Creating a
/etc/rc.local/99-firstboot.sh
script didn't work after reboot. – SebMa Feb 09 '23 at 13:36 -
Make sure your script is executable. Check syslog for crontab errors. You should see something like this
Feb 5 12:43:31 madeleine cron[1432]: (CRON) INFO (Running @reboot jobs)
– Awi Feb 09 '23 at 16:42
Create a tracking file when the script runs. If the file already exists, exit the script.

- 750
-
7While it might not seem so at first glance, this may be a better solution than deleting the script as it retains the possibility to trigger it again, should you ever want to. – msanford May 08 '14 at 14:43
In my case, it was building a custom system and I had to refuse to use cloud-init and placing a script under /etc/init.d/script
didn't work - so I used systemd.
FILE /etc/systemd/system/firstboot.service
[Unit]
Description=One time boot script
[Service]
Type=simple
ExecStart=/firstboot.sh
[Install]
WantedBy=multi-user.target
and
FILE /firstboot.sh
#!/bin/bash
SOME COMMANDS YOU WANT TO EXECUTE
systemctl disable firstboot.service
rm -f /etc/systemd/system/firstboot.service
rm -f /firstboot.sh
Then enable
sudo chmod +x /firstboot.sh
sudo systemctl enable firstboot.service
This one works just fine for me.

- 2,291
-
You just need to add the directory names and filenames for the files you created. – WinEunuuchs2Unix Mar 29 '21 at 11:17
-
note that commands I've posted are
echo "sth" > filename
. The output of echo command is directed to a specific file with filename (if the file doesn't exist then it's created) – Adam Krawczyk Mar 29 '21 at 11:40 -
-
1
I'm surprised at the results I'm seeing for searching for a well-defined and supported Ubuntu "first boot" hook. Seems like the Red Hat / Fedora / CentOS crowd has had this nailed for over a decade. The closest Ubuntu equivalent seems to be oem-config-firstboot.
The idea of simply performing an rm $0
will work. But, technically there are some interesting semantics involved. Unlike most other script interpreters under Unix a shell script is read and processed one line/statement at a time. If you unlink (rm
) the file out from under it then that the instance of the shell that's processing that script is now working with an anonymous file (any file that's open but unlinked).
Consider a file like this:
#!/bin/bash
rm $0
echo "I've removed myself: $0"
ls -l $0
cat <<COMMENTARY
This is a test.
I'm still here, because the "here" doc is being fed to 'cat'
via the anonymous file through the open file descriptor.
But I cannot be re-exec'd
COMMENTARY
exec $0
If you save that to something like rmself.sh
and (hard) link that to something like tst
then running ./tst
should show something like this as output:
$ ./tst
I've removed myself: ./tst
ls: ./tst: No such file or directory
This is a test.
I'm still here, because the "here" doc is being fed to 'cat'
via the anonymous file through the open file descriptor.
But I cannot be re-exec'd
./tst: line 11: /home/jimd/bin/tst: No such file or directory
./tst: line 11: exec: /home/jimd/bin/tst: cannot execute: No such file or directory
Now there are some odd possible corner cases with regards to symlinks and cases where the script was invoked as a bare name (forcing the shell to search the $PATH
for the script.
But it seems that bash
(at least in version 3.2) prepends $0
with the path if it searched the path and otherwise leaves $0 set to whatever relative or absolute path was used to invoke the script. It doesn't seem to do any normalization or resolution relative paths nor symlinks.
Probably the cleanest "firstboot" for Ubuntu would be to create a small package (.deb) containing a script to be placed in /etc/init.d/firstboot
and a post-install script that uses update-rc.d
to link that into runlevel 1 (/etc/rc1.d
) (using a command like: update-rc.d firstboot defaults
) ... and then have the last line perform a deactivation or delete using something like: update-rc.d firstboot disable
Here's a link to the Debian update-rc.d HOWTO

- 141
The question was about running a script at first boot of EC2.
You can use cloud-init
for this purpose.
When launching a new EC2 instance you have an option to define User data
under Advanced datails
. If you place cloud-init
script there, it will be executed at first boot only.
For example you can place the following in User data
:
#cloud-config
runcmd:
- /usr/bin/command1.sh
- /usr/bin/command2.sh
The output will be written to /var/log/cloud-init-output.log
Cloud-init
can do much more than this. It is designed especially to perform early initialization of cloud instances. See the docs here: http://cloudinit.readthedocs.io/en/latest/index.html

- 1,903
- 15
- 11
You can backup current rc.local to rc.local.bak
Then you can have the stuff you want to do in rc.local and at the end just mv /etc/rc.loca.bak /etc/rc.local.

- 101
$0
is bash-specific (version >= 3). For compatibility purpose you can provide script file name instead, making this less generic:rm /etc/init.d/script
– Andrejs Cainikovs Jun 27 '12 at 16:07