Why Automate Deployment?
Every time you push a change, manually building and uploading files to your server is tedious and error-prone. A CI/CD pipeline removes that friction entirely — push to main, and your site is live within minutes.
The best deployment is one you don't have to think about. Automate everything that can be automated.
In this post, I'll walk through how I set up continuous deployment for this portfolio using GitHub Actions, SSH, and rsync.
The Stack
Here's what we're working with:
| Component | Technology |
|---|---|
| Framework | React + Vite |
| Language | TypeScript |
| Hosting | Hostinger VPS |
| CI/CD | GitHub Actions |
| Transfer | rsync over SSH |
The Workflow
1. Trigger on Push
The pipeline runs whenever code is pushed to the main branch:
on:
push:
branches:
- main
2. Build the Project
We install dependencies with Yarn and run the production build:
yarn install --frozen-lockfile
yarn build
This produces a dist/ folder with the optimized static assets.
3. Deploy with rsync
The built files are synced to the server using rsync over SSH:
rsync -avz \
-e "ssh -i ~/.ssh/key -p $PORT" \
dist/ \
user@host:/path/to/public_html
rsync only transfers changed files, making deployments fast and bandwidth-efficient.
Key Decisions
Here's what I considered when setting this up:
- Yarn over npm — Deterministic installs with
--frozen-lockfileensure CI builds match local builds exactly - rsync over FTP — Incremental transfers, SSH encryption, and better reliability
- GitHub Secrets — SSH keys, host, port, and paths are never committed to the repo
Security Considerations
- Generate a dedicated SSH key pair for CI/CD
- Add the public key to your server's
authorized_keys - Store the private key as a GitHub secret
- Use a restricted user account with minimal permissions
The Result
With this setup, the entire flow looks like:
- Write code locally
- Push to
main - GitHub Actions builds the project
- rsync deploys to Hostinger
- Site is live
The whole process takes under 60 seconds from push to production.

Lessons Learned
Start simple. You don't need Kubernetes to deploy a portfolio. A well-configured rsync pipeline is fast, reliable, and easy to debug.
- Keep your pipeline fast — cache dependencies, minimize build steps
- Test locally first — run
yarn buildbefore pushing to catch errors early - Monitor your deploys — check GitHub Actions logs after each push
- Use branch protection — prevent direct pushes to
mainin team settings
That's the entire setup. No Docker, no cloud functions, no over-engineering — just a clean pipeline that gets your code from editor to production reliably.