How to Deploy to Hostinger Automatically with GitHub Actions

GitHub logo - automated deployment with GitHub Actions

Tired of manually uploading files via FTP every time you update your website? In this guide, I’ll show you how to set up automatic deployments from GitHub to your Hostinger server using GitHub Actions and SSH.

Once configured, every time you push to your main branch, your changes will automatically deploy to your live site.

Prerequisites

  • A Hostinger hosting account (shared or VPS)
  • A GitHub account
  • A project you want to deploy (WordPress theme, static site, etc.)
  • Terminal access on your local machine (Mac/Linux) or Git Bash (Windows)

Step 1: Generate an SSH Key Pair

First, create an SSH key pair on your local machine. This will allow GitHub Actions to securely connect to your Hostinger server.

Open your terminal and run:

ssh-keygen -t ed25519 -C "your-project-deploy" -f ~/.ssh/your_project_deploy

Replace your-project-deploy with a descriptive name for your project.

When prompted for a passphrase, press Enter twice to leave it empty. Automated deployments can’t enter passphrases.

This creates two files:

  • ~/.ssh/your_project_deploy – Your private key (goes to GitHub)
  • ~/.ssh/your_project_deploy.pub – Your public key (goes to Hostinger)

Step 2: Enable SSH Access in Hostinger

  1. Log into your Hostinger hPanel
  2. Navigate to AdvancedSSH Access
  3. Click Enable if SSH isn’t already enabled
  4. Note down your:
    • SSH Host/IP (e.g., 123.456.789.012)
    • SSH Username (e.g., u847362951)
    • SSH Port (usually 65002 for shared hosting)

Step 3: Add Your Public Key to Hostinger

  1. In hPanel, go to AdvancedSSH AccessSSH Keys
  2. Click Add SSH Key
  3. Get your public key by running:
    cat ~/.ssh/your_project_deploy.pub
  4. Copy the entire output (starts with ssh-ed25519)
  5. Paste it into Hostinger and give it a name (e.g., github-deploy)
  6. Save

Step 4: Find Your Deployment Path

You need the full server path to where your files should be deployed.

For a WordPress theme, it’s typically:

/home/YOUR_USERNAME/domains/yourdomain.com/public_html/wp-content/themes/your-theme

For a regular website:

/home/YOUR_USERNAME/domains/yourdomain.com/public_html

You can verify this by:

  1. Going to hPanel → FilesFile Manager
  2. Navigating to your target folder
  3. The path shown (minus the /files/ prefix) combined with /home/YOUR_USERNAME/ is your full path

Step 5: Create the GitHub Actions Workflow

In your project, create the directory structure and workflow file:

mkdir -p .github/workflows

Create .github/workflows/deploy.yml:

name: Deploy to Hostinger

on:
  push:
    branches:
      - main
  workflow_dispatch:  # Allows manual trigger

env:
  # Hostinger shared hosting uses port 65002, VPS uses 22
  DEFAULT_SSH_PORT: 65002

jobs:
  deploy:
    name: Deploy to Production
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup SSH key
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_KEY }}" > ~/.ssh/deploy_key
          chmod 600 ~/.ssh/deploy_key
          ssh-keyscan -p ${{ secrets.SSH_PORT || env.DEFAULT_SSH_PORT }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true

      - name: Deploy files via rsync
        run: |
          rsync -avz --delete \
            --exclude='.git' \
            --exclude='.github' \
            --exclude='node_modules' \
            --exclude='.env' \
            --exclude='README.md' \
            -e "ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT || env.DEFAULT_SSH_PORT }} -o StrictHostKeyChecking=no" \
            ./ \
            ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ secrets.DEPLOY_PATH }}/

      - name: Cleanup SSH key
        if: always()
        run: rm -f ~/.ssh/deploy_key

      - name: Deployment Summary
        run: |
          echo "## Deployment Complete" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "**Commit:** \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
          echo "**Deployed at:** $(date -u)" >> $GITHUB_STEP_SUMMARY

Understanding the Workflow

  • rsync: Efficiently syncs only changed files (faster than copying everything)
  • –delete: Removes files on the server that don’t exist locally (keeps server in sync)
  • –exclude: Skips files/folders you don’t want deployed (like .git, node_modules)
  • workflow_dispatch: Lets you manually trigger deployments from GitHub’s UI

Customizing Exclusions

Modify the --exclude lines based on your project. Common exclusions:

--exclude='.git' \
--exclude='.github' \
--exclude='node_modules' \
--exclude='.env' \
--exclude='.env.local' \
--exclude='README.md' \
--exclude='*.md' \
--exclude='tests' \
--exclude='__tests__' \
--exclude='.vscode'

Step 6: Add Secrets to GitHub

  1. Go to your GitHub repository
  2. Navigate to SettingsSecrets and variablesActions
  3. Click New repository secret for each:
Secret Name Value
SSH_KEY Contents of your private key (cat ~/.ssh/your_project_deploy)
SSH_HOST Your Hostinger server IP
SSH_USER Your SSH username (e.g., u847362951)
SSH_PORT 65002 (for shared hosting) or 22 (for VPS)
DEPLOY_PATH Full path to deployment folder

Getting Your Private Key

cat ~/.ssh/your_project_deploy

Copy everything including:

-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----

Step 7: Initialize Git and Push

If your project isn’t already a Git repository:

cd your-project
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin git@github.com:YOUR_USERNAME/your-repo.git
git push -u origin main

Or create the repo with GitHub CLI:

cd your-project
git init
git add .
git commit -m "Initial commit"
gh repo create your-repo-name --private --source=. --push

Step 8: Test the Deployment

Option 1: Push a change

Make any small change, commit, and push:

echo "<!-- deployed -->" >> index.html
git add .
git commit -m "Test deployment"
git push

Option 2: Manual trigger

gh workflow run deploy.yml

Or go to your repo on GitHub → ActionsDeploy to HostingerRun workflow

Monitoring the Deployment

Watch the deployment in real-time:

gh run watch

Or check the Actions tab on GitHub.

Troubleshooting

“Permission denied (publickey)”

  • Verify your public key is added correctly in Hostinger
  • Check that the private key in GitHub secrets is complete (including BEGIN/END lines)
  • Ensure there are no extra spaces or newlines in your secrets

“Connection refused” or timeout

  • Confirm you’re using the correct port (65002 for shared, 22 for VPS)
  • Verify SSH is enabled in hPanel
  • Check if your server IP is correct

“rsync: command not found”

This shouldn’t happen on ubuntu-latest, but if it does, add this step before the deploy:

- name: Install rsync
  run: sudo apt-get install -y rsync

Files not appearing on server

  • Verify your DEPLOY_PATH is correct
  • Check the workflow logs for any rsync errors
  • Ensure the SSH user has write permissions to the target directory

Deploying Multiple Environments

Want staging and production? Create two workflows:

.github/workflows/deploy-staging.yml – triggers on staging branch
.github/workflows/deploy-production.yml – triggers on main branch

Use different secrets for each:

  • STAGING_SSH_HOST, STAGING_DEPLOY_PATH, etc.
  • PROD_SSH_HOST, PROD_DEPLOY_PATH, etc.

Security Best Practices

  1. Never commit secrets – Use GitHub Secrets, never hardcode credentials
  2. Use deploy keys – Create a dedicated SSH key just for deployments
  3. Limit access – The SSH key only needs access to the deployment folder
  4. Private repos – Keep your repo private if it contains any sensitive configuration
  5. Review exclusions – Never deploy .env files, credentials, or API keys

Conclusion

You now have a fully automated deployment pipeline from GitHub to Hostinger. Every push to your main branch will automatically sync your files to your live server within seconds.

This setup works great for:

  • WordPress themes and plugins
  • Static websites
  • PHP applications
  • Any file-based deployments

No more manual FTP uploads. Just push your code and let GitHub Actions handle the rest.