内容简介:Ever considered setting up and running your very own git server? It’s actually quite easy! In this post, I’ll outline the steps I took to set upmy own so that you can give it a try yourself. But first, why might you even want to go through the trouble of s
Ever considered setting up and running your very own git server? It’s actually quite easy! In this post, I’ll outline the steps I took to set upmy own so that you can give it a try yourself. But first, why might you even want to go through the trouble of setting up your own server?
After all, there are a wide array of excellent and free to use choices out there, such as Github, Gitlab, and the up-and-coming sourcehut .
One reason is ownership: in today’s world of corporate surveillance, rampant privacy violations, and data breaches, there is something to be said of truly owning your own data. Both git and the web itself were designed and built on principles of decentralization and distribution. Standing up your own server is one way to tap into that heritage.
It’s also just plain fun, at least if you’re into that sort of thing. You get to build something useful and put your name on it. It’s something you control. You get to decide how it works, how it looks, who can access it, and what exists on it.
Setting up a git server is actually relatively straight-forward. Almost all of the heavy lifting is done by git itself, but I will also introduce a few supplementary tools to handle things like access control and HTTP access.
Preparing your server
You can run your git server on something as simple as a Raspberry Pi or a Digital Ocean droplet. It’s not very demanding, so you don’t need much horsepower.
First, create a git
user on your server. This user’s home directory will act as the base location for all of your repositories. I chose /var/lib/git
as the home directory, but /home/git
or /srv/git
are other common choices.
# useradd -r -d /var/lib/git git
Make sure to set the password for the new user:
# passwd git
And make sure you can SSH to the git
user on your server:
$ ssh git@yourserver.com
Gitolite
Next, install the excellent gitolite tool. Gitolite makes managing your server much easier and allows you to do things like user management, access control, triggers, hooks, and more. Copy your SSH public key into your git user’s home directory and then clone gitolite into the git user’s home directory.
From your home computer (i.e. not your server):
$ scp ~/.ssh/id_rsa.pub git@yourserver:yourname.pub
From your server:
$ su - git $ git clone https://github.com/sitaramc/gitolite $ mkdir -p ~/bin $ gitolite/install -ln ~/bin $ gitolite setup -pk yourname.pub
Now from your home computer, test your gitolite installation:
$ git ls-remote git@server:gitolite-admin
You should get something like:
9dd8aab60bac5e54ccf887a87b4f3d35c96b05e4 HEAD 9dd8aab60bac5e54ccf887a87b4f3d35c96b05e4 refs/heads/master
The gitolite-admin
repo is where all of the gitolite configuration takes place. You can clone this to your home computer and push your changes back to your server and gitolite will automatically re-configure itself. This is also how you add new SSH keys (either for yourself or for other users).
Gitolite also interfaces quite nicely with git-daemon
and gitweb
. Be sure to check out the thorough documentation on gitolite’s website .
git daemon
Git includes a daemon
subcommand that will listen for incoming connections and serve data over the git://
protocol. This allows you to clone repos from your server using
$ git clone git://yourserver/repo.git
The git://
protocol is the fastest and simplest option for read-only access, and it’s trivial to set up. Assuming your git
user’s home directory is /var/lib/git
, simply create the following systemd
service file (e.g. at /etc/systemd/system/git-daemon.service
):
[Unit] Description=Start Git Daemon [Service] ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/var/lib/git/repositories /var/lib/git/repositories Restart=always RestartSec=500ms StandardOutput=syslog StandardError=syslog SyslogIdentifier=git-daemon User=git Group=git [Install] WantedBy=multi-user.target
Then simply run systemctl enable --now git-daemon
. Make sure port 9418 is open on your firewall.
If you don’t use systemd, you can probably find alternative init scripts for your particular init system in your package manager. Debian, for example, has git-daemon-sysvinit
and git-daemon-run
if you use SysV or runit, respectively.
The git daemon only serves repositories that have a file called git-daemon-export-ok
in their directory root. This allows you to control which repositories you want to be publicly accessible. Gitolite will automatically create this file for you for any repos that are readable by the special daemon
user.
Gitweb and HTTP
The most difficult part of setting up a git server is the web frontend and HTTP access. The git documentation has a section on Smart HTTP which is a good starting point, but it still took me quite a while to get everything working. Part of the reason I had some difficulty was because I insisted on running the webserver in a Docker container (so that I can version control the configuration).
By default, your git
installation includes the git-http-backend
script which allows you to clone over HTTP. If you also want to host a web frontend, then you have to create some rules for your webserver so that it knows when to serve the web page and when to direct traffic to the git-http-backend
script.
Here is an example Apache configuration file:
ServerName yourserver.com DocumentRoot /usr/share/gitweb <Directory "/usr/share/gitweb"> DirectoryIndex gitweb.cgi Options ExecCGI FollowSymLinks SymLinksIfOwnerMatch AddHandler cgi-script cgi Require all granted SetEnv GITWEB_CONFIG /etc/gitweb.conf RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} !^/([^/]+/(HEAD|info|objects|git-(upload|receive)-pack).*)$ RewriteRule ^.* /gitweb.cgi/$0?js=1 [L,QSA,PT] </Directory> ScriptAliasMatch \ "(?x)^/([^./]+)(\.git)?/(HEAD | \ info/refs | \ objects/info/[^/]+ | \ git-(upload|receive)-pack)$" \ /usr/libexec/git-core/git-http-backend/$1/$3 <Files "git-http-backend"> SetEnv GIT_PROJECT_ROOT /var/lib/git/repositories Require all granted </Files>
The above configuration allows repos to be cloned with or without the .git
extension, but since gitolite creates all repositories with the .git
suffix you’ll have to create non-suffixed symlinks to those directories.
Create and modify the /etc/gitweb.conf
file to configure Gitweb.
I run Apache behind a reverse proxy that handles all of the TLS encryption, so the configuration above doesn’t deal with any of that. Setting up TLS for a webserver is out of scope for this guide and if that’s not something you care to do, you can always omit the HTTP/S portion of your server and simply serve via git://
and SSH. Like I said, this part is the most complex and will likely take more time than the other steps. The above snippet should be a good starting point though.
Unfortunately, even after getting the web server configured, I had another problem. The default Gitweb web page is a bit… utilitarian, to phrase it mildly.
Gitweb uses a Perl CGI script to generate the HTML, which means unless you want to manually modify that script your basically stuck with the HTML that Gitweb gives you.
Fortunately, CSS is quite powerful these days and there is a lot you can do with it. With only 6.25 KB of CSS I was able to transform the drab, default Gitweb interface into what you see today atgit.gpanders.com. You may think it still looks drab, but I’m fairly proud of how it turned out.
Gitolite tips and tricks
Here are some of the gitolite tricks I’ve set up on my server that you may find useful.
Mirroring to Github
I still mirror most of my repositories to Github, as that’s still the best place for discoverability and compatibility with other programs.
This is easy to set up in gitolite. In your gitolite.conf
file, add the following to configure the repos you want to mirror to Github:
@github = repo1 repo2 repo @github config remote.github.url = git@github.com:gpanders/%GL_REPO.git config remote.github.mirror = true option hook.post-receive.mirror = mirror
Update your gitolite.rc
file to allow the remote.*
config options to be set:
GIT_CONFIG_KEYS => 'remote\..*\.(url|mirror)',
Now create the following script at hooks/repo-specific/mirror
in your local code path :
#!/bin/sh git push --quiet --mirror --force github
You’ll also need to create an SSH key for your git
user on your server and upload the public key to Github to allow your server to push to Github:
$ ssh yourserver.com $ su - git $ ssh-keygen -t rsa -b 2048 -C 'Git user' $ # Paste the contents of ~/.ssh/id_rsa.pub to https://github.com/settings/ssh/new
Clone repos without .git suffix
Github and other popular hosting sites allow you to interact with remote git repos with or without the .git
suffix, e.g.
git clone https://github.com/gpanders/dotfiles.git
and
git clone https://github.com/gpanders/dotfiles
are the same. Gitolite always uses the .git
suffix on repositories, but you can simply create non-suffixed symlinks that will allow you to clone repositories with or without the .git
extension:
$ cd /var/lib/git/repositories $ ln -s dotfiles.git dotfiles
You can do this manually quite easily, but you can also create a gitolite trigger to automatically create these symlinks everytime a new repo is created.
Create a trigger at triggers/post-compile/create-symlinks
in your local code path with the following contents:
#!/bin/sh # For projects that gitweb has access to, create symlinks in the 'repositories' # directory without the .git suffix pointing to the real repos symlink() { repo="$1" [ -L "$repo" ] && rm "$repo" if gitolite access -q "$repo" gitweb R any || gitolite git-config -q -r "$repo" gitweb\\.; then ln -s "$repo".git "$repo" fi } cd "$GL_REPO_BASE" || exit 1 if [ "$1" = "POST_CREATE" ] && [ -n "$2" ]; then # just one to be done symlink "$2" else # all of them gitolite list-phy-repos | while IFS= read -r repo; do symlink "$repo" done fi
In the above script, only repositories which are publicly acessible on Gitweb have a symlink created, since I only really care about the .git
extension on the web interface (e.g. I want to use git.gpanders.com/dotfiles instead of git.gpanders.com/dotfiles.git). If you want this to apply to all repos, simply remove the gitolite access
check.
You’ll also need a second trigger at triggers/post-compile/update-gitweb-access-list
. This trigger is supplied by gitolite by default, so creating a new trigger just overrides the default one. The only change we need to make to the default trigger is to exclude the .git
suffix from the list of repositories that gitolite makes available to Gitweb.
Copy the default trigger to triggers/post-compile/update-gitweb-access-list
in your local code path and modify line 28 to
echo "$repo" >> $tmpfile
Generate a README
Github and other sites automatically convert your README file (if it exists) from Markdown, reStructured Text, etc. into HTML when you visit the web page. We can do this too with gitolite!
If the file README.html
exists in the root of your repository, Gitweb will display it on the project’s summary page (example). We can create a hook to automatically create this file from the plain text README file in the repo. Create a hook at hooks/repo-specific/readme
in your local code directory with the following contents:
#!/bin/sh if ! command -v pandoc >/dev/null 2>/dev/null; then exit 0 fi tmpdir=$(mktemp -d) git --work-tree="$tmpdir" checkout --force for file in README README.md README.rst README.txt; do if [ -f "$tmpdir"/"$file" ]; then pandoc -o README.html "$tmpdir"/"$file" break fi done rm -rf "$tmpdir"
Now in your gitolite.conf
file add
repo @all option hook.post-receive.readme = readme
Obviously this requires that pandoc
be installed on your git server.
Publish a Hugo site
This is the hook I use to publish this blog. I use Hugo to “compile” my site and I push it to Github where it’s hosted on Github Pages. My publish hook is located at hooks/repo-specific/publish
:
#!/bin/sh set -e if ! command -v hugo >/dev/null 2>&1; then echo "hugo not found" >&2 exit 1 fi if [ -z "$GIT_DIR" ]; then echo "GIT_DIR not set" >&2 exit 1 fi TMPDIR=$(mktemp -d) git --work-tree="$TMPDIR" checkout --force --recurse-submodules git clone --quiet git@github.com:gpanders/gpanders.github.io "$TMPDIR"/public echo "Building site..." (cd "$TMPDIR" && hugo --quiet --cleanDestinationDir --destination public) ( cd "$TMPDIR"/public export GIT_DIR=.git if ! git diff-index --quiet HEAD --; then echo "Publishing site..." git add . git commit --quiet -m "Rebuilding site $(date)" git push --quiet origin master echo "Done!" fi ) rm -rf "$TMPDIR"
and in my gitolite.conf
I simply use:
repo blog option hook.post-receive.publish = publish
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Measure What Matters
John Doerr / Portfolio / 2018-4-24 / GBP 19.67
In the fall of 1999, John Doerr met with the founders of a start-up he’d just given $11.8 million, the biggest investment of his career. Larry Page and Sergey Brin had amazing technology, entrepreneur......一起来看看 《Measure What Matters》 这本书的介绍吧!