Nginx (pronounced Engine-X) is a very popular web server, second only to Apache in the open-source world. Did you know it runs on IBM i?
"Put on your big-boy pants!" is what they told me. "Dig deeper and figure stuff out for yourself!" they said. Based on the feedback I was getting from online forums, I realized I needed to step up my game in my first open-source ventures. Those were some tough days for my RPG programmer brain, but I stuck with it. Now I see the advantages of going through many mud puddles.
Today, I'm striving to wear "big-boy" pants. Through this article, I'm actually hoping to give you some fabric, a pants pattern, some pins, as well as a sewing machine and teach you how to make pants. You can determine whether to put them on. OK, Ok...enough with the metaphors!
As an aside, I grew up with five sisters. My mom taught sewing lessons. So I know how to sew and have even tried to make shoes out of fleece (I bet the reason my mom never stopped me was because she couldn't stop laughing). It was a good thing I learned early that sewing shouldn't be an occupational pursuit. Now my sister Ahmelie on the other hand did much better on the sewing front. Check out www.ahmelie.com.
So what are these pants I talk of? Well, I was going to write an article about how easy it was to install the popular Nginx web server on IBM i. However, it turns out open source had something else in mind. It wasn't easy, but I figured it out. I want to teach you the "how" of getting Nginx installed and working on IBM i in manual fashion. It's kind of like that "give a man a fish, teach a man to fish" saying.
Before I go on, it would be good to back up a bit and describe Nginx. Nginx is an HTTP web server and is used in similar scenarios to Apache. It has been rising in popularity over the past few years and is a common choice for fronting Ruby, Node.js, and other open-source stacks. Why Nginx when we have Apache on IBM i? Well, DigitalOcean has a good Apache vs. Nginx comparison that you can read to learn more about the differences as I won't be focusing on that here. Instead, I will document the motions I went through to get it working on my machine.
In article Installing Git on IBM i, I showed how to use an open-source shell script named wwwperzl.sh to install Git on IBM i. My plan was to use the same process for installing Nginx but I hit a snag. The snag was when it attempted to run line 304 wwwperzl.sh for the Nginx RPM, as shown below.
execute_cmd "rpm --ignoreos --ignorearch --nodeps --replacepkgs -hUv $rpm"
Side note: RPM Package Manager (RPM) is a popular utility for installing software on UNIX-like systems. Think of it as being similar to a *SAVF for moving software around from one machine to the next. Although, it's really much more.
When that line ran, it showed only the following in my PASE shell, with no indication of successful installation.
install nginx-1.9.4-1.aix5.3.ppc.rpm ...
The first step I take in debugging something like this is to break it into small chunks. In this case, I put together the exact rpm command to run manually, as shown below. Note I am running this from a PASE shell, which you can get to via CALL QP2TERM or SSH into your machine.
$ rpm --ignoreos --ignorearch --replacepkgs --nodeps -hUv nginx-1.9.4-1.aix5.3.ppc.rpm
Not remembering what each option does, I went to Google and searched for "rpm linux command" and came to the "man page" (manual/documentation) for the rpm command. From there I see that -v can be added to create a more verbose output, so I add that to the rpm command and ran it again.
$ rpm -v --ignoreos --ignorearch --nodeps --replacepkgs -hUv nginx-1.9.4-1.aix5.3.ppc.rpm
D: counting packages to install
D: found 1 packages
D: looking for packages to download
D: retrieved 0 packages
D: New Header signature
D: Signature size: 68
D: Signature pad : 4
D: sigsize : 72
D: Header + Archive: 438096
D: expected size : 438096
D: opening database mode 0x102 in /opt/freeware/packages
D: found 0 source and 1 binary packages
D: installing binary packages
failed to stat /QNTC: No such file or directory
D: New Header signature
D: Signature size: 68
D: Signature pad : 4
D: sigsize : 72
D: Header + Archive: 438096
D: expected size : 438096
D: package: nginx-1.9.4-1 files test = 0
D: file: /etc/nginx action: create
D: file: /etc/nginx/conf.d action: create
D: file: /etc/nginx/conf.d/default.conf action: create
D: file: /etc/nginx/conf.d/ssl.conf action: create
D: file: /etc/nginx/conf.d/virtual.conf action: create
D: file: /etc/nginx/fastcgi.conf action: create
D: file: /etc/nginx/fastcgi.conf.default action: create
D: file: /etc/nginx/fastcgi_params action: create
D: file: /etc/nginx/fastcgi_params.default action: create
D: file: /etc/nginx/koi-utf action: create
D: file: /etc/nginx/koi-win action: create
D: file: /etc/nginx/mime.types action: create
D: file: /etc/nginx/mime.types.default action: create
D: file: /etc/nginx/nginx.conf action: create
D: file: /etc/nginx/nginx.conf.default action: create
D: file: /etc/nginx/scgi_params action: create
D: file: /etc/nginx/scgi_params.default action: create
D: file: /etc/nginx/uwsgi_params action: create
D: file: /etc/nginx/uwsgi_params.default action: create
D: file: /etc/nginx/win-utf action: create
D: file: /etc/rc.d/init.d/nginx action: create
D: file: /etc/rc.d/rc2.d/Knginx action: create
D: file: /etc/rc.d/rc2.d/Snginx action: create
D: file: /etc/rc.d/rc3.d/Knginx action: create
D: file: /etc/rc.d/rc3.d/Snginx action: create
D: file: /opt/freeware/doc/nginx-1.9.4 action: create
D: file: /opt/freeware/doc/nginx-1.9.4/CHANGES action: create
D: file: /opt/freeware/doc/nginx-1.9.4/LICENSE action: create
D: file: /opt/freeware/doc/nginx-1.9.4/README action: create
D: file: /opt/freeware/etc/logrotate.d/nginx action: create
D: file: /opt/freeware/man/man8/nginx.8 action: create
D: file: /opt/freeware/sbin/nginx action: create
D: file: /opt/freeware/share/nginx action: create
D: file: /opt/freeware/share/nginx/html action: create
D: file: /opt/freeware/share/nginx/html/50x.html action: create
D: file: /opt/freeware/share/nginx/html/index.html action: create
D: file: /var/lib/nginx action: create
D: file: /var/lib/nginx/tmp action: create
D: file: /var/log/nginx action: create
D: file: /var/nginx/html action: create
D: file: /var/nginx/html/404.html action: create
D: file: /var/nginx/html/50x.html action: create
D: file: /var/nginx/html/index.html action: create
D: file: /var/nginx/html/nginx-logo.png action: create
D: running preinstall script (if any)
The D: denotes debugging and gives us an idea of all the directories and files slated for creation. After the command ran, I looked in the IFS to see if program nginx existed, using the following command. I knew to look there based on the debug output declaring that was one of the locations for Nginx files.
$ ls /opt/freeware/sbin/nginx
/opt/freeware/sbin/nginx not found
Hmm… not found. So the install is still unsuccessful, and I have no idea why. However, I do see it hung on "D: running preinstall script (if any)". I go back to the rpm documentation and see I can add a second "v" to get even more debugging information. I run the following command again with more v's. At this point I also dug deeper into some of the rpm options and decided to remove --nodeps (no dependency check) to see what effect that might have.
$ rpm -vv --ignoreos --ignorearch --replacepkgs -hUv nginx-1.9.4-1.aix5.3.ppc.rpm
D: counting packages to install
D: found 1 packages
D: looking for packages to download
D: retrieved 0 packages
D: New Header signature
D: Signature size: 68
D: Signature pad : 4
D: sigsize : 72
D: Header + Archive: 438096
D: expected size : 438096
D: opening database mode 0x102 in /opt/freeware/packages
D: found 0 source and 1 binary packages
D: YES A libgcc = 4.8.3-1 B libgcc >= 4.5.4-1
D: requires: libgcc >= 4.5.4-1 satisfied by db packages.
D: YES A GeoIP = 1.5.1-1 B GeoIP >= 1.5.1-1
D: requires: GeoIP >= 1.5.1-1 satisfied by db packages.
D: YES A gd = 2.0.35-5 B gd >= 2.0.35-5
D: requires: gd >= 2.0.35-5 satisfied by db packages.
D: YES A libxslt = 1.1.28-2 B libxslt >= 1.1.28-2
D: requires: libxslt >= 1.1.28-2 satisfied by db packages.
D: YES A libxml2 = 2.9.2-1 B libxml2 >= 2.9.2-1
D: requires: libxml2 >= 2.9.2-1 satisfied by db packages.
D: YES A openssl = 1.0.1p-1 B openssl >= 1.0.1m-1
D: requires: openssl >= 1.0.1m-1 satisfied by db packages.
D: YES A pcre = 8.37-1 B pcre >= 8.36-1
D: requires: pcre >= 8.36-1 satisfied by db packages.
D: YES A zlib = 1.2.8-1 B zlib >= 1.2.3-7
D: requires: zlib >= 1.2.3-7 satisfied by db packages.
D: requires: AIX-rpm >= 5.3.0.0 unsatisfied.
D: package nginx require not satisfied: AIX-rpm >= 5.3.0.0
D: requires: /bin/sh unsatisfied.
D: package nginx require not satisfied: /bin/sh
D: requires: /usr/bin/ksh unsatisfied.
D: package nginx require not satisfied: /usr/bin/ksh
D: requires: libGeoIP.a(libGeoIP.so.1) satisfied by db provides.
D: requires: libc.a(shr.o) unsatisfied.
D: package nginx require not satisfied: libc.a(shr.o)
D: requires: libcrypto.a(libcrypto.so.1.0.1) satisfied by db provides.
D: requires: libexslt.a(libexslt.so.0) satisfied by db provides.
D: requires: libgd.a(libgd.so.2) satisfied by db provides.
D: requires: libpcre.a(libpcre.so.1) satisfied by db provides.
D: requires: libssl.a(libssl.so.1.0.1) satisfied by db provides.
D: requires: libxml2.a(libxml2.so.2) satisfied by db provides.
D: requires: libxslt.a(libxslt.so.1) satisfied by db provides.
D: requires: libz.a(libz.so.1) satisfied by db provides.
error: failed dependencies:
AIX-rpm >= 5.3.0.0 is needed by nginx-1.9.4-1
/bin/sh is needed by nginx-1.9.4-1
/usr/bin/ksh is needed by nginx-1.9.4-1
libc.a(shr.o) is needed by nginx-1.9.4-1
Bingo. I see some useful information, in particular the lines that say "unsatisfied" and "error: failed dependencies" at the bottom. The first one, "AIX-rpm >= 5.3.0.0 is needed by nginx-1.9.4-1", I don't expect to resolve because we aren't on AIX, though PASE is essentially AIX. The --ignoreos and --ignorearch are in the command for this reason. Moving on, I see sh and ksh are expected to exist. These are programs for the Bourne Shell and Korn Shell, respectively. I run the which command to determine whether they exist and find their location if they do.
$ which sh
/QOpenSys/usr/bin/sh
$ which ksh
/QOpenSys/usr/bin/ksh
As you can see, they do in fact exist and are available to my current shell session (aka IBM i job) but are located in /QOpenSys instead of /bin. Listing the contents of /bin, I see it is in fact a symbolic link to /QOpenSys/usr/bin, as shown below. Symbolic links are like alias or shortcut files in Windows, basically a way to link to a file or directory from a different directory.
$ ls -all /bin
lrwxrwxrwx 1 aaron 0 34 Oct 30 23:20 /bin -> /QOpenSys/usr/bin
At this point, I chalk the sh and ksh problems up as a red herring and move to error "libc.a(shr.o) is needed by nginx-1.9.4-1". File libc.a is an "archive" file that is similar in nature to an RPG *SRVPGM—a way to hold many different modules in a single file or object. Files with names starting in "lib…" are often located in /QOpenSys/usr/lib. Using the ls command, we can see it does in fact exist.
$ ls /QOpenSys/usr/lib/libc.a
/QOpenSys/usr/lib/libc.a
OK, so libc.a does exist, and for some reason the rpm install process couldn't find it. The LIBPATH environment variable can be used to explicitly declare where libraries (of the C variety) can be searched for. So, I set it to look in the directory where I found libc.a, as shown below.
$ export LIBPATH=/QOpenSys/usr/lib
I tried the rpm install again and received the same error. At this point, I am not convinced that libc.a is a red herring but need to keep trying things. Going back to the original debugging info, I remember the "D: running preinstall script (if any)" error. That leads me to look at the rpm command to determine if I can bypass the preinstall script. Sure enough, a couple Google searches lead me to add the --noscripts option to the rpm install, as shown below.
$ rpm --ignoreos --ignorearch --replacepkgs --nodeps -hUv --noscripts nginx-1.9.4-1.aix5.3.ppc.rpm
. . . logs omitted for brevity and duplication sake . . .
nginx ############################GZDIO: 475 reads, 1277040 total bytes in 0.000 secs
Victory! This time I see what I expect with the "nginx ####..." output. Now to check whether the nginx program is available at the location specified in earlier debugging output.
$ ls /opt/freeware/sbin/nginx
/opt/freeware/sbin/nginx
Victory again!
Next I use the which command to see if it finds the nginx program without my having to specify the fully qualified path of /opt/freeware/sbin.
$ which nginx
nginx not found
Bummer. Let's see if the nginx program can display its version to confirm it works at a minimal level.
$ /opt/freeware/sbin/nginx -v
nginx version: nginx/1.9.4
Back on the winning path!
My assumption at this point is some setup, like symbolic link creation, has been lost because I specified --noscripts. I can deal with that later. For now, I am curious to know whether I can create an Nginx HTTP server with a simple configuration. Below is my nginx.conf file that is as bare bones as possible.
/home/aaron/nginx.conf contents:
pid /home/aaron/nginx.pid;
events {
}
http {
server {
listen 8080;
root /home/aaron;
index index.html;
}
}
As you can see from the above nginx.conf, we need to create an index.html file. Below you can see my simple example.
/home/aaron/index.html contents:
<html>
<body>
<h1>Have you tried turning it off and on again?</h1>
</body>
</html>
Now we're ready to start the Nginx web server. By default, the nginx program will look for the nginx.conf file in /etc/nginx, so we need to review the command line options to learn how to override the default. The Nginx docs say to add the -c option along with the path to the config file. Note the tilde (~) character signifies, and is a shortcut to, my home directory (i.e., /home/aaron).
$ /opt/freeware/sbin/nginx -c ~/nginx.conf
Now launch a browser and point it at your machine and the port specified in nginx.conf, as shown below.
Back on the winning path!
You'll notice that when you run the nginx program it doesn't tie up your session. This is sometimes the case with other tooling. Instead, it starts itself as a daemon, which is similar to submitting a job to batch. At this point, we could use the 5250 NETSTAT command to see that Nginx is listening on port 8080.
To end the web server, we again visit the Nginx command line options and learn about the signal (-s) option and apply it as shown below.
$ /opt/freeware/sbin/nginx -c ~/nginx.conf -s stop
At this point, we've successfully installed, and have running, the Nginx web server on IBM i. In the past, on other machines, I didn't have these same issues. This could be a configuration issue, or maybe I've hosed something on my machine. Regardless, you've now learned a little more on how to debug these types of problems—a necessary skill to have as your shop adopts open source.
I'm curious. Do you (the reader) like these types of articles where I walk through more painful approaches to open source on IBM i? Would you prefer the nicely wrapped and packaged "here are the two commands you need to install Nginx on IBM i"? Or maybe both serve a purpose for you. Let me know in the comments or reach me directly at
LATEST COMMENTS
MC Press Online