
- Make Git the single source of truth: if a change is not in the repository, it does not go to production.
- A small team needs only four pieces: automated checks on every change, a staging environment, a repeatable deploy and a quick rollback.
- Keep secrets in the CI platform or a secrets manager, never in the repository, and scope them to the environment that needs them.
- GitHub Actions environments can require a reviewer's approval before a production deploy, but on Free, Pro and Team plans that protection only applies to public repositories.
- Start with a pipeline that deploys to staging automatically and to production with one approved click, then add more checks over time.
How should a small team set up CI/CD and stop deploying by FTP?
Put all code in Git, run automated checks on every change, deploy automatically to a staging copy, promote to production with one approved step, keep secrets out of the repository, and make rollbacks a single action. That is continuous integration and continuous delivery in a form a two or three person team can run. It replaces dragging files over FTP with a process that records every change and makes mistakes easy to undo.
This is the setup our cloud and DevOps team introduces when we take over sites and apps that are still deployed by hand.
Why is deploying by FTP risky?
- No history: nobody can say exactly what changed, when or why.
- No easy undo: rolling back means remembering and re-uploading old files.
- Half-finished uploads: a dropped connection can leave the site with a mix of old and new files.
- Drift: quick fixes made directly on the server never reach the code repository and get overwritten later.
- Shared passwords: FTP accounts are often shared and rarely rotated.
Step 1: Why must Git be the source of truth?
Every change, from a one-line fix to a new feature, goes through the repository. Work happens on branches, changes are merged through pull requests where someone reviews them, and the main branch always reflects what should be live. If you have inherited a project where the server and the repository disagree, sync them first; our guide to taking over a codebase covers that audit.
Step 2: What should run on every change?
Continuous integration means the CI platform checks every pull request automatically before it is merged. For a small team, start with:
- Installing dependencies from the lock file, so builds are repeatable.
- A linter or code style check.
- Automated tests for the most important flows.
- A production build, so build errors are caught before deploy day.
- A dependency security audit.
Keep the pipeline fast. If checks take too long, people stop waiting for them.
Step 3: Why do you need a staging environment?
Staging is a copy of production where every merged change lands first. It uses the same software versions and similar configuration, with test or masked data. Clients and team members check new work there, and risky updates, such as framework or plugin upgrades, are tried there before anyone touches the live site. Our guide to upgrading an old Laravel app shows how staging makes large updates safe.
Step 4: What does a good deploy look like?
| Property | What it means |
|---|---|
| Repeatable | The same scripted steps every time, no manual commands |
| Atomic | The new release switches on all at once, not file by file |
| Recorded | Each deploy is linked to a commit and a person |
| Reversible | The previous release can be restored quickly |
| Verified | A health check confirms the site works after the switch |
A common pattern on virtual servers is to upload each release into its own folder, run migrations, then switch a link to the new folder. Rolling back is switching the link back.
Step 5: Where should secrets live?
Passwords, API keys and tokens never belong in the repository. Store them in the CI platform's secret storage or a dedicated secrets manager, and give each environment its own values. GitHub's documentation on using secrets notes that, apart from the built-in token, secrets are not passed to workflows triggered from forked repositories, and it warns teams to make sure secrets are not printed in logs. Rotate any secret that was ever committed to the code history.
Step 6: How do you control who can deploy to production?
Production deploys should need a deliberate step. In GitHub Actions, deployment environments can carry protection rules. GitHub's environment documentation explains that you can add up to 6 required reviewers, one of whom must approve the job, plus an optional wait timer, and that environment secrets only become available to the job after those rules pass. It also notes that on the Free, Pro and Team plans, rules such as required reviewers apply only to public repositories, so check your plan before relying on them for private code. Other platforms offer similar manual approval steps.
Step 7: How fast can you roll back?
Practise it before you need it. A rollback should restore the previous release in minutes, and the team should know when to roll back instead of trying to fix forward under pressure. Database changes need extra care: write migrations that the old and new code can both work with during the switch, and keep a backup before risky ones.
What should happen after each deploy?
Run an automatic health check on key pages, watch error rates for the next few minutes, and post a short note in the team channel with the release and the person who deployed it. Our guide on what to monitor on a production web app lists the alerts that catch a bad release early.
How should a small team start this week?
- Move the live code into a Git repository and confirm it matches the server.
- Add a pipeline that runs the build and basic checks on every pull request.
- Create a staging environment and deploy to it automatically from the main branch.
- Add a production deploy job with a manual approval step and a rollback command.
- Move secrets into the CI platform and rotate any that were exposed.
If you would rather not set this up yourself, our maintenance and security plans include managed deployments, and our custom software team builds pipelines into every new project.
Frequently asked questions
Is FTP deployment really a problem for a small website?
It works until something goes wrong. With FTP there is no record of what changed, no easy way to undo a mistake, and files can be left half uploaded. Even a small site benefits from Git-based deploys, because every change is recorded and a bad release can be reversed in minutes.
Do we need Docker or Kubernetes for CI/CD?
No. Many small teams deploy straight from a pipeline to a virtual server, a managed platform or shared hosting over SSH. Containers help when you run several services or need identical environments everywhere, but they add complexity. Start simple and adopt them only when you have a clear reason.
Which CI/CD tool should we choose?
Use the one built into where your code already lives: GitHub Actions for GitHub, GitLab CI for GitLab or Bitbucket Pipelines for Bitbucket. They are all capable for small teams. The habits matter more than the tool: tests on every change, staging first, secrets out of code and a tested rollback.
How do we handle database changes in a pipeline?
Use migrations: versioned scripts stored in the repository that change the database step by step. The pipeline runs them during deployment. Write migrations so the old and new code can both work during the switch, take a backup before risky changes, and test them on staging first.
Can CI/CD work with WordPress sites?
Yes. Themes, custom plugins and configuration can live in Git and deploy through a pipeline, while content and uploads stay on the server and in the database. Plugin and core updates can be tested on staging before they reach production, which avoids many update-day surprises.
Last updated