IPv4 & IPv6 Leasing - Any RIR, Any LocationOrder Now
Hostperl

Managed Hosting Migration on AlmaLinux for Agencies

By Raman Kumar

Share:

Updated on Sep 14, 2026

Managed Hosting Migration on AlmaLinux for Agencies

What this managed hosting migration solves

Use this guide when you need to move a managed hosting account, application, or client site onto a fresh AlmaLinux 9 server without rushing into lockouts or broken services. You will create a non-root admin, confirm the operating system, prepare the firewall, move files safely, and verify the cutover before you retire the old host. If you are planning agency work or client migrations, a Hostperl managed VPS is a practical place to stage the destination before production traffic moves.

This tutorial stays on AlmaLinux because it covers the RHEL-compatible path that is easiest to miss in mixed hosting environments. The same approach also fits many managed server moves where support teams need a clean handoff, stable SSH access, and a rollback path if DNS or application checks fail.

Before you begin on the new server

You should have root SSH access to the destination AlmaLinux server, the source server details, and a maintenance window. Keep the source server online until the final checks pass.

On your local computer, connect to the new server first:

ssh root@203.0.113.10

Replace 203.0.113.10 with the public IP assigned to your server. If your provider uses a non-root SSH account, connect with that account instead, but keep the same documentation IP example while you follow along.

Once connected, detect the operating system:

cat /etc/os-release

On AlmaLinux 9, you should see AlmaLinux in the output. If you are on a different distribution, stop here and use the matching Hostperl procedure for that platform. This tutorial is written for AlmaLinux because the firewall, SELinux, and package flow differ from Debian-family servers.

Create a non-root admin and keep root open

Do not disable root SSH until a second terminal proves the new account works. On AlmaLinux, create a sudo-capable admin named deploy, then install your SSH key.

On the VPS as root, run:

dnf -y update
useradd -m -G wheel deploy
passwd deploy
install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
cat /root/.ssh/authorized_keys > /home/deploy/.ssh/authorized_keys
chown deploy:deploy /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys

This updates the server, creates the deploy account, sets a password if you need one for console recovery, and copies the existing root key so you can log in as the new user. Replace the key-copy step with your own public key if you do not want to reuse the root key.

Open a second terminal on your local computer and test the login:

ssh deploy@203.0.113.10

After login, confirm sudo works:

sudo -v
whoami
pwd

You should see deploy from whoami, and sudo should not prompt for an error. Keep the original root session open until this works.

Prepare storage, time sync, and basic services

Managed hosting migrations fail more often because of filesystem surprises than because of application code. Check space, time sync, and service state before you transfer data.

On the VPS as the non-root sudo user:

sudo dnf -y install chrony rsync firewalld policycoreutils-python-utils
sudo systemctl enable --now chronyd
sudo systemctl enable --now firewalld
sudo timedatectl set-ntp true
df -hT
systemctl status chronyd --no-pager
systemctl status firewalld --no-pager

These commands install the tools needed for synchronization, copying, and SELinux adjustments. You want chronyd active, firewalld running, and enough free disk space for the incoming data.

Open SSH and web ports safely on AlmaLinux

Before changing SSH or closing anything down, make sure the new rules are in place. On AlmaLinux with firewalld, add SSH and your web port first.

On the VPS as the non-root sudo user:

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

You should see SSH, HTTP, and HTTPS allowed. If your application listens on a custom port such as 8000, add it now instead of waiting until after the cutover:

sudo firewall-cmd --permanent --add-port=8000/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports

This sequence avoids lockout. Add the new rule before removing the old one.

Copy the managed workload to the new server

The exact file layout depends on the customer service you are moving. For a web app, a common staging location is /opt/myapp. Use rsync with permissions preserved, then check the result before the DNS change.

On the VPS as the non-root sudo user, create the target directory and copy the data from the source server:

sudo mkdir -p /opt/myapp
sudo chown -R deploy:deploy /opt/myapp
rsync -aHAX --delete -e ssh root@203.0.113.10:/opt/myapp/ /opt/myapp/

Replace the source IP in the rsync command with the real old server address if different from the documentation IP. The trailing slash matters. It tells rsync to copy the contents of the source directory, not the directory itself.

Check ownership and file count after the transfer:

cd /opt/myapp
find . | wc -l
ls -la

If your migration includes databases, dump them on the source server, copy the dump, and restore it on the destination. The safest pattern is source-side export, transfer, then destination-side import. If you already maintain PostgreSQL recovery drills, apply the same discipline here: verify the backup before you trust the cutover.

Handle SELinux so the new host actually serves traffic

AlmaLinux commonly blocks new paths until SELinux labels match the service. That is normal. Do not disable SELinux to make a migration easier.

On the VPS as the non-root sudo user, label a web directory and confirm the current mode:

getenforce
sudo semanage fcontext -a -t httpd_sys_content_t "/opt/myapp(/.*)?"
sudo restorecon -Rv /opt/myapp

If the site writes uploads or cache files, give those subdirectories the correct writable type instead of opening the entire tree. For example:

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/opt/myapp/storage(/.*)?"
sudo restorecon -Rv /opt/myapp/storage

A successful run prints the relabeled paths. If semanage is missing, the policycoreutils-python-utils package was not installed correctly.

Run the service and check the logs

For this tutorial, assume the migrated app listens on port 8000. Start it with systemd so the server survives reboots. If your application already has a service file, adapt the content to your binary or start script.

On the VPS as the non-root sudo user, create the service file:

sudo tee /etc/systemd/system/myapp.service > /dev/null <<'EOF'
[Unit]
Description=MyApp managed hosting workload
After=network-online.target
Wants=network-online.target

[Service]
User=deploy
Group=deploy
WorkingDirectory=/opt/myapp
EnvironmentFile=-/opt/myapp/.env
ExecStart=/opt/myapp/bin/myapp --port 8000
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Then check the unit syntax and start it:

sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myapp --no-pager
sudo journalctl -u myapp -n 50 --no-pager

Replace /opt/myapp/bin/myapp with the real application command. A healthy start shows active (running) and no repeated crash loop in the journal.

Put Nginx in front of the application

Many managed hosting moves need a reverse proxy. This keeps the app private on localhost while Nginx handles TLS, headers, and client connections. If you want a deeper Nginx reference, Hostperl already has Nginx log guidance for hosting support and reachability troubleshooting that complement this workflow.

On the VPS as root, install Nginx and create a site file:

sudo dnf -y install nginx
sudo tee /etc/nginx/conf.d/myapp.conf > /dev/null <<'EOF'
server {
    listen 80;
    server_name server.example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
EOF

Test the config before reload:

sudo nginx -t
sudo systemctl enable --now nginx
sudo systemctl reload nginx
sudo systemctl status nginx --no-pager

If nginx -t reports an error, fix it before reloading. That is the safest way to avoid a public outage.

Verify the managed hosting cutover

At this point, the new server should respond locally and over the public IP. Use the local server first, then test from your computer.

On the VPS as the non-root sudo user:

curl -I http://127.0.0.1
ss -tulpn | grep -E ':80|:8000'
systemctl is-enabled myapp
systemctl is-enabled nginx

You want both services enabled and listening. If the app fails only behind Nginx, check the proxy target and the app port.

On your local computer, test the public endpoint:

curl -I http://203.0.113.10
curl http://203.0.113.10

Replace 203.0.113.10 with the destination IP if it differs. A successful response should return your site headers or application output, not a connection timeout.

Safe rollback if something breaks

If the app or proxy fails, keep the old server online and switch DNS back only after you confirm the old host still works. On the new server, stop the service but do not delete the files yet.

On the VPS as the non-root sudo user:

sudo systemctl stop myapp nginx
sudo systemctl disable myapp nginx
sudo firewall-cmd --permanent --remove-port=8000/tcp
sudo firewall-cmd --reload

Then point traffic back to the old host and re-run the source-side checks. That gives you a clean rollback without data loss. If the problem is a bad release rather than the migration itself, restore the previous application tree from backup and repeat the cutover after a local smoke test.

Most likely migration failures and fixes

  • SSH works as root but not as deploy. Run ls -ld /home/deploy /home/deploy/.ssh /home/deploy/.ssh/authorized_keys. The expected permissions are 700 on .ssh and 600 on authorized_keys. Fix them with chmod 700 /home/deploy/.ssh and chmod 600 /home/deploy/.ssh/authorized_keys.
  • Nginx returns 502. Check the app listener with ss -tulpn | grep 8000 and the logs with journalctl -u myapp -n 100 --no-pager. Restart the app only after you correct the executable path or environment file.
  • The app works on localhost but not on the public IP. Run sudo firewall-cmd --list-all and confirm port 80 or 8000 is open. Then test from your local computer again.
  • SELinux blocks files or uploads. Check the denial clues with sudo ausearch -m avc -ts recent. Reapply the correct context with sudo restorecon -Rv /opt/myapp or adjust the fcontext rule.

Final verification and next steps

Finish with one reboot test, because a managed hosting migration is only real if the services return after boot. On the VPS as the non-root sudo user:

sudo reboot

Reconnect after the server comes back, then run:

ssh deploy@203.0.113.10
systemctl status myapp --no-pager
systemctl status nginx --no-pager
curl -I http://127.0.0.1

If those checks pass, the destination is ready for DNS cutover. Keep the old server available for a short safety window, then decommission it only after the new host has served real traffic without errors.

For agency migrations and support-led launches, Hostperl can stage the destination on the right platform and keep the operational details under control. If your workload is better suited to a VPS than a larger box, start with managed VPS hosting; if the migration is customer-facing or high traffic, review dedicated server hosting for more headroom.

That combination gives you a clear path for cutovers, rollback, and post-move validation without guessing at the next step.

FAQ

Should I disable root SSH after the migration?

Only after a second terminal proves the deploy account works with sudo and key-based login. Keep a root console path until the cutover is stable.

Can I use this AlmaLinux workflow on Debian?

The migration pattern is similar, but the package manager, firewall, and SELinux pieces are different. Use a Debian-specific guide for apt and UFW.

Why does this guide keep the source server online?

Because rollback is much faster when the old host still has intact data and a working service. You can switch traffic back immediately if the destination fails validation.

Do I need Nginx for every managed hosting migration?

No. Use it when you need a reverse proxy, TLS termination, or a public front end for an internal app. If the workload already has a separate web stack, adapt the service layer only.