CVS is a legacy version control system, but some teams still maintain historical codebases that depend on it. This guide explains how to run a CVS server over SSH authentication on FreeBSD, with a focus on practical hardening: key-only access, forced commands, and controlled repository permissions.
Originally published on 2010-04-20; fully revised and updated.

What this guide covers
The original post mixed system bootstrap, CVS setup, and SSH hardening. This revision separates those tasks so you can apply them safely in a maintenance environment.
- Create and initialize a CVS repository directory
- Require SSH key authentication for CVS users
- Force SSH sessions to run only the CVS server command
- Add CVSROOT-level ACL and commit-mail basics
- Optionally expose repositories through cvsweb
CVS over SSH architecture
The security model is straightforward: users authenticate with SSH keys, and each key is restricted to run a single CVS server command against an allowed repository path.
flowchart LR
A[Developer generates SSH key] --> B[Admin installs key in authorized_keys]
B --> C[Developer runs CVS command over SSH]
C --> D[SSHD validates key]
D --> E[Forced CVS server command runs]
E --> F[Repository under home ncvs is served]
Prepare the FreeBSD host (legacy baseline)
The source material targets older FreeBSD releases and ports layouts. Treat these commands as a legacy baseline and adapt package names/paths for your current release.
Install required components referenced in the original flow
pkg_add -r cvsup-without-gui
cd /usr/ports/lang/perl5.8 && make all install clean && rehash
use.perl portCode language: PHP (php)
Code bootstrap methods mentioned in the original
| Method | Command path | Notes |
|---|---|---|
| FreeBSD source sync via CVS | cvs -d :pserver:… login/export | No X11 dependency; endpoint and tags are legacy |
| Install cvsup-without-gui | pkg_add -r cvsup-without-gui | Historically faster sync path; package availability may vary |
# Method 1: CVS-based bootstrap (legacy example)
cvs -d :pserver:anoncvs@anoncvs.jp.FreeBSD.org:/home/ncvs login
cd /usr
cvs -R -d :pserver:anoncvs@anoncvs.jp.FreeBSD.org:/home/ncvs export -r RELENG_5_2 src ports
# Method 2: cvsup package (legacy example)
pkg_add -r cvsup-without-guiCode language: PHP (php)
Harden SSH before enabling CVS access
The original guidance explicitly enforces SSH protocol 2 and disables password authentication. This is the minimum baseline for a key-driven CVS setup.
# /etc/ssh/sshd_config
Protocol 2
PasswordAuthentication noCode language: PHP (php)
Create the repository path and initialize CVSROOT
Use a dedicated group (for example ncvs) and a repository manager account (for example repoman) to separate administration from normal user logins.
rm -rf /home/ncvs
mkdir -p /home/ncvs
chown -R repoman:ncvs /home/ncvs
chmod -R 775 /home/ncvs
su -l repoman
cvs -d /home/ncvs init
Restrict CVS users with forced commands in authorized_keys
SSH accounts can become shell-access paths if unrestricted. The original method mitigates this by forcing each key to execute only the CVS server command.
# ~/.ssh/authorized_keys for a CVS user
command="/usr/bin/cvs --allow-root=/home/ncvs server",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAA... user@exampleCode language: PHP (php)
The original post showed ssh-dss keys. In modern OpenSSH deployments, DSA keys are commonly disabled; use a currently supported key type in your environment.
Configure commit mail and ACL-related files in CVSROOT
The source references FreeBSD CVSROOT hook patterns for commit notification and basic access control. At minimum, validate these file roles in your repository:
- avail: controls module/path access by user group
- access: controls who can perform CVS operations
- exclude: excludes paths from tag checks
- options: tag/keyword behavior options
# Example values referenced in cfg_local.pm style configuration
$MAILADDRS = 'cvs-all@example.org';
$MAIL_BRANCH_HDR = 'X-Phantasm-CVS-Branch';
$MAILBANNER = 'The Phantasm Studio repository';
$CVSWEB_URL = 'http://cvsweb.example.org/cgi-bin/cvsweb.cgi';Code language: PHP (php)
Set up cvsweb for browser access
The original article installs cvsweb from ports and then registers repositories in cvsweb.conf. It also points to the FreeBSD CVSweb project page for newer versions: http://www.freebsd.org/projects/cvsweb.html.
cd /usr/ports/devel/cvsweb && make all install clean
cd /usr/local/etc/cvsweb
vi cvsweb.conf
# Add repository mapping (example)
# @CVSrepositories = (
# 'ncvs' => ['New CVS Repository', '/home/ncvs'],
# );Code language: PHP (php)
Comparison of access patterns in this setup
| Access pattern | Security level | Operational impact | Typical use |
|---|---|---|---|
| SSH keys + forced CVS command | Strongest in this guide | Requires key distribution and per-key controls | Committer access to legacy repositories |
| SSH password login | Weaker | Simpler onboarding but larger attack surface | Not recommended for CVS commit paths |
| Anonymous pserver (for sync/fetch) | Limited and legacy | Useful for historical anonymous export flows | Read-oriented bootstrap tasks only |
Best practices for legacy CVS operations
- Keep CVS on an isolated host or VM with minimal services enabled.
- Use key-only SSH authentication and forced commands for every committer key.
- Back up repository data and CVSROOT hook/config files together.
- Document all local patches and custom hooks before OS/package upgrades.
- Plan a migration path to a modern VCS where possible; treat CVS as maintenance-only infrastructure.
I’m Rajesh Kumar, a DevOps, SRE, DevSecOps, Cloud, and Platform Engineering expert passionate about sharing practical knowledge, real-world experiences, and industry best practices. I have worked at Cotocus and regularly write about technology, travel, investing, health, product reviews, and digital marketing through my various platforms.
I publish technical articles at DevOps School, travel stories at Holiday Landmark, stock market insights at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow, and SEO and digital marketing strategies at Wizbrand.
Find Trusted Cardiac Hospitals
Compare heart hospitals by city and services — all in one place.
Explore Hospitals