This site looks a lot better with CSS turned on. Note: IE<10 is not supported.

an article is displayed.

How to run the Nessus (v7) security scanner in a Docker container

The Nessus Vulnerability Scanner logo


I've been looking into automated vulnerability testing quite recently, and decided to give Tenable's Nessus scanner a go. I haven't been using the product anywhere near long enough to write a meaningful review, but I thought that a quick tutorial on how to spin it up in a Docker container might help people that want to try it out for themselves.

There are quite a few ready made Nessus containers on Docker Hub, but the ones I tried seemed either to contain older versions of Nessus, or else were difficult to get set up. Your mileage may vary if you're better with Docker than I am.


By the end of this article, you should be able to:

  • locate and download Nessus Home
  • create and apply the correct license key
  • create a Docker image that can be used to run the latest version of Nessus Home (7.0.2 at the time of writing)


  • OSX (High Sierra) as a development platform
  • a Docker installation
  • a working knowledge of the Docker command line

OSX isn't an essential requirement, but it's what I used for my Nessus / Docker installation.

Get Nessus

You'll need to sign up for a free Nessus account, and you can get that sorted out on Tenable's site.

Go to the registration page and enter your details.

The Nessus registration page

When registration is complete, Tenable will send you an activation code via email.

Remember that the Home license only authorises you to run the scanner for non-commercial purposes.

If you're feeling lazy, you can simply use my ready made image directly from Dockerhub as soon as you have your activation code, and skip past writing the Dockerfile altogether. If you'd rather do this, simply run the following command at the terminal and then jump to the Running the Docker image section:

docker pull fizzymatt/nessus-7-ubuntu

If you're content to take the long way round, however....

Head on over to the Nessus downloads page

Grab yourself a copy of the package. You'll need to read and accept the license agreement first.

I'm using this particular package because it's compatible with the 64 bit Ubuntu 16.04 image that we'll build later on.

Make sure that the package has downloaded completely (it should be 58mb) before proceeding, or you'll get an "unexpected end of file or stream" error when attempting to install Nessus.

The Nessus download page

Creating the Docker image

As soon as you receive the email containing your activation code, you have everything you need to start writing a Docker file.

Create the following directory structure, containing an empty Dockerfile and the Nessus package that we downloaded earlier.

- nessus
    -- Dockerfile
    -- Nessus-7.0.2-ubuntu1110_amd64.deb

Copy and paste the following code into the Dockerfile.

FROM ubuntu:16.04

ADD Nessus-7.0.2-ubuntu1110_amd64.deb /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb

RUN apt-get update -y \
    && apt-get install -y apt-utils tzdata \
    && dpkg -i /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb \
    && rm -r /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb


CMD service nessusd start && tail -f /dev/null

So what's going on in the Dockerfile?

This first line tells Docker that we want to use Ubuntu as a base image. When we create a container from the image later on, you'll see that Docker pulls in the Ubuntu image automatically.

FROM ubuntu:16.04

Next, we pull the Nessus package that we stored locally into the Docker image, using Docker's ADD command.

ADD Nessus-7.0.2-ubuntu1110_amd64.deb /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb

In order to keep the Docker image as small as possible, the next few lines actually run a few different commands in succession.

RUN apt-get update -y \
    && apt-get install -y apt-utils tzdata \
    && dpkg -i /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb \
    && rm -r /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb

What are all those ampersands for?

The double ampersands cause one command to be run after another, so we don't need to use RUN as many times.

Every time an instruction is used in a Dockerfile, Docker will add an extra layer to the resulting image, which will cause it to increase in size. For this reason, it's a good idea to take care when adding instructions.

Let's break those commands down a bit:

First of all, we update the package lists for our Ubuntu base.

RUN apt-get update -y \

Next we install "tzdata", which is a package required to process time zone and daylight-saving time data.

&& apt-get install -y apt-utils tzdata \

We then install the Nessus package using Ubuntu's dpkg tool.

&& dpkg -i /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb \

And then, remove the Nessus package that we pulled in from our local environment. Nessus is installed, so there's no point in having a redundant package hanging around just taking up valuable space.

&& rm -r /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb

The Nessus scanner listens for requests on port 8834, so we tell Docker to expose it on our image


Finally, we run the commands that will start the Nessus process when a container, based on our image, is run.

CMD service nessusd start && tail -f /dev/null

The first command starts the nessusd service....

CMD service nessusd start ....

....and the second command is actually a workaround to prevent the container from exiting after the nessusd process starts.

The nessusd process runs in the background, which causes Docker to think that the application process has stopped, so we need to create a foreground process to persist our container. The tail command is an example of a process that runs in the foreground, and in our Dockerfile we tell it to write to the /dev/null directory.

/dev/null is a special directory by default on Unix systems, and writing to it has no effect (reading from /dev/null should return 0 bytes). There are no logs being filled up or anything like that, and so we can use it to keep our container up and running without any impact on the main nessusd process.

.... tail -f /dev/null

Building the Docker image

Building the Docker image is a simple matter, and can be acheived by running the following command at the terminal:

docker build -t fizzymatt/nessus-7-ubuntu .

The argument allows us to provide a tag that we can use to reference the image. It's best to read the Docker documentation for recommendations about creating tags, but I'll be using "fizzymatt/nessus-7-ubuntu" for the purposes of this article.

The last argument "." tells Docker to search for the Dockerfile in the location where the command is run, so if you're running the command in a different location, be sure to provide the path.

You may notice a warning that reads "debconf: delaying package configuration, since apt-utils is not installed" in the Docker build output. This is benign for our purposes and can be ignored, but if you'd like to know more then you can read the discussion on Github.

When the build has finished, you can check that the Docker image exists by running the following command:

docker images

You should see the "fizzymatt/nessus-7-ubuntu" image (or however you decided to tag it) listed in the output.

Be sure to read the Docker documentation regarding image management (deleting, tagging, etc) as that is beyond the scope of this article.

Running the Docker container

Now it's time to run a container (an instance of an image) based upon the image that we built.

Run the following command at the terminal:

If you aren't running the command in the same directory as the image then be sure to provide the correct path. Also, be sure to read the Docker documentation for "docker run".

docker run -d --name nessus-7-ubuntu -p 8834:8834 fizzymatt/nessus-7-ubuntu

The (detached) argument tells Docker that we want to run the container without attaching a terminal.

The is just a handy way to reference your container.

The argument allows us to publish a specific port to the host. Here we've published port 8834 (the port that our containerised Nessus instance listens on) to port 8834 on the host (which in my case is my laptop).

The final argument (fizzymatt/nessus-7-ubuntu) is a reference to the image that we're using to create the container.

Check that the container has started by running the following command:

docker ps -a

This command tells Docker to list all containers, regardless of their state.

If all's well, you should see the name of your container in the output. Beneath the PORTS heading you'll see ">8834/tcp", and the STATUS will be "Up".

Accessing Nessus

Now that the container is spinning, you should be able to access the Nessus instance.

Open up a web browser and point it at: https://localhost:8834

Depending on how you have your browser set up, you might need to add a security exception if prompted by your browser. This is because we're connecting to Nessus using an https connection, but localhost does not provide a valid SSL certificate. There's no need to worry about this while we're just evaluating Nessus on a local environment, so go ahead and add the exception.

You should be prompted to create a root account. Enter a username and password, and then click "Continue".

Create an account

Next you'll need to enter the activation code that you should have received from Tenable via email, as discussed previously. Be sure to select the scanner type that corresponds to your license, and then click "Continue".

Enter the activation code

There will then follow a great deal of downloading and installing, which took a few minutes over my modest internet connection.

Installing plugins

When all this has finished, you'll be presented with a screen similar to the following:

The Nessus 'My Scans' page displays a link entitled 'Create a new scan'

If you click on "Create a new scan", you should be able to see all the installed templates.

The Nessus 'Scan Templates' page displays 21 available scan templates


By this stage you should have a running Docker container that you can use to get a feel for how Nessus works.

You're on your own from here, as I've not had time to give Nessus a decent test run, but hopefully this has been enough to get you off the starting blocks.

Remember that data will only be persisted inside the container given our current setup, so if you want your settings to stick around after you've stopped or rebuilt the container then you'll probably need to look into using a data volume.

That's beyond the scope of this article, but I might create a "Part 2" if and when I have more experience with the product.

Happy scanning :)

If you liked that article, then why not try:

Symfony 4: setting up a new project

How to set up a Symfony 4 project from scratch using the Composer dependency manager.