This weekend I spent a couple hours seeing if I could get the original CERN httpd web server running. I guess this is tangentially related to some things I’m doing at work–maybe more about that another time.

I wasn’t hopeful. The last released version of httpd was from 1996, so this C code is 26 years old. Also while I know what C is, I wouldn’t call myself an expert C programmer by any means. C has always seemed like the Greek or Latin of programming languages to me: an important thing to know because of how it has influenced other languages, and to understand how things have come to be the way they are. But unlike Latin and (ancient) Greek, C is still actively being used today.

I started by downloading the w3c-httpd-3.0A.tar.gz and unpacking it.

Glancing at the BUILD.SH it had all kinds of options for different operating systems that were popular back then: Ultrix, AIX, Mach, HP-UX, SunOS, Irix, SCO, and of course NeXT, which is the operating system that Tim Berners-Lee originally used to build the first web browser and web server. But Linux was in the list too, so I ssh’d to my Ubuntu VPS at Linode (where I host this blog), downloaded and unpacked the tarball there, crossed my fingers, and typed make.

I noticed there were a lot of warnings, which aren’t necessarily bad, but there were also some errors that stopped the compilation in its tracks like:

../../Library/Implementation/HTFTP.c:444:14: error: dereferencing pointer to incomplete type ‘str
uct tm’

So I took a look and did some googling and saw some Stack Overflow comments suggesting that the time.h header needed to be included when you see this error. So I added one to HTFTP.c and the build moved on. Then I encountered this error:

../../Library/Implementation/HTTCP.c:120:14: error: conflicting types for ‘sys_errlist’
  120 | extern char *sys_errlist[];  /* see man perror on cernvax */
      |              ^~~~~~~~~~~
In file included from /usr/include/stdio.h:781,
                 from ../../Library/Implementation/tcp.h:164,
                 from ../../Library/Implementation/HTTCP.c:19:
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h:27:26: note: previous declaration of ‘sys_errlist’ was here
   27 | extern const char *const sys_errlist[];

Reading this error suggested that the variable declaration in HTTPCP.c didn’t match the system level definition so I updated the declaration in HTTCP.c to match the one found in /usr/include/x86_64-linux-gnu/bits/sys_errlist.h. Then the build moved on to another missing time.h which I added. Then I ran into a linking problem:

cc -o httpd_3.0A  HTDaemonDIR.o HTRequest.o HTRetrieve.o HTScript.o HTLoad.o HTCache.o HTCacheInfo.o HTConfig.o HTWild.o HTSInit.o HTSUtils.o HTims.o HTPasswd.o HTAuth.o HTLex.o HTGroup.o HTACL.o HTAAProt.o HTAAServ.o HTAAFile.o HTLog.o HTgc.o HTUserInit.o HTRFC931.o ../../Library/linux/libwww.a
/usr/bin/ld: ../../Library/linux/libwww.a(HTTCP.o): in function `HTErrnoString':
/home/ed/Projects/cern-httpd-orig/Library/linux/../../Library/Implementation/HTTCP.c:148: warning
: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead
/usr/bin/ld: /home/ed/Projects/cern-httpd-orig/Library/linux/../../Library/Implementation/HTTCP.c
:148: warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead
/usr/bin/ld: HTPasswd.o: in function `HTAA_encryptPasswd':
/home/ed/Projects/cern-httpd-orig/Daemon/linux/../../Daemon/Implementation/HTPasswd.c:104: undefined reference to `crypt

A bit more googling around led me to try adding LFLAGS = -lcrypt to the All/linux/Makefile.include file, and then the build succeeded!

httpd, htadm, htimage, cgiparse and cgiutils built successfully
and can be found in directory Daemon/linux.

Have fun! If you have any problems with this software feel free to
contact <>. Online documentation is available via
the <URL:>

BUILD complete!
make[1]: Leaving directory '/home/ed/Projects/cern-httpd-orig/All/Implementation'
WWW build for  linux  done. status =  0

I started it up using the provided httpd.conf after changing the port to 9999 and the document root to my static site website and it worked.

$ Daemon/linux/httpd -r server_root/config/httpd.conf

Interestingly it didn’t work in the browser completely because my style.css was being served up using a Content-Type: text/plain and browsers won’t use it unless it is served up with text/css. CERN httpd stopped being developed the year that CSS was initially released.

Of course after all this noodling around I happened to notice that Emanuele Goldoni had already figured this all out and published his updates on GitHub, after simplifying things a bit by cleaning out unused non-Linux build configuration.

Still, getting it working was kind of a fun exercise, and I was really surprised that so little changes were required to get this 26 year old C code to run. I think this says something interesting about how interconnected C, GCC, Linux and the web are as a software ecosystem–and perhaps about the original httpd code itself. But most importantly it speaks to how the W3C has cared for its own history on the web–the fact that this code was even downloadable, and there was still documentation for it.

I guess seeing httpd serve up my recently updated static website, and for it to render in a browser, also illustrates how backwards compatible the web has been at the protocol level. This seems highly unusual for software.

I’m running httpd for a little bit at … but will turn it off shortly 🖥 🐞 🔥

Update 2022-04-21: It might be nice to create a little Dockerfile for httpd to make it easy to run.