Treating server configuration as code — tracked in Git, reviewed, and deployed like any application — brings the same reliability benefits to infrastructure that version control brings to software.
Why Version Control Configuration
- Full history of every change, who made it, and why
- Ability to review changes before applying (pull requests)
- Rollback capability if a configuration change causes problems
- Documentation by nature — the repository itself describes the intended server state
What to Version Control
| Category | Examples |
|---|---|
| Web server configs | Nginx/Apache virtual host files |
| Application deployment configs | docker-compose.yml, systemd unit files |
| Infrastructure definitions | Terraform files, Ansible playbooks, cloud-init templates |
| CI/CD pipeline definitions | GitHub Actions workflows, Jenkinsfiles |
What NOT to Commit Directly
- Secrets, passwords, API keys — use environment variables or a secrets manager instead (see How to Manage Environment Variables and Secrets on a VPS)
- SSL private keys
- Anything containing customer/personal data
Setting Up a Basic Infrastructure Repository
mkdir infrastructure && cd infrastructure
git init
infrastructure/
├── nginx/
│ ├── sites/
│ │ └── myapp.conf
├── systemd/
│ └── myapp.service
├── ansible/
│ ├── inventory.ini
│ └── playbook.yml
└── README.md
Deploying Configuration Changes from the Repository
Rather than editing config files directly on the server, edit them in the repository, then deploy:
scp nginx/sites/myapp.conf deploy@YOUR_SERVER_IP:/tmp/
ssh deploy@YOUR_SERVER_IP "sudo cp /tmp/myapp.conf /etc/nginx/sites-available/ && sudo nginx -t && sudo systemctl reload nginx"
Or, more robustly, use Ansible to apply changes consistently (see How to Use Ansible for Server Configuration Management).
Using Pull Requests for Configuration Changes
Even for infrastructure, requiring a pull request/review before merging configuration changes catches mistakes before they reach a live server — the same discipline applied to application code.
Detecting Configuration Drift
Over time, manual fixes made directly on a server (during an incident, for example) can cause the live server to diverge from what's in version control. Periodically audit for this:
diff /etc/nginx/sites-available/myapp.conf infrastructure/nginx/sites/myapp.conf
Tools like Ansible naturally help prevent drift, since re-applying a playbook enforces the defined state, correcting any manual deviations.
Documenting the "Why" Alongside the "What"
Use commit messages and a README to explain non-obvious configuration decisions — a future administrator (including yourself, months later) benefits enormously from understanding why a particular setting exists, not just what it is.
Example Commit Message Practice
git commit -m "Increase Nginx client_max_body_size to 50m
Required for the new bulk file upload feature added in
the main application (see app repo commit abc123).
Without this, uploads over 1MB were rejected with 413."
Handling Server-Specific Variations
For configuration that legitimately differs between servers (different domains, different resource limits), use templating (Ansible Jinja2 templates, or environment-specific variable files) rather than maintaining entirely separate, drifting copies of similar configs.
Common Errors
Committed a secret accidentally — treat it as compromised and rotate immediately; Git history retains it even after a subsequent removal commit.
Best Practices
- Never commit secrets directly; use environment variables or a dedicated secrets manager
- Require review for infrastructure changes, same as application code
- Periodically check for configuration drift between the repository and live servers
Related Articles
- How to Use Ansible for Server Configuration Management
- How to Manage Environment Variables and Secrets on a VPS
- Infrastructure as Code Basics: Managing VPS Config with Terraform
