Nginx Web Server in Linux Containers (LXC)

Published: 2022-02-03 | Last Updated: 2022-02-11 | ~8 Minute Read

Table of Contents


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

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
--2022-02-03 20:45:20--
Connecting to||:443... connected.
WARNING: cannot verify'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:
# 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)
cat <<EOF > $CONF/templates/minimal-lxc.template

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
slack-nginx RUNNING 0         - -    

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@
root@'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:
# 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:
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
<!DOCTYPE html>
<title>Welcome to nginx!</title>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
<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=""></a>.<br/>
Commercial support is available at
<a href=""></a>.</p>

<p><em>Thank you for using nginx.</em></p>

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: = veth = up = lxcbr0                  # We changed this line
# Bridge to use on the host = br0                      # New line
# Ip to get from the gateway =          # New line
# define a gateway to have access to the internet =      # 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:

# 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.

This configuration should allow the proper creation of a bridge on the host which can then be used by the containers.

The new 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
virbr0          8000.5254002fb2c7       yes

In the above output we can see that the br0 bridge is being used by three interfaces:

With this configuration other hosts on our network can now reach our containerized Nginx web server.


This configuration allows for the host and the container to be on the same network segment ( 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.

Have a comment on one of my posts? Start a discussion in my public inbox by sending an email to ~grokkingnix/ [mailing list etiquette] [mailing list archive]

Posts from blogs I follow:

Free software licenses explained: MIT

This is the first in a series of posts I intend to write explaining how various free and open source software licenses work, and what that means for you as a user or developer of that software. Today we’ll look at the MIT license, also sometimes referred to …

via Drew DeVault's blog February 7, 2022
Introducing a Falkon extension RSS Finder

This weekend I decided to semi automate the process of searching for RSS feeds on websites while using Falkon web brosers. Many websites provide RSS feeds but do not provide any visible link or icon to access them (eg. many Wordpress based sites) and I ha…

via My land January 23, 2022
A warning to business owners and managers, you are a big part of the problem!

In my last couple of articles, mainly So-called modern web developers are the culprits and Is the madness ever going to end? I have written about some of the major problems with so-called modern web development and I have addressed the issues to the devel…

via January 13, 2022

Generated by openring