This guide walks through replacing a running Ubuntu installation on an OVH VPS with a fresh Arch Linux base system, using OVH's built-in Rescue Mode as the installation environment. No external ISO (not available for VPS) or boot image (again, arch it's not available for VPS) is used.
WARNING: This process will completely wipe your existing VPS disk. Back up all data, databases, configuration files, and SSH keys before proceeding.
Before wiping the VPS, you may want a full local copy of the current disk as a safety net. OVH allows you to create a snapshot via the control panel and download it as a QCOW2 image.
- Go to OVH Control Panel → Your VPS
- Create a snapshot from the control panel interface
- Once complete, OVH provides a direct download URL
- Download it to your local machine:
curl -o vps-snapshot.qcow2 "<OVH_SNAPSHOT_DOWNLOAD_URL>"OVH snapshots are in QCOW2 format. Convert to a raw image for mounting:
qemu-img convert -f qcow2 -O raw vps-snapshot.qcow2 vps.imgLoad the loop module if not already loaded:
sudo modprobe loopAttach the image as a loop device:
sudo losetup -fP vps.img
sudo losetup -l # confirm the assigned loop device, e.g. /dev/loop0Check the partition layout:
sudo fdisk -l /dev/loop0Mount the root partition (usually the largest one, e.g. p1 or p2):
sudo mkdir -p /mnt/vps
sudo mount /dev/loop0p1 /mnt/vps # adjust partition number as neededYou can now browse and extract files from the old system at /mnt/vps.
sudo umount /mnt/vps
sudo losetup -d /dev/loop0Run these commands on your currently running Ubuntu VPS before doing anything else. Record every value you will need them during the chroot configuration step and cannot retrieve them once the disk is wiped.
Network interface name:
ip -o link show | awk '$2 != "lo:" {print $2}' | tr -d ':'
# Example output: ens3
# Save as <YOUR_INTERFACE>Static IP address and prefix:
ip addr show | grep "inet " | grep -v "127.0.0.1" | awk '{print $2}'
# Example output: 15.204.86.133/32
# Save IP part as <YOUR_VPS_IP>, prefix as <YOUR_PREFIX> (usually /32 on OVH)Default gateway:
ip route show | grep default | awk '{print $3}'
# Example output: 15.204.86.1
# Save as <YOUR_GATEWAY_IP>DNS server:
resolvectl status 2>/dev/null | grep "DNS Servers" | awk '{print $3}' || \
grep nameserver /etc/resolv.conf | awk '{print $2}' | head -1
# Example output: 213.186.33.99
# Save as <YOUR_DNS_IP>Your SSH public key:
cat ~/.ssh/authorized_keys
# Save the full key string as <YOUR_SSH_PUBLIC_KEY>Your desired SSH port (pick a non-standard port, e.g. 25782):
# Decide on a value and save as <YOUR_SSH_PORT>Your admin username:
whoami
# Save as <YOUR_USERNAME>Your hostname:
hostname
# Save as <YOUR_HOSTNAME> (or choose a new one)Your timezone:
timedatectl | grep "Time zone" | awk '{print $3}'
# Example output: America/Sao_Paulo
# Save as <YOUR_TIMEZONE> (or use UTC for servers)Once collected, fill in this reference table before proceeding:
| Variable | Command to probe | Your value |
|---|---|---|
<YOUR_INTERFACE> |
ip -o link show |
e.g. ens3 |
<YOUR_VPS_IP> |
ip addr show |
e.g. 1.2.3.4 |
<YOUR_PREFIX> |
ip addr show |
e.g. /32 |
<YOUR_GATEWAY_IP> |
ip route show |
e.g. 1.2.3.1 |
<YOUR_DNS_IP> |
resolvectl status |
e.g. 213.186.33.99 |
<YOUR_SSH_PUBLIC_KEY> |
cat ~/.ssh/authorized_keys |
ssh-ed25519 AAA... |
<YOUR_SSH_PORT> |
your choice | e.g. 25782 |
<YOUR_USERNAME> |
whoami |
e.g. admin |
<YOUR_HOSTNAME> |
hostname |
e.g. myvps |
<YOUR_TIMEZONE> |
timedatectl |
e.g. UTC |
- Log in to the OVH Control Panel
- Navigate to Bare Metal Cloud VPS Your VPS
- Click the
...menu next to Boot and select Reboot in rescue mode - Confirm the reboot OVH will send the temporary root credentials to your account email
- Wait approximately 3 minutes, then SSH in using port 22:
ssh root@<YOUR_VPS_IP>lsblkThe VPS disk is typically /dev/sda or /dev/vda. The rescue environment boots from a separate smaller disk (usually /dev/sdb).
wipefs -af /dev/sdX
gdisk /dev/sdXInside gdisk:
ocreate new GPT table confirm withynpartition 1 Enter (default start)+1Mtypeef02(BIOS boot for GRUB)npartition 2 Enter Enter type8300(Linux filesystem)wwrite and exit confirm withy
Verify the result:
lsblk /dev/sdX
# Expected: sdX1 = 1M, sdX2 = remaindermkfs.ext4 /dev/sdX2mount /dev/sdX2 /mntDownload the official Arch Linux bootstrap tarball directly to the rescue environment:
cd /tmp
wget https://mirrors.kernel.org/archlinux/iso/latest/archlinux-bootstrap-x86_64.tar.zstExtract the bootstrap directly into the mounted root partition:
tar xf /tmp/archlinux-bootstrap-x86_64.tar.zst -C /mnt --strip-components=1The
--strip-components=1flag is required to extract contents ofroot.x86_64/directly into/mntrather than creating a subdirectory.
mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
mount --bind /dev /mnt/dev
mount --bind /dev/pts /mnt/dev/ptssed -i 's/^#Server/Server/' /mnt/etc/pacman.d/mirrorlistchroot /mnt /bin/bashecho "nameserver 8.8.8.8" > /etc/resolv.confpacman-key --init
pacman-key --populate archlinuxpacman -Sy base linux linux-firmware grub openssh sudo git curl wgetWhen prompted to choose an initramfs provider, select mkinitcpio (option 1).
OVH VPS instances use a /32 static IP with a gateway that is outside the subnet. This requires the GatewayOnLink=yes directive to be reachable.
Create the network configuration file:
cat > /etc/systemd/network/20-wired.network << 'EOF'
[Match]
Name=<YOUR_INTERFACE>
[Network]
Address=<YOUR_VPS_IP>/32
Gateway=<YOUR_GATEWAY_IP>
DNS=<YOUR_DNS_IP>
[Route]
Gateway=<YOUR_GATEWAY_IP>
GatewayOnLink=yes
EOFReplace:
<YOUR_INTERFACE>typicallyens3oreth0<YOUR_VPS_IP>your VPS static IP<YOUR_GATEWAY_IP>the gateway shown byip route show<YOUR_DNS_IP>the DNS server (OVH provides213.186.33.99for US/CA region)
Enable networking services:
systemctl enable systemd-networkd
systemctl enable systemd-resolvedImportant: After the system is running, set
/etc/resolv.confto use your DNS directly for best performance:echo "nameserver <YOUR_DNS_IP>" > /etc/resolv.confOVH's local DNS server resolves significantly faster than external DNS when queried from within OVH's network.
Important: Mask
systemd-networkd-wait-onlineto prevent a ~2 minute boot delay that blocks nginx and all other network-dependent services:systemctl mask systemd-networkd-wait-online
# Hostname
echo "<YOUR_HOSTNAME>" > /etc/hostname
# Timezone (UTC recommended for servers)
ln -sf /usr/share/zoneinfo/UTC /etc/localtime
# Locale
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf
# Root password
passwdConfigure SSH to prevent lockout after reboot:
cat > /etc/ssh/sshd_config << 'EOF'
Port <YOUR_SSH_PORT>
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
AuthorizedKeysFile .ssh/authorized_keys
Subsystem sftp /usr/lib/ssh/sftp-server
UseDNS no
EOFCreate your admin user and inject your SSH key:
useradd -m -G wheel -s /bin/bash <YOUR_USERNAME>
passwd <YOUR_USERNAME>
mkdir -p /home/<YOUR_USERNAME>/.ssh
echo "<YOUR_SSH_PUBLIC_KEY>" > /home/<YOUR_USERNAME>/.ssh/authorized_keys
chown -R <YOUR_USERNAME>:<YOUR_USERNAME> /home/<YOUR_USERNAME>/.ssh
chmod 700 /home/<YOUR_USERNAME>/.ssh
chmod 600 /home/<YOUR_USERNAME>/.ssh/authorized_keysEnable sudo for the wheel group:
echo "%wheel ALL=(ALL:ALL) ALL" >> /etc/sudoersEnable sshd:
systemctl enable sshdInstall GRUB to the disk (BIOS mode OVH VPS uses BIOS, not UEFI):
grub-install --target=i386-pc /dev/sdX
grub-mkconfig -o /boot/grub/grub.cfgexit
umount -R /mnt- Go back to OVH Control Panel > Boot
- Click
...and select Reboot my VPS - Reboot the VPS
Wait about 30 seconds, then connect using your configured SSH port:
ssh -p <YOUR_SSH_PORT> <YOUR_USERNAME>@<YOUR_VPS_IP>ip addr show
ping -c 3 archlinux.orgsystemd-resolved adds latency on OVH's network. Use OVH's regional DNS directly instead:
sudo rm /etc/resolv.conf
echo "nameserver <YOUR_DNS_IP>" | sudo tee /etc/resolv.conf
sudo chattr +i /etc/resolv.conf # prevent overwrites on rebootVerify response time:
curl -o /dev/null -s -w "DNS: %{time_namelookup}\nTotal: %{time_total}\n" https://archlinux.orgDNS lookup should be under 5ms from within OVH's network.
On OVH VPS with a static IP, systemd-networkd-wait-online serves no purpose and causes a ~2 minute boot delay that blocks all network-dependent services. Mask it permanently:
sudo systemctl mask systemd-networkd-wait-online
sudo systemctl daemon-reloadVerify boot time after next reboot:
systemd-analyze
# Expected: under 10 seconds totalRequired for OVH snapshots to flush disk buffers correctly and for graceful shutdowns from the control panel:
sudo pacman -S qemu-guest-agentThe service is socket-activated and does not need to be manually enabled.
yay is required for packages not available in the official Arch repositories:
sudo pacman -S --needed git base-devel
cd /tmp
git clone https://aur.archlinux.org/yay.git
cd yay
makepkg -siOn Arch Linux, the web server user is http, not www-data. Update ownership of all web files accordingly:
sudo chown -R http:http /var/www/Any application config files that reference www-data must be updated to http.
Use pacman for all official repository packages and yay for AUR packages:
sudo pacman -S <package> # official repos
yay -S <package> # AUR