User data

User data refers to the user-specific configuration parameters of the server's operating system. The primary use of User data is to automate server settings. These parameters are defined during the operating system installation phase and are specified as cloud-config scripts in a text file with YAML syntax or as bash scripts. While cloud-config scripts are primarily used for Linux-based systems, Windows-based systems can achieve similar automation using PowerShell scripts. More detailed information can be found in the cloud-init documentation and Microsoft PowerShell documentation.

The scripts are automatically encoded in Base64 and sent to the server, where they are executed by the cloud-init agent upon the first boot of the operating system. They are not re-applied on subsequent reboots of the same server.

In the scripts, you can specify both individual configuration parameters of the operating system and entire sequences of parameters. For example:

Scripts reference

The following scripts illustrate common automation scenarios. Examples are provided in both cloud-config and bash formats where applicable.

Script 1: Sets the timezone and locale

  • Cloud-config
#cloud-config
# Sets the timezone to UTC
timezone: "Etc/UTC"
 
# Verifies the change
runcmd:
  - timedatectl set-timezone UTC
 
# Sets the system locale to en-US
locale: "en_US.UTF-8"
  • Bash script
#!/bin/bash
 
# Sets the timezone to UTC
timedatectl set-timezone UTC
 
# Verifies the change
timedatectl
 
# Sets the system locale to en-US
localectl set-locale LANG=en_US.UTF-8
localectl set-keymap us

Script 2: Installs a set of packages

  • Cloud-config
#cloud-config
 
#Updates the package list
package_update: true
 
#Upgrades all installed packages
package_upgrade: true
 
#Installs specified packages, in this case,
#nginx, mysql-server, and apache2
packages:
- nginx
- mysql
- apache2

 
#Sets up a basic page for an Apache web server
write_files:
  - path: /var/www/html/index.html
    content: |
      <html>
      <head><title>Welcome</title></head>
      <body><h1>Welcome to your dedicated server!</h1>.</body>
      </html>
 
 
#Executes commands after package installation to start
#and enable services at system boot.
runcmd:
  - systemctl start nginx
  - systemctl enable nginx
  - systemctl start mysql
  - systemctl enable mysql
  - systemctl enable apache2
  - systemctl start apache2
  • Bash script
#!/bin/bash
 
# Updates the package list
apt-get update
 
# Upgrades all installed packages
apt-get -y upgrade
 
# Installs specified packages
apt-get install -y nginx mysql-server apache2
 
# Sets up a basic page for an Apache web server
cat <<EOF > /var/www/html/index.html
<html>
<head><title>Welcome</title></head>
<body><h1>Welcome to your dedicated server!</h1>.</body>
</html>
EOF
 
#Executes commands after package installation to start
#and enable services at system boot
systemctl start nginx
systemctl enable nginx
systemctl start mysql
systemctl enable mysql
systemctl start apache2
systemctl enable apache2

Script 3: Configures the system

  • Cloud-config
#cloud-config
 
# Sets the hostname
hostname: my-dedicated-server
 
# Creates users and adds SSH keys
users:
# User 1
  - name: username
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    groups: sudo
    home: /home/username
    shell: /bin/bash
    lock_passwd: false
    passwd: $6$rounds=4096$abcdefghijklmnopqrstuv...
    ssh-authorized-keys:
      - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA7...
 
# User 2
  - name: new_username
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    groups: sudo
    home: /home/new_username
    shell: /bin/bash
    lock_passwd: false
    passwd: $6$rounds=4096$abcdefghijklmnopqrstuv...
    ssh-authorized-keys:
      - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA7...
  • Bash script
#!/bin/bash
 
# Sets the hostname
hostnamectl set-hostname my-dedicated-server
 
# Creates users and sets up SSH keys
# User 1
username1="username"
password1="your_hashed_password1"
ssh_key1="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA7..."
 
#-m: Creates a home directory for the user. 
#-s /bin/bash: Sets the shell for the user.
useradd -m -s /bin/bash $username1
echo "$username1:$password1" | chpasswd -e
usermod -aG sudo $username1
 
mkdir -p /home/$username1/.ssh
echo $ssh_key1 > /home/$username1/.ssh/authorized_keys
chown -R $username1:$username1 /home/$username1/.ssh
chmod 700 /home/$username1/.ssh
chmod 600 /home/$username1/.ssh/authorized_keys
 
# User 2
username2="new_username"
password2="your_hashed_password2"
ssh_key2="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA7..."
 
useradd -m -s /bin/bash $username2
echo "$username2:$password2" | chpasswd -e
usermod -aG sudo $username2
 
mkdir -p /home/$username2/.ssh
echo $ssh_key2 > /home/$username2/.ssh/authorized_keys
chown -R $username2:$username2 /home/$username2/.ssh
chmod 700 /home/$username2/.ssh
chmod 600 /home/$username2/.ssh/authorized_keys

Script 4: Enables/installs SSH on Windows

  • PowerShell
Start-Transcript -path C:\postinstall.log -append
  
#Activates the administrator account:
net user Administrator /active:yes
 
#Disables administrator password expiration:
wmic UserAccount where Name='Administrator' set PasswordExpires=False
  
Disable-NetAdapterBinding -Name "*" -ComponentID ms_tcpip6
  
# RDP switch port
# https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/clients/change-listening-port
$portvalue = 21337
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -name "PortNumber" -Value $portvalue
New-NetFirewallRule -DisplayName 'RDPPORTLatest-TCP-In' -Profile 'Public' -Direction Inbound -Action Allow -Protocol TCP -LocalPort $portvalue
New-NetFirewallRule -DisplayName 'RDPPORTLatest-UDP-In' -Profile 'Public' -Direction Inbound -Action Allow -Protocol UDP -LocalPort $portvalue
  
# RDP AccountLockout
# https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/configure-remote-access-client-account-lockout
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\RemoteAccess\Parameters\AccountLockout" -Name "ResetTime (mins)" -Value "0x05"
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\RemoteAccess\Parameters\AccountLockout" -Name "MaxDenials" -Value "10"
  
# wait for internet availability
while (!(test-connection chocolatey.org -Quiet -Count 5)) {
    sleep 5
}
  
# choco install/configuration
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
choco feature enable -n allowGlobalConfirmation
choco allow-empty-checksums
  
# sshd install/configuration
net stop sshd
taskkill /F /IM sshd.exe
choco install openssh -params "/SSHServerFeature" --force
  
wget "url_to_pub_key" -outfile $HOME\.ssh\authorized_keys
wget "url_to_sshd_config_file" -outfile "%PROGRAMDATA%\ssh\sshd_config"
  
Set-Service sshd -StartupType Automatic
Restart-Service -name sshd
  
Stop-Transcript

Script 5: Replaces mirrors

  • Cloud-config
#cloud-config
#This script replaces mirrors with mirrors.servers.com
#for VMs operating in gp-only mode
apt:
  preserve_sources_list: false
  primary:
    - arches: [default]
      uri: http://mirror.servers.com/debian
  security:
    - arches: [default]
      uri: http://mirror.servers.com/debian-security
  • Bash script
#!/bin/bash
 
#This script replaces mirrors with mirrors.servers.com
#for VMs operating in gp-only mode
# Backup the current sources list
cp /etc/apt/sources.list /etc/apt/sources.list.bak
 
# Replace the sources list with the new mirrors
cat < /etc/apt/sources.list
deb http://mirror.servers.com/debian $(lsb_release -cs) main
deb http://mirror.servers.com/debian-security $(lsb_release -cs)/updates main
EOF
 
# Update the package list
apt-get update

Script 6: Creates a directory and downloads files into it over the network

  • Cloud-config
#cloud-config
 
#Creates a directory
runcmd:
- mkdir -p /run/newdir
 
#Downloads files into it over the network
- [
    wget,
    "http://example.com",
    -O,
    /run/newdir/index.html
  ]
 
#Where
#http://example.com: The URL address of the file to be downloaded. 
#-O /run/newdir/index.html: Specifies the path
#and filename where the content will be saved.
  • Bash script
#!/bin/bash
 
# Creates a directory
mkdir -p /run/newdir
 
# Downloads a file into the created directory over the network
wget "http://example.com" -O /run/newdir/index.html

Script 7: Configures a new user with admin rights and sets up WinRM

  • Windows (Batch)
#Activates the administrator account
echo 'Enable Administrator user'
net user Administrator /active:yes
echo 'Creating %Usertname% user'
 
#Creates a new user and adds them to the administrators group:
net user %Usertname% %Password% /add
net localgroup Administrators %Usertname% /add
 
#Configures WinRM
echo 'Starting to configure winrm'
winrm quickconfig -q
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="300"}'
winrm set winrm/config '@{MaxTimeoutms="1800000"}'
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
winrm set winrm/config/service/auth '@{Basic="true"}'
echo 'Starting to configure firewall rules'
netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 action=allow
netsh advfirewall firewall add rule name="WinRM 5986" protocol=TCP dir=in localport=5986 action=allow
net stop winrm
cmd /c sc config winrm start=auto
net start winrm
echo "setting ExecutionPolicy"
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope LocalMachine -Force

Script 8: Changes the boot order

  • Cloud-config
#cloud-config
runcmd:
- efibootmgr -o $(efibootmgr | grep BootCurrent | cut -d' ' -f2),$(efibootmgr | grep BootOrder | cut -d' ' -f2 | cut -d',' -f1)
  • Bash script
#!/bin/sh
efibootmgr -o $(efibootmgr | grep BootCurrent | cut -d' ' -f2),$(efibootmgr | grep BootOrder | cut -d' ' -f2 | cut -d',' -f1)

Setting user data

In the Customer Portal, there is a User data field where you can enter the script.

After the automatic installation is complete, it will no longer be possible to change the text in this field. The maximum script size without Base64 encoding is 16 KB.

On this page