> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gcore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Customize the initial setup for a Virtual Machine

> Configure a Virtual Machine initial setup with cloud-init user data for passwords, users, SSH keys, and first boot scripts.

### Set a password

By default, password-based SSH authentication is disabled on Gcore Virtual Machines — only SSH key authentication is enabled. Set `ssh_pwauth: true` to allow password access.

```yaml theme={null}
#cloud-config
password: your_password
chpasswd: { expire: false }
ssh_pwauth: true
power_state:
  mode: reboot
  timeout: 30
  condition: true
```

* `password` — sets the password for the default OS user (e.g. `ubuntu` on Ubuntu images).
* `chpasswd: { expire: false }` — keeps the password active without requiring a change on first login.
* `ssh_pwauth: true` — enables password-based SSH authentication.
* `power_state` — reboots the VM after cloud-init finishes so the changes take effect.

After the VM is ready, connect with:

```bash theme={null}
ssh your_default_username@your_instance_ip_address
```

### Create a user

Add a `users` block to create a new OS user at boot. The example below creates a `guest` user with sudo access.

```yaml theme={null}
#cloud-config
users:
  - name:         guest
    sudo:         ALL=(ALL) NOPASSWD:ALL
    passwd:       SHA-512_encrypted_value_of_guest_password
    groups:       users,admin
    lock_passwd:  false
    shell:        /bin/bash
power_state:
  mode: reboot
  timeout: 30
  condition: true
```

* `sudo: ALL=(ALL) NOPASSWD:ALL` — grants the user passwordless sudo rights.
* `passwd` — SHA-512 encrypted password. Generate it with `mkpasswd -m sha512crypt guest`.
* `groups` — comma-separated list of groups. The groups must already exist on the system.
* `lock_passwd: false` — allows password-based login.
* `shell: /bin/bash` — sets the default shell.

> [!NOTE]
>
> Run `groups` after connecting to verify group membership.

### Enable root user

Set `disable_root: false` to allow the root user to log in with SSH.

```yaml theme={null}
#cloud-config
disable_root: false
```

### Configure user groups

Add the `groups` directive to create custom groups at boot.

```yaml theme={null}
#cloud-config
groups:
  - regular-users
power_state:
  mode: reboot
  timeout: 30
  condition: true
```

After the VM is ready, run `compgen -g` to verify the group appears.

### Add an SSH key

Add public SSH keys from other machines using `ssh_authorized_keys`.

```yaml theme={null}
#cloud-config
ssh_authorized_keys:
  - ssh-rsa <YOUR_PUBLIC_KEY> user@host
```

After the VM starts, verify with `cat ~/.ssh/authorized_keys`.

### Add repositories and install packages

Install packages at first boot using the `packages` directive. Packages from external repositories require an `apt.sources` entry.

> [!NOTE]
>
> The example below uses `apt` and applies to Debian-based distributions (Ubuntu, Debian). For RPM-based distributions (CentOS, Rocky Linux, Fedora), use the `yum_repos` directive and replace `packages` entries with the corresponding package names.

```yaml theme={null}
#cloud-config
apt:
  sources:
    docker.list:
      source: deb [arch=amd64] https://download.docker.com/linux/ubuntu $RELEASE stable
      keyid: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88
package_update: true
package_upgrade: true
packages:
  - apt-transport-https
  - ca-certificates
  - gnupg-agent
  - software-properties-common
  - gnupg
  - docker-ce
  - docker-ce-cli
  - nmap
  - traceroute
power_state:
  mode: reboot
  timeout: 30
  condition: true
```

### Write files

Create files on the VM at boot using the `write_files` directive.

```yaml theme={null}
#cloud-config
write_files:
  - path: /root/useful-docker-script.sh
    permissions: '0644'
    content: |
      #!/bin/bash
      docker build -t dockerhub-username/docker-image-name .
      docker login
      docker push dockerhub-username/docker-image-name
```

### Configure network interfaces

Add a static IP address by writing a Netplan configuration file. Cloud-init merges it with the auto-generated `50-cloud-init.yaml` during boot.

> [!NOTE]
>
> Netplan applies to Ubuntu. For other distributions, write the appropriate network configuration file for the system's network manager (for example, NetworkManager connection files on Rocky Linux or CentOS).

```yaml theme={null}
#cloud-config
write_files:
  - content: |
      network:
          version: 2
          renderer: networkd
          ethernets:
            enp3s0:
              addresses:
              - 192.170.1.25/24
              - 2020:1::1/64
              nameservers:
                addresses:
                - 8.8.8.8
                - 8.8.4.4
    path: /etc/netplan/00-add-static-ip.yaml
    permissions: '0644'
power_state:
  mode: reboot
  timeout: 30
  condition: true
```

After the VM reboots, run `ip a` to verify the static addresses appear on the `enp3s0` interface.

## Check cloud-init logs

Two log files are available on the VM for diagnosing cloud-init issues.

**`/var/log/cloud-init.log`** — full process log with debug output:

```bash theme={null}
cat /var/log/cloud-init.log
```

**`/var/log/cloud-init-output.log`** — stdout/stderr from scripts cloud-init ran:

```bash theme={null}
cat /var/log/cloud-init-output.log
```
