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

# Secure your Linux VPS

> Harden your FlashRDP Linux VPS: install updates, add a sudo user, sign in with SSH keys, turn off password logins and turn on a firewall.

A Linux VPS with a public IP address gets automated SSH password-guessing from the moment it boots. You have full `root` access, so securing the server is up to you. Do these steps right after your first sign-in:

1. Install all updates.
2. Create a user with `sudo` rights.
3. Sign in with an SSH key.
4. Turn off password and root logins over SSH.
5. Turn on a firewall that allows SSH.
6. Install security updates automatically.
7. Check which services listen on the network.

Commands are shown for the `root` account. From a sudo user, put `sudo` in front of them. Replace `alice` with your own username. FreeBSD uses different tools, so these commands don't apply to it.

<Warning>
  A mistake in the SSH or firewall steps can lock you out. Keep the server's page in the [Billing Portal](https://new.flashrdp.com/servers) open: the [Console](/docs/control-panel/server-panel#browser-console) button gives you the server's screen and keyboard in your browser, even when SSH is blocked. Sign in there as `root` with its password to undo a change. If you don't know the root password, use **Reset password** first; the server must be running.
</Warning>

## Update the system

<Tabs>
  <Tab title="Ubuntu and Debian">
    ```bash theme={null}
    apt update && apt upgrade
    ```
  </Tab>

  <Tab title="AlmaLinux, Rocky, Oracle, CentOS Stream, Fedora">
    ```bash theme={null}
    dnf upgrade --refresh
    ```
  </Tab>

  <Tab title="openSUSE">
    ```bash theme={null}
    zypper refresh && zypper update
    ```
  </Tab>

  <Tab title="Arch Linux">
    ```bash theme={null}
    pacman -Syu
    ```

    If the upgrade stops with signature errors, update the keyring first with `pacman -Sy archlinux-keyring`, then run `pacman -Su`.
  </Tab>

  <Tab title="Alpine Linux">
    ```bash theme={null}
    apk update && apk upgrade
    ```
  </Tab>
</Tabs>

If a new kernel was installed, restart the server with `reboot`.

## Create a sudo user

Use your own account for daily work and keep `root` for recovery.

<Tabs>
  <Tab title="Ubuntu and Debian">
    ```bash theme={null}
    apt install sudo
    adduser alice
    usermod -aG sudo alice
    ```

    `adduser` asks for a password for the new user.
  </Tab>

  <Tab title="AlmaLinux, Rocky, Oracle, CentOS Stream, Fedora">
    ```bash theme={null}
    dnf install sudo
    useradd -m alice
    passwd alice
    usermod -aG wheel alice
    ```
  </Tab>

  <Tab title="openSUSE">
    By default, `sudo` on openSUSE asks for the `root` password. This lets members of the `wheel` group use their own password:

    ```bash theme={null}
    useradd -m alice
    passwd alice
    groupadd -f wheel
    usermod -aG wheel alice
    printf 'Defaults:%%wheel !targetpw\n%%wheel ALL=(ALL:ALL) ALL\n' > /etc/sudoers.d/wheel
    chmod 440 /etc/sudoers.d/wheel
    visudo -c
    ```
  </Tab>

  <Tab title="Arch Linux">
    ```bash theme={null}
    pacman -S sudo
    useradd -m -G wheel alice
    passwd alice
    echo '%wheel ALL=(ALL:ALL) ALL' > /etc/sudoers.d/wheel
    chmod 440 /etc/sudoers.d/wheel
    visudo -c
    ```
  </Tab>

  <Tab title="Alpine Linux">
    ```bash theme={null}
    apk add sudo
    adduser alice
    addgroup alice wheel
    echo '%wheel ALL=(ALL:ALL) ALL' > /etc/sudoers.d/wheel
    chmod 440 /etc/sudoers.d/wheel
    visudo -c
    ```

    `adduser` asks for a password for the new user.
  </Tab>
</Tabs>

Check that it works. This asks for `alice`'s password and should print `root`:

```bash theme={null}
su - alice -c 'sudo whoami'
```

## Sign in with an SSH key

If you don't use a key yet, create one and add it to the server: see [Sign in with an SSH key](/docs/linux-vps/ssh-access#sign-in-with-an-ssh-key). For future installs, save it on the [SSH keys](/docs/control-panel/ssh-keys) page of the Billing Portal.

Keys added in the Billing Portal or with `ssh-copy-id root@YOUR_IP` belong to `root`. To use the same keys for your new user, run as `root`:

```bash theme={null}
mkdir -p /home/alice/.ssh
cp /root/.ssh/authorized_keys /home/alice/.ssh/
chown -R alice /home/alice/.ssh
chmod 700 /home/alice/.ssh
chmod 600 /home/alice/.ssh/authorized_keys
```

On AlmaLinux, Rocky Linux, Oracle Linux, CentOS Stream and Fedora, also run `restorecon -R /home/alice/.ssh` so SELinux lets SSH read the file.

From your computer, check that `ssh alice@YOUR_IP` signs you in without a password.

## Turn off password and root login

Once your key works, stop SSH from accepting passwords. Bots can then no longer guess their way in.

<Warning>
  Keep your current SSH session open until you have tested a new one. Restarting SSH doesn't close existing sessions, so you can still undo a mistake. If you do get locked out, use the **Console** in the Billing Portal.
</Warning>

<Steps>
  <Step title="Choose where to put the settings">
    Run:

    ```bash theme={null}
    grep -i '^Include' /etc/ssh/sshd_config
    ```

    If it prints a line with `/etc/ssh/sshd_config.d/*.conf`, create a settings file that is read before the others:

    ```bash theme={null}
    printf 'PermitRootLogin prohibit-password\nPasswordAuthentication no\n' > /etc/ssh/sshd_config.d/00-hardening.conf
    ```

    If it prints nothing, open `/etc/ssh/sshd_config` in an editor and set `PermitRootLogin prohibit-password` and `PasswordAuthentication no`. Change the existing lines instead of adding second copies: SSH uses the first value it reads.

    `prohibit-password` still lets `root` sign in with a key. If you sign in as your sudo user, use `PermitRootLogin no` to block `root` over SSH entirely.
  </Step>

  <Step title="Check the configuration">
    ```bash theme={null}
    sshd -t
    sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|challengeresponseauthentication)'
    ```

    `sshd -t` prints nothing when the configuration is valid. The second command should show `passwordauthentication no`. If `kbdinteractiveauthentication` or `challengeresponseauthentication` shows `yes`, set it to `no` the same way, because it can also accept passwords.
  </Step>

  <Step title="Restart SSH">
    <Tabs>
      <Tab title="Ubuntu and Debian">
        ```bash theme={null}
        systemctl restart ssh
        ```
      </Tab>

      <Tab title="Other distributions">
        ```bash theme={null}
        systemctl restart sshd
        ```
      </Tab>

      <Tab title="Alpine Linux">
        ```bash theme={null}
        rc-service sshd restart
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Test in a new terminal">
    Without closing your current session, open a new terminal on your computer and check that your key still works:

    ```bash theme={null}
    ssh alice@YOUR_IP
    ```

    Then check that passwords are refused:

    ```bash theme={null}
    ssh -o PubkeyAuthentication=no root@YOUR_IP
    ```

    This should end with `Permission denied (publickey)`. If it asks for a password, password login is still on: go back to the second step.
  </Step>
</Steps>

<Note>
  **Reset password** in the Billing Portal still sets the `root` password. With password login off, that password works in the **Console**, not over SSH.
</Note>

## Turn on a firewall

Allow SSH before you turn the firewall on. If you moved SSH to another port, allow that port instead of `22`.

<Tabs>
  <Tab title="Ubuntu and Debian">
    ```bash theme={null}
    apt install ufw
    ufw allow 22/tcp
    ufw enable
    ufw status verbose
    ```

    Open more ports as you need them, for example `ufw allow 443/tcp` for a website.
  </Tab>

  <Tab title="AlmaLinux, Rocky, Oracle, CentOS Stream, Fedora">
    ```bash theme={null}
    dnf install firewalld
    systemctl enable --now firewalld
    firewall-cmd --permanent --add-service=ssh
    firewall-cmd --reload
    firewall-cmd --list-services
    ```

    The default zone already allows SSH; the `--add-service` command makes sure. Open more ports with, for example, `firewall-cmd --permanent --add-service=https` followed by `firewall-cmd --reload`.
  </Tab>

  <Tab title="openSUSE">
    ```bash theme={null}
    zypper install firewalld
    systemctl enable --now firewalld
    firewall-cmd --permanent --add-service=ssh
    firewall-cmd --reload
    firewall-cmd --list-services
    ```
  </Tab>

  <Tab title="Arch Linux">
    ```bash theme={null}
    pacman -S ufw
    ufw allow 22/tcp
    ufw enable
    systemctl enable --now ufw
    ufw status verbose
    ```
  </Tab>

  <Tab title="Alpine Linux">
    Alpine's `nftables` package comes with a ruleset in `/etc/nftables.nft` that drops incoming connections, including SSH, so add an SSH rule before you start it.

    <Steps>
      <Step title="Install nftables">
        ```bash theme={null}
        apk add nftables
        ```
      </Step>

      <Step title="Allow SSH">
        Open `/etc/nftables.nft` with `vi`. In the `input` chain, add this line after the rule that accepts established connections:

        ```text theme={null}
        tcp dport 22 accept
        ```
      </Step>

      <Step title="Check and start the firewall">
        ```bash theme={null}
        nft -c -f /etc/nftables.nft
        rc-service nftables start
        rc-update add nftables
        ```

        `nft -c` checks the file without loading it and prints nothing when it is valid.
      </Step>
    </Steps>
  </Tab>
</Tabs>

## Block repeated sign-in attempts (optional)

Once password login is off, password-guessing can't succeed, so this is optional. If you want to block addresses that keep trying, install `fail2ban` from your distribution's packages (on AlmaLinux, Rocky Linux and Oracle Linux it comes from the EPEL repository) and turn on its `sshd` jail. See the [fail2ban project](https://github.com/fail2ban/fail2ban) for setup.

## Install security updates automatically

<Tabs>
  <Tab title="Ubuntu and Debian">
    ```bash theme={null}
    apt install unattended-upgrades
    dpkg-reconfigure -plow unattended-upgrades
    ```

    Answer **Yes**. By default it installs security updates only.
  </Tab>

  <Tab title="AlmaLinux, Rocky, Oracle, CentOS Stream, Fedora">
    ```bash theme={null}
    dnf install dnf-automatic
    ```

    In `/etc/dnf/automatic.conf`, under `[commands]`, set:

    ```ini theme={null}
    upgrade_type = security
    apply_updates = yes
    ```

    Then turn on the timer:

    ```bash theme={null}
    systemctl enable --now dnf-automatic.timer
    ```

    On Fedora 41 and later, install `dnf5-plugin-automatic` instead, put the same two settings under `[commands]` in `/etc/dnf/automatic.conf`, and run `systemctl enable --now dnf5-automatic.timer`.
  </Tab>

  <Tab title="openSUSE, Arch, Alpine">
    Update by hand on a regular schedule with the commands under [Update the system](#update-the-system). On Arch Linux, read the news on [archlinux.org](https://archlinux.org) before you upgrade.
  </Tab>
</Tabs>

## Check what is listening

List every service that accepts network connections:

```bash theme={null}
ss -tulpn
```

On Alpine Linux, use `netstat -tulpn`. Services bound to `0.0.0.0`, `[::]` or `*` accept connections from the internet unless the firewall blocks them; `127.0.0.1` and `[::1]` are local only. Stop anything you don't need, for example `systemctl disable --now SERVICE`, or on Alpine `rc-service SERVICE stop` and `rc-update del SERVICE`.

<Note>
  Outgoing port 25 (SMTP) is blocked by default. To send email directly from your server, [open a ticket](https://new.flashrdp.com/support/new) with a business justification.
</Note>

## Related Articles

<CardGroup cols={2}>
  <Card horizontal title="Connect to your Linux VPS via SSH" icon="terminal" href="/docs/linux-vps/ssh-access" />

  <Card horizontal title="Manage SSH keys" icon="key" href="/docs/control-panel/ssh-keys" />

  <Card horizontal title="Reset server password" icon="key-round" href="/docs/control-panel/reset-server-password" />

  <Card horizontal title="Supported Linux distributions" icon="layers" href="/docs/linux-vps/distributions" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.