Mind Chasers Inc.
Mind Chasers Inc.

Build an Apache HTTP Server from Source and Configure it to Work as a GIT HTTP Server

We show how to checkout, configure, build, and setup a local Apache HTTP Server on Ubuntu 18.04 along with configuring it to work as a smart HTTP Git server.

X-ray Engineering Services


This brief article shows by example how to build the Apache HTTP Server from source on Ubuntu 18.04 and configure it as an HTTP GIT server to support operations like git clone and git push via HTTP. There are many, many options to choose from when setting up an Apache HTTP Server; however, creating a server on an internal LAN for the purpose of acting as a Git server is fairly straightforward.

Building the HTTP Server from the Apache SVN trunk is surprisingly simple, and the server configuration from source has a different, more straightforward approach than the Ubuntu package version, which splits the server configuration into multiple files, folders, and helpers. If you're new to Apache on Ubuntu, you may find you like working with the upstream version better.

Note that the steps shown below may be suitable for internal development on a private network, but additional research and care should be applied before hosting an HTTP (Git) server on a public port accessible via the Internet. Fortunately, Apache has great documentation, and many good references are provided at the end of this article.

Configure, Build, and Install Apache HTTP

Our first step is to use SVN to check out the 2.5.x development trunk version:

# install some dependencies
$ sudo apt install subversion libtool-bin autoconf libpcre++-dev

$ cd /build
$ svn checkout http://svn.apache.org/repos/asf/httpd/httpd/trunk httpd-trunk
A    httpd-trunk/httpd.dsp
 U   httpd-trunk
Checked out revision 1883578.

$ cd /build/httpd-trunk

# Build the APR from source along with httpd
$ svn co http://svn.apache.org/repos/asf/apr/apr/trunk srclib/apr

# configure doesn't exist after svn checkout
$ ./buildconf

found apr source: srclib/apr
rebuilding srclib/apr/configure
buildconf: checking installation...
buildconf: python version 3.6.9 (ok)
buildconf: autoconf version 2.69 (ok)
buildconf: libtool version 2.4.6 (ok)
buildconf: copying libtool helper files using /usr/bin/libtoolize
buildconf: creating include/arch/unix/apr_private.h.in ...
buildconf: creating configure ...
buildconf: generating 'make' outputs ...
buildconf: rebuilding rpm spec file
copying build files
rebuilding include/ap_config_auto.h.in
rebuilding configure
rebuilding rpm spec file
buildconf: Fixing timestamps for ap_expr sources to prevent regeneration

Our next step is to configure and build httpd. Note that we'll be installing the server into /opt/apache2/:

$ CFLAGS="-Og" ./configure --prefix=/opt/apache2 --enable-debugger-mode  --enable-rewrite --enable-log-debug

configure: summary of build options:

    Server Version: 2.5.1
    Install prefix: /opt/apache2
    C compiler:     gcc
    CFLAGS:         -Og -pthread  -O0 -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wdeclaration-after-statement -Werror=declaration-after-statement -Wpointer-arith -Wformat -Wformat-security -Werror=format-security
    C preprocessor: gcc -E
$ make

$ make install
Installing configuration files
Installing HTML documents
Installing error documents
Installing icons
Installing CGIs
Installing header files
Installing build system files
Installing man pages and online manual
make[1]: Leaving directory '/build/httpd-trunk'

Let's perform some introspection of our installation:

$ ls /opt/apache2
bin  build  cgi-bin  conf  error  htdocs  icons  include  lib  logs  man  manual  modules  state

$ ls /opt/apache2/bin/
ab         apr-2-config  checkgid     dbmmanage  envvars-std  firehose      htdbm     htpasswd  httxt2dbm   rotatelogs
apachectl  apxs          ctlogconfig  envvars    fcgistarter  htcacheclean  htdigest  httpd     logresolve

$ ldd /opt/apache2/bin/httpd 
	linux-vdso.so.1 (0x00007ffd013cd000)
	libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007fd29b4a3000)
	libapr-2.so.0 => /opt/apache2/lib/libapr-2.so.0 (0x00007fd29b239000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd29b01a000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd29ac29000)
	libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007fd29a9f1000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd29a7ed000)
	libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fd29a5bb000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fd29b9d2000)

$ ls /opt/apache2/lib/
apr.exp  libapr-2.a  libapr-2.la  libapr-2.so  libapr-2.so.0  libapr-2.so.0.0.0  pkgconfig

$ /opt/apache2/bin/apachectl -V
Server version: Apache/2.5.1-dev (Unix)
Server built:   Nov 17 2020 22:45:58
Server's Module Magic Number: 20200705:2
Server loaded:  APR 2.0.0-dev, PCRE 8.39 2016-06-14
Compiled using: APR 2.0.0-dev, PCRE 8.39 2016-06-14
Architecture:   64-bit
Server MPM:     event
  threaded:     yes (fixed thread count)
    forked:     yes (variable process count)
Server compiled with....
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D HTTPD_ROOT="/opt/apache2"
 -D SUEXEC_BIN="/opt/apache2/bin/suexec"
 -D DEFAULT_PIDLOG="httpd.pid"
 -D DEFAULT_SCOREBOARD="apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"

Next we make a couple of tweaks to the configuration file (/opt/apache2/conf/httpd.conf) so we don't have to run as root:

Listen 8001

ServerName <hostname>:8001

Let's give it a quick try - httpd should serve up /opt/apache2/htdocs/index.html as shown below:

$ /opt/apache2/bin/apachectl -k start

$ ps -e | grep httpd
14056 ?        00:00:00 httpd

$ wget localhost:8001
HTTP request sent, awaiting response... 200 OK
Length: 45 [text/html]
Saving to: ‘index.html’

$ more index.html
<html><body><h1>It works!</h1></body></html>

Configure Apache to work with Git

For this step, we'll follow the guidance provided by the Pro Git ebook to set up a Smart HTTP server that supports authentication and operations like git push. From our reference: "The idea is that Git comes with a CGI called git-http-backend that when invoked will do all the negotiation to send and receive data over HTTP."

Make sure mod_cgi, mod_alias and mod_env modules are being loaded:

LoadModule cgid_module modules/mod_cgid.so
LoadModule alias_module modules/mod_alias.so
LoadModule env_module modules/mod_env.so

Below, we modify httpd.conf to configure the ScriptAlias directive to assoiate the URL path /opt with our Ubuntu Git CGI. We also set two environment variables to be passed to the git-http-backend CGI.

ScriptAlias /git/ /usr/lib/git-core/git-http-backend/
SetEnv GIT_PROJECT_ROOT /opt/depot

Below we continue to follow the aforementioned Pro Git refernece and setup basic authentication using .htpasswd with the following additions to our httpd.conf conf file.

<Files "git-http-backend">
    AuthType Basic
    AuthName "Git Access"
    AuthUserFile /opt/depot/.htpasswd
    Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)
    Require valid-user

Our last step before trying to clone, modify, commit, and push via HTTP is to set up our username and password:

$ htpasswd -c /opt/depot/.htpasswd  <username>

Now we should be able to interact with our Git repo (server) using HTTP:

$ git clone http://<hostname>:8001/git/privateisland.git
Cloning into 'privateisland'...


If you see the error shown below when trying to perform a push (write), make sure your permissions are set up properly on the server so the Apache daemon process can perform writes:


$ git push 
error: remote unpack failed: unable to create temporary object directory


$ ps -ef | grep httpd
root     18715     1  0 16:43 ?        00:00:00 /opt/apache2/bin/httpd -k start
daemon   18716 18715  0 16:43 ?        00:00:00 /opt/apache2/bin/httpd -k start

$ chmod -R 774 <path to repo>
$ chgrp -R daemon <path to repo>

If you get into a state where apachectl can't start or restart, but the httpd processes are still running, you may want to kill all httpd processes and start again:

# apachectl -k restart

# ps -e | grep httpd
 4335 ?        00:00:00 httpd
 4452 ?        00:00:00 httpd
 4453 ?        00:00:00 httpd

# killall httpd

# ps -e | grep httpd

# apachectl -k start


apachectl is a front-end command-line interface to the Apache HTTP server. Below we show various examples with the server we just built.

# Parse the configuration file
$ apachectl -S
ServerRoot: "/opt/apache2"
Main DocumentRoot: "/opt/apache2/htdocs"
Main ErrorLog: "/opt/apache2/logs/error_log"
Define: DOCROOT=/opt/apache2/htdocs

# Is our configuration syntax OK?
$ apachectl -t
Syntax OK

Other Notes

If you want to run the ACME tool certbot, it may not like your non-standard configuration on Ubuntu. You can still use it as shown below:

$ certbot certonly
How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Plugins selected: Authenticator webroot, Installer None

Terms and Acronyms

  • APXS: Apache Extension Tool is a "is a tool for building and installing extension modules for the Apache HTTP server".
  • APR: Apache Portable Runtime "create and maintain software libraries that provide a predictable and consistent interface to underlying platform-specific implementations"
  • CGI: Common Gateway Interface
  • DSO: Dynamic Shared Objects: Modules are ""compiled as DSOs that exist separately from the main httpd binary file"
  • MPM: Multi-Processing Modules "implement the basic behavior of the server. A single MPM must be active in order for the server to function."
  • PCRE: Perl-Compatible Regular Expressions Library
  • VHOST: Virtual Host is the practice of running more than one web site on a single PC / machine.


Didn't find an answer to your question? Post your issue below or in our new FORUM, and we'll try our best to help you find a solution.

And please note that we update our site daily with new content related to our open source approach to network security and system design. If you would like to be notified about these changes, then please join our mailing list.

Related articles on this site:

subscribe to mailing list:

Date: May 4, 2021

Author: Peter


Thanks for the article. I can pull, but I can't push. Here's what I'm getting: > git push Enumerating objects: 12, done. Counting objects: 100% (12/12), done. Delta compression using up to 12 threads Compressing objects: 100% (8/8), done. Writing objects: 100% (8/8), 4.23 MiB | 26.28 MiB/s, done. Total 8 (delta 5), reused 0 (delta 0), pack-reused 0 error: unable to rewind rpc post data - try increasing http.postBuffer fatal: the remote end hung up unexpectedly fatal: the remote end hung up unexpectedly error: RPC failed; curl 65 ioctl callback returned error 2 Everything up-to-date

Date: May 4, 2021

Author: Mind Chasers


From a server shell, make sure your permissions are configured properly for the git repo. You may have incorrect ownership and/or write privileges if you set up the repo first locally. Assuming you're using Ubuntu and following the example above: $ cd /opt/depot/ $ sudo chgrp -R daemon <repo name>.git $ sudo chmod 774 -R <repo name>.git

Add a new comment here or reply to one above:

your email address will be kept private
authenticate with a 3rd party for enhanced features, such as image upload
previous month
next month