A self-hosted CI/CD pipeline can turn a Git commit into a tested, security-checked, deployable release without handing the entire workflow to a hosted service. This guide provides a reusable checklist for connecting a repository to build automation, artifact storage, environment promotion, rollback procedures, and operational checks.
Overview
A practical Git-to-deployment pipeline has a clear sequence: a change is committed, automated checks run, a versioned artifact is created, the artifact is reviewed or promoted, and the target environment is updated. Self-hosting gives your team control over the runners, credentials, network access, logs, and deployment process, but it also makes those responsibilities explicit.
Before choosing a CI/CD platform, define the boundaries of the system. Identify where the source repository is hosted, where jobs will run, where build artifacts will be stored, and how deployments will reach each environment. A Git-based hosting service may provide repository management while a separate open-source deployment platform, container registry, or runner handles the rest. For background on evaluating hosting choices, see Best Open-Source Hosting Platforms for Teams.
Keep the first pipeline deliberately small. A useful initial workflow usually includes:
- Dependency installation using a lockfile where the project supports one.
- Formatting, linting, type checks, and unit tests.
- Build or packaging steps that produce a repeatable artifact.
- Dependency and image scanning appropriate to the application.
- Artifact publication with a commit or release identifier.
- Deployment to a non-production environment before production promotion.
Make the artifact the unit of promotion. Building separately in every environment can create differences between what was tested and what was released. A container image, package, static asset bundle, or compiled binary should be identifiable by its commit, release tag, or another immutable version.
Checklist by scenario
For a small application or single repository
- Document the required runtime. Record the language version, operating-system assumptions, services, and environment variables needed for local and automated builds.
- Pin the build inputs. Use dependency lockfiles, explicit base-image versions, and a predictable package-manager configuration where practical.
- Separate verification from deployment. The test job should be able to fail without changing a server. Deployment should run only after the required checks pass.
- Publish one identifiable artifact. Include the commit identifier in the image tag, package metadata, or artifact name. Avoid relying on an ambiguous tag such as “latest” for rollback.
- Start with staging. Deploy automatically to a staging environment, then require an explicit promotion step for production until the workflow has been exercised.
For a web app that must deploy from Git
Define what happens after a merge to the release branch. A typical flow runs tests, builds frontend assets or a server image, publishes the result, applies configuration for staging, and performs a health check. Production promotion can then reuse the same artifact rather than rebuilding it. For a more detailed application workflow, consult How to Deploy a Web App From a Git Repository.
Use deployment checks that test the application from the outside: an expected HTTP status, a readiness endpoint, a database connectivity check where appropriate, and a small set of critical user paths. Keep these checks safe and non-destructive.
For a containerized service
- Build the image in the CI runner and run tests against it where possible.
- Scan the image and its dependencies according to your risk model.
- Push the image to a private or appropriately controlled registry.
- Deploy by immutable digest or a unique version tag.
- Wait for rollout health checks before marking the job successful.
- Retain enough previous versions to support a tested rollback process.
Registry design matters in a self-hosted setup. Decide who can push, who can pull, how credentials are rotated, and how unused images are retained or removed. See Best Open Source Container Registries for Private Projects for related considerations.
For a monorepo or multi-service project
Do not run every job for every change unless that is intentional. Use path-based conditions, dependency-aware build logic, or a clear matrix strategy to identify affected services. Keep shared validation jobs separate from service-specific jobs, and make the final deployment decision depend on the complete set of required checks. The guidance in Monorepo CI/CD Best Practices can help structure this approach.
For slow builds, add caching only after measuring the bottleneck. Cache package downloads or build outputs with keys that include the relevant lockfile and runtime version. Treat caches as disposable optimization data, not as the source of truth.
What to double-check
Runner isolation and permissions
Determine whether jobs from untrusted branches can run on the same machines or with the same credentials as protected deployment jobs. Prefer isolated runners for sensitive workloads, restrict access to production networks, and avoid granting every pipeline job administrative permissions. A runner should have only the tools and network access required for its assigned work.
Secrets and configuration
Keep secrets out of the repository, build logs, command history, and generated artifacts. Use the CI/CD platform’s protected secret mechanism or an external secret store. Separate staging and production credentials, limit which branches can use production secrets, and rotate credentials when ownership or infrastructure changes.
Configuration should be visible enough to review without exposing sensitive values. Record required variable names, expected formats, and safe defaults in project documentation. If a deployment requires a database migration, define whether it runs before the application rollout, during it, or as a separately reviewed operation.
Deployment safety and rollback
Write down the rollback command or procedure before the first production deployment. Confirm that the previous artifact still exists, that the service can run with the previous application version, and that database changes are compatible with rollback. Not every schema change can be reversed safely; migrations may require an expand-and-contract approach or a forward fix instead.
Add a post-deployment observation window. Check logs, error rates, health endpoints, queue depth, and other service-specific signals before closing the release. If the platform supports preview environments, use them for pull requests that need realistic integration testing; see How to Set Up Preview Environments for Pull Requests.
Common mistakes
- Deploying directly from a developer workstation: this bypasses repeatable checks and makes the release difficult to audit. Put the deployment command in the pipeline or a reviewed automation script.
- Rebuilding during promotion: a second build can differ from the tested build. Promote the stored artifact instead.
- Using mutable artifact names: tags that are overwritten make incident investigation and rollback harder. Use immutable identifiers and maintain a human-readable release record.
- Installing unverified tools at runtime: dynamic downloads can make builds unpredictable. Pin versions and verify sources where practical.
- Ignoring failed cleanup: old artifacts, logs, runner workspaces, and caches can consume storage or expose data. Define retention and cleanup rules.
- Making production the first realistic test: validate networking, permissions, migrations, and health checks in a staging environment that resembles production.
- Adding complexity before measuring: multiple deployment controllers, elaborate caching, and custom orchestration are not substitutes for clear stages and observable outcomes.
When to revisit
Review the pipeline before seasonal planning cycles, major releases, infrastructure migrations, or changes to the repository and deployment tools. Also revisit it whenever the application adds a service, changes its runtime, introduces a new data store, or begins handling more sensitive information.
Use a short review checklist:
- Can a new team member explain how a commit becomes a production artifact?
- Are the required checks still relevant to the current codebase?
- Can the team identify exactly which version is running in each environment?
- Have runner permissions, secrets, and network rules been reviewed?
- Has rollback been tested with a realistic failure scenario?
- Are artifact, log, and cache retention rules still appropriate?
- Do pipeline duration and failure patterns point to a specific improvement?
Capture the answers in the repository alongside the pipeline configuration. A self-hosted CI/CD system remains maintainable when its assumptions are documented, its permissions are narrow, and its release path is tested regularly. Start with one reliable path from Git to staging, add production promotion only after the checks are trustworthy, and improve the workflow in response to measured failures rather than adding automation for its own sake.