Linux

How to set up a self-hosted speed test server on Ubuntu Linux

This is a self-hosted lightweight speed test implemented in JavaScript and it is based on Web Workers and XMLHttpRequest. The goal of the speed​​test is to measure download speed, upload speed, and ping value. In this article, I will be discussing how an organization can set up a speed test server in its corporate network and measure its employees’ internet connection speed. Fast internet connection is absolutely essential for our day to day work online. It is worth noting that the achievable speed of an internet connection is often slower than stated by the provider. Please see the following guides on how to install and configure Ubuntu Linux, how to install the Windows Subsystem for Linux (WSL) on Windows Server via Server Manager and PowerShell, and how to set up SELinux on a Linux server. Here is a list of the top 20 Speedtest Open Source Projects.

Due to the slow internet connection, I experienced repeatedly during the Covid19 lockdown. I found myself performing multiple speed tests and I thought to myself and needed to set one up for myself :)  

You can set up a speed test server to check how fast your Internet connection is (measure download speed, upload speed, and ping value) and to determine the latency of your users working from the home. To have the Speed Test installed on your server, please head over to this URL and click on download ZIP. If you have GIT installed on your device, you could just clone the repository.

Kindly extract the downloaded speedtest to your desired location. I extracted mine into the downloads folder as this is a test VM.

Install the NPM Package: This is a package manager for the Node JavaScript platform. It puts modules in place so that node can find them, and manages dependency conflicts intelligently. It is extremely configurable to support a wide variety of use cases. is a subsidiary of GitHub, that provides hosting for software development and version control with the usage of Git. NPM is the default package manager for the JavaScript runtime environment Node.js. If you do not have NPM installed on your server, you will not be able to continue with the installation steps below. To have NPM installed on your server, please run the command below.

apt install npm

Having cloned or downloaded this repository, please change into the directory and issue the following command below. For more information on the NPM CLI commands, please see the following link.

npm run setup

NPM run build: This will run the build field from the package.json scripts. This is the plumbing command called by npm link and npm install.

npm run build
root@christian-virtual-machine:/home/christian/Downloads/speedtest-master# npm run build

> speedtest@ build /home/christian/Downloads/speedtest-master
> lerna run build

lerna notice cli v3.22.1
lerna info Executing command in 1 package: "npm run build"
lerna info run Ran npm script 'build' in 'speedtest-web' in 25.2s:

> speedtest-web@0.5.3 build /home/christian/Downloads/speedtest-master/packages/web
> webpack --env=prod --progress --profile --colors

Hash: ad2aa3d93ecefe4d5e02
Version: webpack 4.46.0
Time: 21725ms
Built at: 02/13/2021 3:11:05 PM
               Asset       Size  Chunks                         Chunk Names
     app.79a3bdd9.js    158 KiB       0  [emitted] [immutable]  app
    app.7f6a55ca.css   13.3 KiB       0  [emitted] [immutable]  app
         config.json    3 bytes          [emitted]              
         favicon.ico   4.19 KiB          [emitted]              
    icon-128x128.png   3.25 KiB          [emitted]              
    icon-144x144.png   3.55 KiB          [emitted]              
    icon-152x152.png   3.68 KiB          [emitted]              
    icon-192x192.png   4.43 KiB          [emitted]              
    icon-256x256.png   5.56 KiB          [emitted]              
    icon-512x512.png   10.7 KiB          [emitted]              
  icons.0d7923fc.svg   5.13 KiB          [emitted]              
icons.20db5f72.woff2   4.03 KiB          [emitted]              
  icons.2936e8bb.eot   7.93 KiB          [emitted]              
 icons.9b44de87.woff   4.85 KiB          [emitted]              
  icons.bf33ee4c.ttf   7.77 KiB          [emitted]              
          index.html   9.26 KiB          [emitted]              
       manifest.json  768 bytes          [emitted]              
  worker.d803dd7c.js   76.4 KiB          [emitted] [immutable]  
Entrypoint app = app.7f6a55ca.css app.79a3bdd9.js
[184] ./src/js/worker.js 101 bytes {0} [not cacheable] [built]
      [] 4902ms -> [] 7504ms -> [] 1769ms -> [] 1959ms -> factory:683ms building:6114ms dependencies:162ms = 23093ms
[186] ./src/css/gauge.scss 39 bytes {0} [built]
      [] 4902ms -> factory:2199ms building:5305ms = 12406ms
[187] ./src/css/app.scss 39 bytes {0} [built]
      [] 4902ms -> factory:2199ms building:5305ms = 12406ms
[191] (webpack)/buildin/global.js 472 bytes {0} [built]
      [] 4902ms -> [] 7504ms -> [] 1769ms -> [76] 1607ms -> [2] 697ms -> factory:0ms building:2ms = 16481ms
[390] ./build/app.js + 17 modules 54 KiB {0} [built]
      | ./build/app.js 171 bytes [built]
      |     factory:868ms building:4034ms = 4902ms
      | ./src/js/app.js 3.37 KiB [built]
      |     [] 4902ms -> factory:2199ms building:5305ms = 12406ms
      | ./src/js/app/ui.js 9.65 KiB [built]
      |     [] 4902ms -> [] 7504ms -> factory:222ms building:1547ms dependencies:1150ms = 15325ms
      | ./src/js/app/navigation.js 3.29 KiB [built]
      |     [] 4902ms -> [] 7504ms -> factory:222ms building:1547ms dependencies:1150ms = 15325ms
      | ./src/js/app/userSettings.js 1.97 KiB [built]
      |     [] 4902ms -> [] 7504ms -> factory:222ms building:1547ms dependencies:1150ms = 15325ms
      | ./src/js/app/speedtest.js 1.08 KiB [built]
      |     [] 4902ms -> [] 7504ms -> factory:222ms building:1547ms dependencies:1150ms = 15325ms
      | ./src/js/app/views/history.js 9.74 KiB [built]
      |     [] 4902ms -> [] 7504ms -> factory:222ms building:1547ms dependencies:1150ms = 15325ms
      | ./src/js/app/views/settings.js 4.64 KiB [built]
      |     [] 4902ms -> [] 7504ms -> factory:222ms building:1547ms dependencies:1150ms = 15325ms
      | ./src/js/app/views/share.js 4.32 KiB [built]
      |     [] 4902ms -> [] 7504ms -> factory:222ms building:1547ms dependencies:1150ms = 15325ms
      | ./src/js/utils/dateFormat.js 826 bytes [built]
      |     [] 4902ms -> [] 7504ms -> [] 1769ms -> factory:1907ms building:180ms dependencies:590ms = 16852ms
      | ./src/js/worker/step.js 96 bytes [built]
      |     [] 4902ms -> [] 7504ms -> [] 1769ms -> factory:1907ms building:180ms dependencies:590ms = 16852ms
      | ./src/js/app/results.js 1.93 KiB [built]
      |     [] 4902ms -> [] 7504ms -> [] 1769ms -> factory:1635ms building:324ms dependencies:323ms = 16457ms
      | ./src/js/app/workerService.js 9 KiB [built]
      |     [] 4902ms -> [] 7504ms -> [] 1769ms -> factory:1635ms building:324ms dependencies:323ms = 16457ms
      | ./src/js/utils/bytes.js 472 bytes [built]
      |     [] 4902ms -> [] 7504ms -> [] 1769ms -> factory:1107ms building:404ms dependencies:569ms = 16255ms
      | ./src/js/utils/semver.js 1.04 KiB [built]
      |     [] 4902ms -> [] 7504ms -> [] 1769ms -> factory:1107ms building:404ms dependencies:569ms = 16255ms
      |     + 3 hidden modules
    + 388 hidden modules
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html 1.72 KiB {0} [built]
        factory:65ms building:55ms = 120ms
    [2] (webpack)/buildin/global.js 472 bytes {0} [built]
        [0] 120ms -> [1] 1385ms -> factory:850ms building:25ms = 2380ms
    [3] (webpack)/buildin/module.js 497 bytes {0} [built]
        [0] 120ms -> [1] 1385ms -> factory:850ms building:25ms = 2380ms
    [4] ./src/views/alerts.html 678 bytes {0} [built]
        [0] 120ms -> factory:1350ms building:35ms = 1505ms
    [5] ./src/views/about.html 3.69 KiB {0} [built]
        [0] 120ms -> factory:1350ms building:35ms = 1505ms
    [6] ./src/views/history.html 1.23 KiB {0} [built]
        [0] 120ms -> factory:1350ms building:35ms = 1505ms
    [7] ./src/views/settings.html 1.82 KiB {0} [built]
        [0] 120ms -> factory:1350ms building:35ms = 1505ms
    [8] ./src/views/share.html 1.71 KiB {0} [built]
        [0] 120ms -> factory:1350ms building:35ms = 1505ms
    [9] ./src/views/speedtest.html 1.6 KiB {0} [built]
        [0] 120ms -> factory:1350ms building:35ms = 1505ms
        + 1 hidden module
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html 1.72 KiB {0} [built]
        factory:58ms building:57ms = 115ms
    [2] (webpack)/buildin/global.js 472 bytes {0} [built]
        [0] 115ms -> [1] 1373ms -> factory:611ms building:27ms = 2126ms
    [3] (webpack)/buildin/module.js 497 bytes {0} [built]
        [0] 115ms -> [1] 1373ms -> factory:611ms building:27ms = 2126ms
    [4] ./src/views/alerts.html 678 bytes {0} [built]
        [0] 115ms -> factory:1337ms building:36ms = 1488ms
    [5] ./src/views/about.html 3.69 KiB {0} [built]
        [0] 115ms -> factory:1337ms building:36ms = 1488ms
    [6] ./src/views/history.html 1.23 KiB {0} [built]
        [0] 115ms -> factory:1337ms building:36ms = 1488ms
    [7] ./src/views/settings.html 1.82 KiB {0} [built]
        [0] 115ms -> factory:1337ms building:36ms = 1488ms
    [8] ./src/views/share.html 1.71 KiB {0} [built]
        [0] 115ms -> factory:1337ms building:36ms = 1488ms
    [9] ./src/views/speedtest.html 1.6 KiB {0} [built]
        [0] 115ms -> factory:1337ms building:36ms = 1488ms
        + 1 hidden module
Child mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/sass-loader/dist/cjs.js!src/css/app.scss:
    Entrypoint mini-css-extract-plugin = *
    [0] ./src/css/icons/icons.eot 64 bytes {0} [built]
        [1] 3794ms -> factory:1343ms building:157ms = 5294ms
    [1] ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/css/app.scss 15.4 KiB {0} [built]
        factory:135ms building:3659ms = 3794ms
    [4] ./src/css/icons/icons.woff2 66 bytes {0} [built]
        [1] 3794ms -> factory:1343ms building:157ms = 5294ms
    [5] ./src/css/icons/icons.woff 65 bytes {0} [built]
        [1] 3794ms -> factory:1343ms building:157ms = 5294ms
    [6] ./src/css/icons/icons.ttf 64 bytes {0} [built]
        [1] 3794ms -> factory:1343ms building:157ms = 5294ms
    [7] ./src/css/icons/icons.svg 64 bytes {0} [built]
        [1] 3794ms -> factory:1343ms building:157ms = 5294ms
    [8] ./src/css/images/logo.svg 1.08 KiB {0} [built]
        [1] 3794ms -> factory:1343ms building:157ms = 5294ms
        + 2 hidden modules
Child mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/sass-loader/dist/cjs.js!src/css/gauge.scss:
    Entrypoint mini-css-extract-plugin = *
    [0] ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/css/gauge.scss 369 bytes {0} [built]
        factory:8ms building:1711ms = 1719ms
        + 1 hidden module
Child worker:
                 Asset      Size  Chunks                         Chunk Names
    worker.d803dd7c.js  76.4 KiB       0  [emitted] [immutable]  main
    Entrypoint main = worker.d803dd7c.js
    [105] (webpack)/buildin/global.js 472 bytes {0} [built]
          [] 347ms -> [20] 1855ms -> [0] 38ms -> factory:32ms building:16ms = 2288ms
    [180] ./node_modules/babel-loader/lib!./src/js/worker.js + 18 modules 41.6 KiB {0} [built]
          | ./node_modules/babel-loader/lib!./src/js/worker.js 5.44 KiB [built]
          |     factory:32ms building:315ms = 347ms
          | ./src/js/utils/object.js 1.78 KiB [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/utils/request.js 1.83 KiB [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/worker/config.js 3.33 KiB [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/worker/status.js 112 bytes [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/worker/result.js 199 bytes [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/worker/test.js 1.79 KiB [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/worker/downloadTest.js 1.24 KiB [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/worker/scope.js 204 bytes [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/worker/messaging.js 860 bytes [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/worker/ipTest.js 2.74 KiB [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/worker/latencyTest.js 6.62 KiB [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/worker/uploadTest.js 3.56 KiB [built]
          |     [] 347ms -> factory:1722ms building:133ms dependencies:747ms = 2949ms
          | ./src/js/utils/uuid.js 691 bytes [built]
          |     [] 347ms -> [] 1855ms -> factory:831ms building:270ms dependencies:1ms = 3304ms
          | ./src/js/worker/abstractTest.js 4 KiB [built]
          |     [] 347ms -> [] 1855ms -> factory:627ms building:364ms dependencies:3ms = 3196ms
          |     + 4 hidden modules
        + 179 hidden modules
lerna success run Ran npm script 'build' in 1 package in 25.2s:
lerna success - speedtest-web

NPM run start: This will run a predefined command specified in the “start” property of a package’s “scripts” object.

npm run start

As you can see, (despite not providing you with the entire logging output), the speed test has started. Now, we can now access this user interface from the browser with the following URL below.

https://localhost:5080

All you need do now is to do from here is to click on “Start” as shown above. This will begin the Speed test as shown below.
Now, you can share this link with your customers and employees in order to determine the speed of their internet connection to your server.

You may additionally have to create firewall rules to permit connection (access) to this server (LAN) etc. Kindly see this article on how to disable automatic screen lock on Ubuntu Desktop with the GUI and dconf Editor.

The following values ​​are automatically checked by some speed test servers.

  • Latency: In simple terms, latency is the reaction speed of your internet connection. It is used to outline the amount of time it takes for a packet to transfer to its destination.
  • Jitter: This is the delay that varies over time when the signal wanes or jitters.
  • Download Speed: The download speed or bandwidth of an Internet connection is most important. It shows how quickly data is being downloaded from the Internet. The higher the speed or bandwidth of a connection (in megabits or gigabits per second), the better. Activities such as listening to music on Spotify, downloading large files, or streaming videos on Netflix all require you to download data.
  • Upload Speed: The upload speed has also become an important parameter for internet connections. In contrast to the download speed, it says how quickly data can be uploaded from a computer to the Internet. While downloading information is more common, some online activities need data to travel in the opposite direction. Sending emails, playing live tournament-style video games, and video calling a friend to require fast upload speeds for you to send data to someone else’s server.
  • Ping Value: The ping value indicates the time that a data packet needs to travel between the sender and receiver (for example from an employee device to your company server (self-hosted speed test)). The lower this value, the better. Most speed test displays this value in milliseconds. The ping value is particularly important for video chats or online games.
Latency and ping are often used interchangeably, they are a little bit different. Ping refers to the signal sent from the device to the server, latency is the time it takes for the ping to return to the device.

How to achieve the optimal speed test: The Internet speed on your computer with which you are performing the speed test can be influenced by numerous factors. Applications that are open during the Internet speed test, such as e-mail or security programs (firewall, anti-virus program), play an important role. Such programs can negatively influence the measurement result, especially if they run unnoticed in the background.

The configuration of the computer used and other hardware used such as modem or WLAN router can also influence the measurement result. In order to obtain the most accurate result possible, your own computer should be connected directly to the modem or WLAN router for the speed test using a LAN cable.

With a wireless connection via WLAN, in addition to the performance of the devices used, the distance or apartment walls between the computer and the WLAN router can lead to a loss of speed. You should take these factors into account when installing WLAN at home.

I hope you found this blog post helpful. If you have any questions, please let me know in the comment session.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x