---
title: 'User data на выделенном сервере'
sidebar_label: 'User data'
sidebar_position: 9
description: 'Как указать пользовательские параметры конфигурации при установке операционной системы автоустановкой, примеры user data'
toc_max_heading_level: 3
---

import Formbricks from '@theme/MDXComponents/Formbricks'
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import {TabItemLabel} from '@selectel/docux/components'
import CopyIcon from '@selectel/docux/icons/copy'

# User data на выделенном сервере

User data — пользовательские параметры конфигурации операционной системы сервера.
Описываются в виде скриптов в формате cloud-config (текстовые файлы с YAML-синтаксисом) или как bash-скрипт.
Скрипты автоматически кодируются в Base64, передаются на сервер и выполняются с помощью агента cloud-init при первом запуске операционной системы.
Использование user data помогает автоматизировать настройку серверов.

[Указать user data](#enter-user-data) можно на этапе установки операционной системы.

Подробнее о форматах скриптов cloud-config и bash в инструкции [User data formats](https://cloudinit.readthedocs.io/en/latest/explanation/format.html) документации cloud-init.

В скриптах можно передавать как отдельные параметры конфигурации операционной системы, так и целые последовательности параметров. Например:

* [установить часовой пояс](#configure-time-zone);
* [создать каталог и загрузить в него файлы](#create-directory);
* [обновить репозитории и установить пакеты](#update-repositories-and-packages);
* [разместить SSH-ключ на сервере](#create-and-place-ssh-key);
* [настроить файл конфигурации преобразователя доменных имен resolv.conf](#configure-configuration-file).

Посмотрите другие примеры в инструкции [Cloud config examples](https://cloudinit.readthedocs.io/en/latest/reference/examples.html#cloud-config-examples) документации cloud-init.

## Указать user data​ \{#enter-user-data}

Указать user data можно только при [автоустановке ОС](/dedicated/manage/autoinstall-os.mdx) на базе Linux.
Текст скрипта вводится в поле **User data**.

После завершения автоматической установки текст в поле **User data** изменить нельзя.

Максимальный размер скрипта с данными, которые не закодированы в Base64, — 16 КБ.

## Примеры user data \{#user-data-script-examples}

### Установить часовой пояс \{#configure-time-zone}

<Tabs queryString="configure-time-zone">
  <TabItem value="cloud-config" default>
    <TabItemLabel>
      Cloud-config
    </TabItemLabel>

    Пример скрипта для установки часового пояса Europe/Moscow:

    ```yaml
    #cloud-config

    timezone: Europe/Moscow
    ```
  </TabItem>

  <TabItem value="bash">
    <TabItemLabel>
      Bash-скрипт​
    </TabItemLabel>

    Пример скрипта для установки часового пояса Europe/Moscow:

    ```bash
    #!/bin/bash

    timedatectl set-timezone Europe/Moscow
    ```
  </TabItem>
</Tabs>

### Создать каталог и загрузить в него файлы \{#create-directory}

<Tabs queryString="create-directory">
  <TabItem value="cloud-config" default>
    <TabItemLabel>
      Cloud-config
    </TabItemLabel>

    Пример скрипта для создания каталога и загрузки в него файла по сети:

    ```yaml
    #cloud-config

    runcmd:
    - mkdir <directory>
    - [ wget, "<url>", -O, <directory>/<file_name> ]
    ```

    Укажите:

    * `<directory>` — каталог на сервере, например `/run/newdir`;
    * `<url>` — URL-адрес до файла, например `https://repo.local/static/page.html`;
    * `<file_name>` — имя файла, под которым загруженный файл будет сохранен в каталоге, например `index.html`.
  </TabItem>

  <TabItem value="bash">
    <TabItemLabel>
      Bash-скрипт​
    </TabItemLabel>

    Пример скрипта для создания каталога и загрузки в него файла по сети:

    ```bash
    #!/bin/bash
    mkdir <directory>
    wget <url> -O <directory>/<file_name>
    ```

    Укажите:

    * `<directory>` — каталог на сервере, например `/run/newdir`;
    * `<url>` — URL-адрес до файла, например `https://repo.local/static/page.html`;
    * `<file_name>` — имя файла, под которым загруженный файл будет сохранен в каталоге, например `index.html`.
  </TabItem>
</Tabs>

### Обновить репозитории и установить пакеты \{#update-repositories-and-packages}

<Tabs queryString="update-repositories-and-packages">
  <TabItem value="cloud-config" default>
    <TabItemLabel>
      Cloud-config
    </TabItemLabel>

    Пример скрипта для установки пакетов:

    * `pwgen` — утилита для генерации случайных паролей;
    * `pastebinit` — инструмент командной строки для публикации в онлайн-сервисах текстов, например выводов команд, логов и др., из терминала.

    ```yaml
    #cloud-config

    package_update: true
    packages:
    - pwgen
    - pastebinit
    ```
  </TabItem>

  <TabItem value="bash">
    <TabItemLabel>
      Bash-скрипт​
    </TabItemLabel>

    Пример скрипта для установки пакетов:

    * `pwgen` — утилита для генерации случайных паролей;
    * `pastebinit` — инструмент командной строки для публикации в онлайн-сервисах текстов из терминала, например выводов команд, логов и др.

    ```bash
    #!/bin/bash
    apt update
    apt install pwgen pastebinit
    ```
  </TabItem>
</Tabs>

### Разместить SSH-ключ на сервере \{#create-and-place-ssh-key}

<Tabs queryString="create-and-place-ssh-key">
  <TabItem value="cloud-config" default>
    <TabItemLabel>
      Cloud-config
    </TabItemLabel>

    Пример скрипта для размещения на сервере двух SSH-ключей.
    Ключ будет добавлен пользователю ОС, по умолчанию это пользователь `root`, в директорию `~/.ssh/authorized_keys`.

    ```yaml
    #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>
    ```

    Укажите:

    * `<ssh_key_user_1>` — публичный SSH-ключ первого пользователя, например `AAAAB3N…V7NZ`;
    * `<user_name_1>@<host_name_1>` — комментарий к SSH-ключу первого пользователя, где:
      * `<user_name_1>` — имя первого пользователя, который сгенерировал SSH-ключ;
      * `<host_name_1>` — имя устройства, на котором сгенерировали SSH-ключ;
    * `<ssh_key_user_2>` — публичный SSH-ключ второго пользователя, например `AAAAB3N…NtHw==`;
    * `<user_name_2>@<host_name_2>` — комментарий к SSH-ключу второго пользователя, где:
      * `<user_name_2>` — имя второго пользователя, который сгенерировал SSH-ключ;
      * `<host_name_2>` — имя устройства, на котором сгенерировали SSH-ключ.
  </TabItem>

  <TabItem value="bash">
    <TabItemLabel>
      Bash-скрипт​
    </TabItemLabel>

    Пример скрипта для размещения на сервере двух SSH-ключей.
    Ключ будет добавлен пользователю ОС, по умолчанию это пользователь `root`, в директорию `~/.ssh/authorized_keys`.

    ```bash
    #!/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
    ```

    Укажите:

    * `<ssh_key_user_1>` — публичный SSH-ключ первого пользователя, например `AAAAB3N…V7NZ`;
    * `<user_name_1>@<host_name_1>` — комментарий к SSH-ключу первого пользователя, где:
      * `<user_name_1>` — имя первого пользователя, который сгенерировал SSH-ключ;
      * `<host_name_1>` — имя устройства, на котором сгенерировали SSH-ключ;
    * `<ssh_key_user_2>` — публичный SSH-ключ второго пользователя, например `AAAAB3N…NtHw==`;
    * `<user_name_2>@<host_name_2>` — комментарий к SSH-ключу второго пользователя, где:
      * `<user_name_2>` — имя второго пользователя, который сгенерировал SSH-ключ;
      * `<host_name_2>` — имя устройства, на котором сгенерировали SSH-ключ.
  </TabItem>
</Tabs>

### Настроить файл конфигурации \{#configure-configuration-file}

<Tabs queryString="configure-configuration-file">
  <TabItem value="cloud-config" default>
    <TabItemLabel>
      Cloud-config
    </TabItemLabel>

    Пример скрипта для преобразователя доменных имен `resolv.conf`:

    ```yaml
    #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
    ```

    Укажите:

    * `<dns_server_ip_address_1>`, `<dns_server_ip_address_2>` — IP-адреса DNS-серверов, к которым будет обращаться система для разрешения доменных имен, например `4.4.4.4` и `8.8.8.8`;
    * `<searchdomain_1>`, `<searchdomain_2>` — домены, которые будут добавляться к коротким (неполным) именам хостов при обращении к ним;
    * `<domain>` — (legacy) основной DNS-домен, который будет добавляться к коротким (неполным) именам хостов при обращении к ним.
  </TabItem>

  <TabItem value="bash">
    <TabItemLabel>
      Bash-скрипт​
    </TabItemLabel>

    Пример скрипта для преобразователя доменных имен `resolv.conf`:

    ```bash
    #!/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
    ```

    Укажите:

    * `<domain>` — (legacy) основной DNS-домен, который будет добавляться к коротким (неполным) именам хостов при обращении к ним;
    * `<dns_server_ip_address_1>`, `<dns_server_ip_address_2>` — IP-адреса DNS-серверов, к которым будет обращаться система для разрешения доменных имен, например `4.4.4.4` и `8.8.8.8`;
    * `<searchdomain_1>`, `<searchdomain_2>` — домены, которые будут добавляться к коротким (неполным) именам хостов при обращении к ним.
  </TabItem>
</Tabs>

### Отключить доступ в интернет \{#disable-internet-access}

<Tabs queryString="disable-internet-access">
  <TabItem value="bash" default>
    <TabItemLabel>
      Bash-скрипт
    </TabItemLabel>

    Пример скрипта для выключения сетевого интерфейса с публичным IPv4-адресом:

    ```bash
    #!/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
    ```
  </TabItem>

  <TabItem value="python">
    <TabItemLabel>
      Python-скрипт​
    </TabItemLabel>

    Пример скрипта для выключения сетевого интерфейса с публичным IPv4-адресом:

    ```python
    #!/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.')
    ```
  </TabItem>
</Tabs>

### Настроить конфигурации контейнеров для установки ОС с приложением Containers Ready \{#containers-ready}

При установке [ОС с приложением Containers Ready](/dedicated/manage-applications/containers-ready.mdx) вы можете с помощью скрипта в поле **User data** настроить конфигурации контейнеров.
Чтобы открывать панель Portainer по домену, нужно в поле **User data** вставить скрипт:

```bash
#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>"
```

Укажите:

* `<containers>` — содержимое файла Docker Compose для файла `docker-compose.yaml`.
  Подробнее в инструкции [docker compose](https://docs.docker.com/reference/cli/docker/compose/#examples) документации Docker;
* `<environment_variables>` — переменные окружения для файла `.env`.
  Если файл не нужен, удалите блок кода.
  Подробнее в инструкции [Use environment variables](https://docs.docker.com/compose/how-tos/environment-variables/) документации Docker;
* в блоке кода `content:` для файла `/opt/user-values.yaml` укажите параметры конфигурации для Portainer:

  * `portainer_use_le: true` — параметр для автоматического выпуска TLS(SSL)-сертификата от Let’s Encrypt®;
  * `<example.com>` — домен для доступа к Portainer.
    Чтобы домен открывался по публичному IP-адресу сервера, в панели управления своего DNS-хостинга добавьте А-запись и укажите в значении записи публичный IP-адрес сервера.
    IP-адрес можно скопировать в [панели управления](https://my.selectel.ru/servers/): в верхнем меню нажмите **Продукты** → **Выделенные серверы** → страница сервера → вкладка **Операционная система** → в поле **IP** нажмите <CopyIcon />.
    Если домен делегирован в [DNS-хостинг Selectel (actual)](/dns-hosting/), используйте инструкцию [Добавить ресурсную запись](/dns-hosting/records/add-record.mdx).
    После установки ОС для домена автоматически выпустится TLS(SSL)-сертификат от Let’s Encrypt®.
    При ошибке выпуска TLS(SSL)-сертификата панель Portainer будет доступна по IP-адресу сервера;
  * `<root@example.com>` — электронная почта администратора Containers Ready для создания аккаунта и получения уведомлений Let’s Encrypt®.

  <Formbricks />
