Nginx Web Server in Linux Containers (LXC)
Published: 2022-02-03 | Last Updated: 2022-02-11 | ~8 Minute Read
Table of Contents
- Introduction
- Building Nginx
- Installing Nginx dependencies
- Alternate way to include dependencies
- Installing the Nginx package
- Container networking
- Conclusion
Introduction
As you might recall we previously created a Slackware based Linux container. I think it would be nice to have this container start doing some useful things.
Today we will look at adding an Nginx web server to a Linux container.
Building Nginx
I have chosen to build the Nginx package on the container host, this will allow us to easily install the package inside the container. Take a look at this previous example in case a refresher is needed as to how to build a Slackware package.
This is what the package looks like on the host:
root@container-host:/tmp # ls | grep .tgz
nginx-1.12.2-x86_64-1_SBo.tgz
Installing Nginx dependencies
Before installing the Nginx package that we built on the host system we need to make sure the container has the required runtime dependencies for nginx: libxml2
, libxslt
, gd
, perl
, libcrypt
, libgpg-error
, fontconfig
, harfbuzz
, freetype
, libXpm
, libX11
, libxcb
, libXau
, libXdmcp
These packages are available from the official Slackware mirrors and the process for installing should be straight forward. I’ll showcase the installation of the first package as it’s the same for the entire list of dependencies:
root@slack-nginx:/tmp# wget --no-check-certificate https://mirrors.eze.sysarmy.com/slackware/slackware64-14.2/slackware64/l/libxml2-2.9.4-x86_64-2.txz
--2022-02-03 20:45:20-- https://mirrors.eze.sysarmy.com/slackware/slackware64-14.2/slackware64/l/libxml2-2.9.4-x86_64-2.txz
Resolving mirrors.eze.sysarmy.com... 200.9.157.182
Connecting to mirrors.eze.sysarmy.com|200.9.157.182|:443... connected.
WARNING: cannot verify mirrors.eze.sysarmy.com's certificate, issued by 'CN=R3,O=Let\'s Encrypt,C=US':
Unable to locally verify the issuer's authority.
HTTP request sent, awaiting response... 200 OK
Length: 1238084 (1.2M)
Saving to: 'libxml2-2.9.4-x86_64-2.txz'
libxml2-2.9.4-x86_64-2.txz 100%[===============================================>] 1.18M 1.16MB/s in 1.0s
2022-02-03 20:45:22 (1.16 MB/s) - 'libxml2-2.9.4-x86_64-2.txz' saved [1238084/1238084]
Install the required dependencies with the installpkg
program:
root@slack-nginx:/tmp# installpkg libxml2-2.9.4-x86_64-2.txz
Verifying package libxml2-2.9.4-x86_64-2.txz.
Installing package libxml2-2.9.4-x86_64-2.txz:
PACKAGE DESCRIPTION:
# libxml2 (XML parser library)
#
# Libxml2 is the XML C parser library and toolkit. XML itself is a
# metalanguage to design markup languages -- i.e. a text language where
# structures are added to the content using extra "markup" information
# enclosed between angle brackets. HTML is the most well-known markup
# language. Though the library is written in C, a variety of language
# bindings make it available in other environments.
#
Executing install script for libxml2-2.9.4-x86_64-2.txz.
Package libxml2-2.9.4-x86_64-2.txz installed.
With these dependencies installed we should now be able to start Nginx
Alternate way to include dependencies
Alternatively you could include the required Nginx runtime dependencies during container build time. Simply add the following lines in the /usr/share/lxc/templates/lxc-slackware
in the template section:
# thanks to Vincent Batts for this list of packages
# (that I modified a little :P)
# http://connie.slackware.com/~vbatts/minimal/
cat <<EOF > $CONF/templates/minimal-lxc.template
...
...
libxml2
libxslt
gd
perl
libgcrypt
libgpg-error
fontconfig
harfbuzz
freetype
libXpm
libX11
libxcb
libXau
libXdmcp
I would recommend to create a copy of the /usr/share/lxc/template/lxc-slackware
file and name it something a bit more specific for the use case /usr/share/lxc/templates/lxc-slack-nginx
for example, you can then create a new container using this template the same way we did previously.
Installing the Nginx package
Let’s obtain our container’s current state and IP with the lxc-ls --fancy
command:
root@container-host:~ # lxc-ls --fancy
NAME STATE AUTOSTART GROUPS IPV4 IPV6
slack-nginx RUNNING 0 - 10.0.3.85 -
Since I have not yet created a regular user I allowed ssh
for the root user in the /etc/ssh/sshd_config
file:
PermitRootLogin yes
Note that in a production environment a non-privileged user should be created since using the root
user for remote ssh administration is not best practice and will become a security hole. I’m just doing this in a temporary lab so I’ll continue.
Once we have ssh
access allowed, we can transfer the built package from host to container via scp
like so:
root@container-host:/tmp # scp nginx-1.12.2-x86_64-1_SBo.tgz root@10.0.3.85:/tmp
root@10.0.3.85's password:
nginx-1.12.2-x86_64-1_SBo.tgz 100% 670KB 52.5MB/s 00:00
Now from the container we can install the package by using the installpkg
program
root@slack-nginx:/tmp# installpkg nginx-1.12.2-x86_64-1_SBo.tgz
Verifying package nginx-1.12.2-x86_64-1_SBo.tgz.
Installing package nginx-1.12.2-x86_64-1_SBo.tgz:
PACKAGE DESCRIPTION:
# nginx (http/imap/pop3 proxy)
#
# Nginx [engine x] is a high-performance HTTP server and reverse proxy,
# as well as an IMAP/POP3 proxy server.
#
# Nginx was written by Igor Sysoev.
#
# Homepage: http://nginx.net/
#
Executing install script for nginx-1.12.2-x86_64-1_SBo.tgz.
Package nginx-1.12.2-x86_64-1_SBo.tgz installed.
Start the Nginx web server:
root@slack-nginx:/tmp# /etc/rc.d/rc.nginx start
Starting Nginx server daemon...
We can now test that Nginx is working by calling the server from the host:
root@container-host:~ # curl 10.0.3.85
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Container networking
We have now confirmed that the container is successfully serving web pages, but other hosts on the same network as the container’s host are unable to reach these web pages.
We need to do some adjustments to the previous network configuration of the container. Before making the changes below make sure to bring down your container gracefully:
root@container-host:/tmp # lxc-stop -n slack-nginx
Below is the updated configuration in the /var/lib/lxc/slack-nginx/config
file on the host:
lxc.network.type = veth
lxc.network.flags = up
#lxc.network.link = lxcbr0 # We changed this line
# Bridge to use on the host
lxc.network.link = br0 # New line
# Ip to get from the gateway
lxc.network.ipv4 = 192.168.2.21/24 # New line
# define a gateway to have access to the internet
lxc.network.ipv4.gateway = 192.168.2.1 # New line
I use this host for virtualization as well, so the br0
bridge was already created in my case, however creating the bridge interface on the host is pretty straight forward by editing the host’s /etc/rc.d/rc.inet1.conf
, below are the relevant lines:
# Default gateway IP address:
GATEWAY="192.168.2.1"
# Example of how to configure a bridge:
# Note the added "BRNICS" variable which contains a space-separated list
# of the physical or virtual network interfaces you want to add to the bridge.
IFNAME[0]="br0"
BRNICS[0]="eth0"
IPADDR[0]="192.168.2.20"
NETMASK[0]="255.255.255.0"
This configuration should allow the proper creation of a bridge on the host which can then be used by the containers.
The new lxc.network.link
entry above defines the bridge on the host to be used by the container. We can take a look at the current available bridges and interfaces using them on the host like so:
root@containter-host:~ # brctl show
bridge name bridge id STP enabled interfaces
br0 8000.74d4358d33a4 no eth0
vethSIP9M7
vnet0
virbr0 8000.5254002fb2c7 yes
In the above output we can see that the br0
bridge is being used by three interfaces:
eth0
- host interfacevethSIP9M7
- LXC container interfacevnet0
- virtual machine
With this configuration other hosts on our 192.168.2.0/24
network can now reach our containerized Nginx web server.
Conclusion
This configuration allows for the host and the container to be on the same network segment (192.168.2.0/24
in our example) and talk to the same gateway as the host. With a bit more configuration on the gateway, such as port forwarding, we could expose the container directly to the internet for example.
We now have our own minimal Nginx web server configured with Slackware based Linux containers.