Initialization Scripts

Last updated on: October 14, 2026

Newly deployed Cloud Servers usually require some steps to set up. Everyone has their own list of things to go through from adding new user accounts to running updates and installing common applications. With Initialization scripts , you can automate the tasks you would otherwise perform again and again when booting up a new server.

Initialization scripts

Adding scripts

You can manage your scripts with the Initialization Scripts feature in your UpCloud Control Panel under your Account section. Click the Add new button at the top of the page to open the editor window.

Add initialization script

Copy any pre-existing script you might have into the script text field, or write a new script straight in the browser. Name your scripts so that you can easily distinguish between them. Once you are done, click the Save script button at the bottom to save the changes.

Deploying with a script

The Initialization scripts are supported by all of our public Linux templates. After adding any SSH keys you may wish to use, you can find the option to load your previously saved initialization scripts.

Selecting one of your stored scripts will bring it to the edit field below. You can make any last-minute changes to the script still before deployment, or you can write a completely new script right on the spot. Once you are done making changes, click the Deploy button as usual to deploy the new server. The server will perform the actions dictated by the script during the first boot up saving you considerable time and effort.

Using initialization script at deployment

If your script didn’t do what you expected, delete the server and deploy a new one to try again.

Writing scripts

Initialization scripts support anything a regular Linux shell script would. Depending on your choice of distribution, the default shell might use different implementations, but the principles remain the same. Below is an example of how to have the server automatically run the update and upgrade routines. The commands depend on the operating system's package manager. The examples cover the following operating systems, installed from the UpCloud templates:

  • Ubuntu 22.04, 24.04, and 26.04
  • Debian 12 and 13
  • AlmaLinux 9 and 10
  • Rocky Linux 9 and 10
  • Fedora 42 and 43
#!/bin/bash
# Stop at the first command that fails
set -e
# Run the commands in a noninteractive mode
export DEBIAN_FRONTEND=noninteractive
# Update source list and log the output to file
apt-get update > /tmp/init-script.log
# Upgrade available software packages with default options when available
apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -y upgrade >> /tmp/init-script.log

You can also write the script as a cloud-config file, which starts with #cloud-config. The same file works on all the operating systems listed above. This example installs nginx, adds a user with sudo rights and your SSH key, and starts nginx:

#cloud-config
package_update: true
packages:
  - nginx
users:
  - default
  - name: <username>
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
    ssh_authorized_keys:
      - <ssh-public-key>
runcmd:
  - systemctl enable --now nginx

It is also possible to enter a URL in an initialization script. If the script begins with a URL, the deployment process will attempt to fetch the script from that URL and use it instead. This allows greater flexibility including dynamically updating the initialization script between deployments.

Deploying with the API

When you create a server with the API, put the script in the user_data field as a string, with each line break written as \n, and turn on the Metadata service with "metadata": "yes". The API requires it for templates that use cloud-init. The example below deploys Ubuntu Server 24.04 LTS with the shell script above. To use another operating system, list the templates and use the template's UUID as the storage of the storage device.

GET /1.3/storage/template
POST /1.3/server
{
  "server": {
    "zone": "de-fra1",
    "title": "<title>",
    "hostname": "<hostname>",
    "plan": "PREMIUM-1xCPU-1GB",
    "metadata": "yes",
    "user_data": "#!/bin/bash\n# Stop at the first command that fails\nset -e\n# Run the commands in a noninteractive mode\nexport DEBIAN_FRONTEND=noninteractive\n# Update source list and log the output to file\napt-get update > /tmp/init-script.log\n# Upgrade available software packages with default options when available\napt-get -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\" -y upgrade >> /tmp/init-script.log",
    "storage_devices": {
      "storage_device": [
        {
          "action": "clone",
          "storage": "01000000-0000-4000-8000-000030240200",
          "title": "<title>-disk",
          "size": 25,
          "tier": "maxiops"
        }
      ]
    },
    "networking": {
      "interfaces": {
        "interface": [
          {
            "type": "public",
            "ip_addresses": {
              "ip_address": [
                {
                  "family": "IPv4"
                }
              ]
            }
          },
          {
            "type": "utility",
            "ip_addresses": {
              "ip_address": [
                {
                  "family": "IPv4"
                }
              ]
            }
          }
        ]
      }
    },
    "login_user": {
      "username": "root",
      "ssh_keys": {
        "ssh_key": [
          "<ssh-public-key>"
        ]
      }
    }
  }
}

Checking that the script finished

The script runs during the server's first boot. To check that it finished, connect to the server and run the following commands. The first command waits until cloud-init, which runs the script, has finished.

cloud-init status --wait --long
echo "exit code: $?"

For a script that ran without errors, the output looks like this:

Output
status: done
extended_status: done
boot_status_code: enabled-by-generator
last_update: Thu, 01 Jan 1970 00:00:54 +0000
detail: DataSourceUpCloudLocal
errors: []
recoverable_errors: {}
exit code: 0

The exit code tells you how the script went:

  • 0: the script finished without an error.
  • 1: something failed, for example a command in your script. The errors list shows where.
  • 2: cloud-init finished with recoverable errors. These can come from the operating system image rather than your script, so check the script's own output.

Start your scripts with set -e, as in the examples above. Without it, a script carries on after a command fails, and the exit code shows only whether its last command succeeded.

The script's output is in /var/log/cloud-init-output.log.

Debian 11, CentOS Stream 9, AlmaLinux 8 and Rocky Linux 8 don't use cloud-init. On these templates, shell scripts run at the first boot, but cloud-config files don't, and the cloud-init command isn't available. Check the script's results on the server instead, for example its log file.

Contributed by: Janne Ruostemaa

Can't find what you're looking for?

For more help you can contact our awesome 24/7 support team