User data on a dedicated server
User data - user configuration parameters of the server operating system. They are described as scripts in cloud-config format (text files with YAML syntax) or as a bash script. The scripts are automatically Base64 encoded, transferred to the server, and executed by the cloud-init agent when the operating system is first started. The use of user data helps automate server configuration.
You can specify user data can be specified during the installation phase of the operating system.
Learn more about cloud-config and bash script formats in the User data formats instruction of the cloud-init documentation.
In scripts, you can pass both individual operating system configuration parameters and entire sequences of parameters. For example:
- set the time zone;
- create a directory and upload files to it;
- update repositories and install packages;
- place the SSH key on the server;
- configure the domain name resolver configuration file resolv.conf.
See more examples in the Cloud config examples documentation cloud-init instructions.
Specify user data
The user data can only be specified during Linux-based OS auto-installation. The script text is entered in the User data field.
After the automatic installation is complete, the text in the User data field cannot be changed.
The maximum size of a script with data that is not Base64 encoded is 16 KB.
Examples of user data
Set time zone
Cloud-config
Bash script
An example script for setting the Europe/Moscow time zone:
#cloud-config
timezone: Europe/Moscow
An example script for setting the Europe/Moscow time zone:
#!/bin/bash
timedatectl set-timezone Europe/Moscow
Create a directory and upload files to it
Cloud-config
Bash script
An example script to create a directory and upload a file to it over the network:
#cloud-config
runcmd:
- mkdir <directory>
- [ wget, "<url>", -O, <directory>/<file_name> ]
Specify:
<directory>- directory on the server, e.g./run/newdir;<url>- URL to the file, e.g.https://repo.local/static/page.html;<file_name>- file name under which the uploaded file will be saved in the directory, e.g.index.html.
An example script to create a directory and upload a file to it over the network:
#!/bin/bash
mkdir <directory>
wget <url> -O <directory>/<file_name>
Specify:
<directory>- directory on the server, e.g./run/newdir;<url>- URL to the file, e.g.https://repo.local/static/page.html;<file_name>- file name under which the uploaded file will be saved in the directory, e.g.index.html.
Update repositories and install packages
Cloud-config
Bash script
An example script for installing packages:
pwgen- A utility for generating random passwords;pastebinit- a command-line tool for publishing texts, such as command outputs, logs, etc., from the terminal to online services.
#cloud-config
package_update: true
packages:
- pwgen
- pastebinit
An example script for installing packages:
pwgen- A utility for generating random passwords;pastebinit- a command-line tool for publishing terminal texts, such as command outputs, logs, etc., to online services.
#!/bin/bash
apt update
apt install pwgen pastebinit
Place the SSH key on the server
Cloud-config
Bash script
An example script to place two SSH keys on the server. The key will be added to the OS user, by default the root user, in the ~/.ssh/authorized_keys directory .
#cloud-config
ssh_authorized_keys:
- ssh-rsa <ssh_key_user_1> <user_name_1>@<host_name_1>
- ssh-rsa <ssh_key_user_2> <user_name_2>@<host_name_2>
Specify:
<ssh_key_user_1>- public SSH key of the first user, e.g.AAAAB3N…V7NZ;<user_name_1>@<host_name_1>- comment to the SSH key of the first user, where:<user_name_1>- the name of the first user who generated the SSH key;<host_name_1>- the name of the device on which the SSH key was generated;
<ssh_key_user_2>- public SSH key of the second user, e.g.AAAAB3N…NtHw==;<user_name_2>@<host_name_2>- comment on the SSH key of the second user, where:<user_name_2>- the name of the second user who generated the SSH key;<host_name_2>- the name of the device on which the SSH key was generated.
An example script to place two SSH keys on the server. The key will be added to the OS user, by default the root user, in the ~/.ssh/authorized_keys directory .
#!/bin/bash
echo "ssh-rsa <ssh_key_user_1> <user_name_1>@<host_name_1>" >> /root/.ssh/authorized_keys
echo "ssh-rsa <ssh_key_user_2> <user_name_2>@<host_name_2>" >> /root/.ssh/authorized_keys
Specify:
<ssh_key_user_1>- public SSH key of the first user, e.g.AAAAB3N…V7NZ;<user_name_1>@<host_name_1>- comment to the SSH key of the first user, where:<user_name_1>- the name of the first user who generated the SSH key;<host_name_1>- the name of the device on which the SSH key was generated;
<ssh_key_user_2>- public SSH key of the second user, e.g.AAAAB3N…NtHw==;<user_name_2>@<host_name_2>- comment on the SSH key of the second user, where:<user_name_2>- the name of the second user who generated the SSH key;<host_name_2>- the name of the device on which the SSH key was generated.
Customize the configuration file
Cloud-config
Bash script
Sample script for the resolv.conf domain name resolver:
#cloud-config
manage_resolv_conf: true
resolv_conf:
nameservers: ['<dns_server_ip_address_1>', '<dns_server_ip_address_2>']
searchdomains:
- <searchdomain_1>
- <searchdomain_2>
domain: <domain>
options:
rotate: true
timeout: 1
Specify:
<dns_server_ip_address_1>,<dns_server_ip_address_2>- IP addresses of DNS servers that the system will contact to resolve domain names, e.g.4.4.4.4and8.8.8.8;<searchdomain_1>,<searchdomain_2>- domains that will be appended to short (incomplete) hostnames when they are accessed;<domain>- (legacy) primary DNS domain, which will be appended to short (incomplete) hostnames when they are accessed.
Sample script for the resolv.conf domain name resolver:
#!/bin/bash
cat <<EOF > /etc/resolv.conf
domain <domain>
nameserver <dns_server_ip_address_1>
nameserver <dns_server_ip_address_2>
search <searchdomain_1> <searchdomain_2>
options rotate
options timeout:1
EOF
Specify:
<domain>- (legacy) primary DNS domain, which will be appended to short (incomplete) hostnames when they are accessed;<dns_server_ip_address_1>,<dns_server_ip_address_2>- IP addresses of DNS servers that the system will contact to resolve domain names, e.g.4.4.4.4and8.8.8.8;<searchdomain_1>,<searchdomain_2>- domains that will be appended to short (incomplete) hostnames when they are accessed.
Disable internet access
Bash script
Python script
Example script to shut down a network interface with a public IPv4 address:
#!/bin/bash
ip addr show
public_interface=$(ip -4 addr show | awk '/inet/ && !/127.0.0.1/ && !/10\./ && !/172\.(1[6-9]|2[0-9]|3[0-1])\./ && !/192\.168\./ {print $NF}')
if [ -n "$public_interface" ]; then
ip link set down dev "$public_interface"
else
echo "Public interface not found."
fi
Example script to shut down a network interface with a public IPv4 address:
#!/usr/bin/env python3
import subprocess
import re
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def disable_public_interface():
logging.info('Starting disable_public_interface function.')
output = subprocess.check_output('ip -4 addr show', shell=True).decode('utf-8')
interfaces = re.findall(r'^\d+: (\S+):.*?\n(?:.*\n)*?\s+inet (\d+\.\d+\.\d+\.\d+)/\d+', output, re.MULTILINE)
public_interfaces = []
for iface, ip in interfaces:
if iface == 'lo':
continue
if re.match(r'^(127\.|10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.)', ip):
continue
public_interfaces.append(iface)
for interface in public_interfaces:
command = ['ip', 'link', 'set', 'dev', interface, 'down']
try:
subprocess.run(command, check=True)
logging.info(f'Successfully disabled interface: {interface}')
except subprocess.CalledProcessError as e:
logging.error(f'Failed to disable interface: {interface}, error: {e}')
if __name__ == "__main__":
logging.info('Script started.')
disable_public_interface()
logging.info('Script finished.')
Configure container configurations for OS installation with the Containers Ready application
When installing an OS with Containers Ready, you can use a script in the User data field to customize container configurations. To open the Portainer panel by domain, you must insert a script in the User data field:
#cloud-config
write_files:
- path: "/opt/containers/docker-compose.yaml"
permissions: "0644"
content: |
version: "3.9"
services:
<containers>
- path: "/opt/containers/.env"
permissions: "0644"
content: |
<environment_variables>
- path: "/opt/user-values.yaml"
permissions: "0644"
content: |
portainer_use_le: true
portainer_domain: "<example.com>"
portainer_le_email: "<root@example.com>"
Specify:
-
<containers>- Docker Compose file contents for the filedocker-compose.yaml. Read more in the instructions docker compose of the Docker documentation; -
<environment_variables>- environment variables for the file.env. If the file is not needed, delete the code block. See the instructions for more details Use environment variables of the Docker documentation; -
in the
content:code block for the/opt/user-values.yamlfile, specify the configuration parameters for Portainer:portainer_use_le: true- parameter to automatically issue a TLS(SSL) certificate from Let's Encrypt®;<example.com>- domain to access Portainer. To have the domain opened by the public IP address of the server, add an A record in the control panel of your DNS hosting and specify the public IP address of the server in the record value. The IP address can be copied in the control panel: in the top menu, click Products → Dedicated Servers → Server page → tab Operating System → in the field IP click . If the domain is delegated to Selectel DNS hosting (actual), use the instructions Add a resource record. After the OS is installed, a TLS(SSL) certificate from Let's Encrypt® will be automatically issued for the domain. If the TLS(SSL) certificate issuance fails, the Portainer panel will be accessible by the server IP address;<root@example.com>- Containers Ready administrator email to create an account and receive Let's Encrypt® notifications.