CVS Setup

CVS is going to be used to hold the authoritative version of all the files in the site. A checked out copy of the repository is then going to be kept up to date with the repository and this is what files will be served from. Groups will be structured so that each committee will only be able to change their own pages and not be able to affect the site at large. Also the repository will be set up so that changes can only be appended; files cannot be deleted by regular users so an attacker could change the website but the last version will always be preserved.


This setup is going to require a variety of groups to be created both for the webserver and for the cvs server. There is a primary group that everyone who is doing web work will be a member of called www. Each committee will have its own group and for convenience sake these groups are prefaced with www- (www-ecology, www-social, www-computer, etc.) Also there are certain shared resources that are not associated with a particular committee but that they will all have access to (stylesheets, backgrounds, images) and there are groups for these as well also prefaced with www- (www-styles, www-images, etc.)

CVS also has a special set of groups to control access. CVS looks for a special group called cvsadmin when changes are requested to the configuration files. If that group exists then the current user must be a member of that group in order to edit the configuration. Also whenever a file is checked out from the repository a lock is created to prevent another process writing to the file while it is being accessed. Usually these locks are created in the same directory structure as the repository but to do this anyone you want to read from the repository will also need write access to those directories. This is a problem since we want apache to read from those directories but not to be able to write to them. The solution is to create a separate directory structure for the locks and then allow everyone you want to read access to that structure including apache. The group that will own that directory structure will be called cvsread.

CVS Initialization

Now that the basic groups have been created with addgroup the repository can be created. The first step is to create a directory to hold it. This directory is later going to be accessed via a web-based CVS browser so it needs to be inside of the apache chroot jail.

          mkdir /home/www/files/cvs

Now that it is created it needs to have the control files created with:

          cvs -d /home/www/files/cvs init

There is now a working repository at /home/www/files/cvs.

To allow people read only access to the repository without having to give them write access to the directory structure we will change the locks directory directive in the configuration. It is tempting to just edit /home/www/files/cvs/CVSROOT/config. This will in fact change the behavior of CVS but it is not the proper way to change the configuration. All of CVS's configuration files are version controlled so to edit then you check them out and make your changes on a checked out copy.

Any user can check out the control files but if the cvsadmin group has been created only users in that group will be allowed to commit (and root cannot commit under any circumstances.) If you have been doing your setup as root you will have to allow the user you plan to make the changes as to create a lock in order to change the setup. You do this by creating the cvsadmin group and adding them to it:

          groupadd cvsadmin
          usermod -G $(id -G $USER_TO_CHANGE | sed -e "s/ /,/g"),cvsadmin $USER_TO_CHANGE

(If the user has any other supplemental groups usermod requires them to be listed in a comma separated list or they will be removed.) Then give cvsadmin group ownership of the configuration directory:

          chown :cvsadmin /home/www/files/cvs/CVSROOT

Finally, from that user account checkout the control files:

          su - username
          cvs -d /home/www/files/cvs checkout CVSROOT

Once you have the control files checked out edit CVSROOT/config and add the line:


You should create the lock directory and let the cvsread write to it:

          mkdir /home/www/files/cvs-locks
          chown :cvsread /home/www/files/cvs-locks
          chmod g+ws /home/www/files/cvs-locks

Because different users will be accessing this directory and creating subdirectories and you want the whole thing to be accessible to all the members of the cvsread group. Setting the set-gid (sgid) bit on the directory solves this problem. On an executable sgid causes the program to run with the gid of the owner of the program, for a directory though it causes any subdirectories created under that directory to be owned by the owner of the parent directory and also to have the same permissions as the parent.

Repository Setup

All of the sites will be held in one project called websites. Getting this set up is fairly simple:

          export CVSROOT=/home/www/files/cvs
          mkdir websites
          cd websites
          cvs import websites honors start
          cd ..
          rm -rf websites
          cvs checkout websites
          cd websites
          cvs add
          cvs add index.html
          cvs commit -m "Test google page"
          cd /home/www/files
          cvs checkout -d html websites
          cd html/
          ln -s . www
          chown -R apache:apache /home/www/files/html/

If apache is running like it was set up before, should now be up with Google's page.

The file which will be run after every checkin has the -P option to update. This will prune empty directories which keeps things cleaner overall, but if you add a new site it will not show up until there is at least one file on it. The symlink to . named www as mentioned earlier allows mod_vhost to serve up the same page for both and

Setting up the synchronized repository

You are going to have a checked out version of the repository at /home/www/files/html and from this apache is going to serve requests. This copy always needs to be up to date with the repository so we will put an option into CVSROOT/loginfo (which is run after every commit) to update Apache's copy of the files. An issue here is that the script in loginfo runs as the user performing the commit. Because the files in Apache's copy are owned by apache the user will not have the rights to perform the update. There are a couple of ways to deal with the, one is to give the user access rights to Apache's copy by making the files group writable and then add everyone maintaining the site to that group. Another way is to use sudo to run the update as apache. sudo is more secure and easier to maintain.

So to CVSROOT/loginfo we add:

          DEFAULT (sleep 2; sudo -u apache /home/www/files/; &) >> /home/www/var/log/cvs-update.log 2>&1

And then /home/www/files/ looks like:

          cd /home/www/files/html;
          /usr/bin/cvs -Q update -d -P;

The permissions on then need to be set with chown apache:apache /home/www/files/

It is also necessary to inform sudo to allow members of the www group to run the webroot-update script. Changes to the sudo configuration are done using visudo which will bring up the configuration and then syntax check it before committing. Simple add the line:

         %www            ALL=(apache) NOPASSWD: /home/www/bin/