Tips on implementing a webserver

Hi, I am using a verdim imx8m SOM with Yavia Carrier board.

I have written a C++ application container and now I intend to implement a webserver for it.

what is the recommended way to go? do I use multiple application containers? one for the application and one for the server in python? or should I just go with implementing a server in C++?

the application is not very cpu intensive and many resources are free. If I go with multiple containers option, how do i establish communication between the two? currently I am using vscode extension v1 experimental version. how can I transfer my signle container application to a multiple container application?

Greetings @geopaxpvtltd,

This is a very situation dependent question, and ultimately the answer is “it depends”. But let me try and share my own thoughts and maybe it can help with your decision.

what is the recommended way to go? do I use multiple application containers? one for the application and one for the server in python? or should I just go with implementing a server in C++?

So the choice of single or multiple containers, depends on how you want to architect this system. With a single container you have the following to consider:

  • Everything will be in a single container, arguably easier to maintain
  • Don’t have to worry about inter-container communications
  • If you want to change only one part of the system (i.e application or webserver), then you have to change your single container which could affect both parts even though you’re only changing one part.

With a multi-container system you have this to consider:

  • Multiple containers so possible more to manage, though the source code is effectively the same.
  • Need to communicate between containers, though this isn’t terribly complex as I will show later
  • With multi-containers you have the advantage of isolation between the various parts of your system. For example, if you only need to change the back-end application of your system, you can only change the respective container while keeping the web-server container up and running. This only isolates changes to certain parts of your stack instead of doing changes that could potentially affect the entire stack if everything was in a single container.

Now I’ve only skimmed the surface here with regards to single vs multi-container and some of this might not even apply to your case. There’s various blogs/articles out there going over in more detail this topic like this: Multi container apps | Docker Documentation

In the end I wouldn’t say there’s an absolute right or wrong approach as I said earlier, it depends.

As for what language you should do the webserver in, well this is kind of personal preference along with your own technical requirements.

If I go with multiple containers option, how do i establish communication between the two?

There are various ways to communication between containers, we have an article here that goes over some of them: Using Multiple Containers with TorizonCore | Toradex Developer Center

But in general between containers you can:

  • Share directories
  • Share linux sockets
  • Share network ports
  • Share network stacks

currently I am using vscode extension v1 experimental version. how can I transfer my signle container application to a multiple container application?

This is a bit inconvenient with our V1 extension. At the moment you’d have to develop each container in it’s own separate project. Then coordinate them outside of VSCode manually. Our new V2 extension does have the option to create multi-container projects in a single project for easier coordination.

This is probably a lot to digest, but I hope I helped clarify some of the options and choices you have available to you.

Best Regards,
Jeremias

Hi @geopaxpvtltd ,

"Could you please provide more details about your goals? Why do you need a web server? What kind of application are you planning to run? Why do you need to implement a web server when you can use an open-source implementation?

@jeremias.tx @alex.tx

Thanks a lot for this information! i shall look into it.

my application is that I am designing a portable iot based product for which I have the hosts connecting to it via bluetooth, wifi and serial.

the webserver is supposed to kind of a dashboard to show stats / control the main application.

I am familiar with linux sockets and file descriptors that I use for serial ports and a local tcp server inside the application.

the term webserver I used was in a generic sense.

it would be great to be able to use an open source approach if you would be kind enough to guide me to an example implementation with C++?

I am a single developer and a single person team. so managing multiple containers would be difficult.

Most open-source web servers are implemented in either C or C++. Since they’re open source, you can download and use their source code. For instance, the source code for Lighttpd can be downloaded here. You can Google the source code for each web server from the list in the link I’ve posted.
Some web servers implemented in C++:

1 Like

Thank you for your input!

I will try to implement these.

just one more thing, do these work similarly to using an external library, eg libgpiod-dev, or do I need to copy the source code and include it in my cmakelists file to be built with the application?

just one more thing, do these work similarly to using an external library, eg libgpiod-dev, or do I need to copy the source code and include it in my cmakelists file to be built with the application?

Well this probably depends with each project. You’ll need to look through each project’s documentation and examples to figure out how they’re meant to be used. To clarify, we don’t advocate for any of these projects specifically, they’re just various open source project we found online. You are free to use any open source project you’d like to implement your web server.

Best Regards,
Jeremias

Thank you for the guidance.

I have started using Poco to test a sample server, however, I am unable to access the port of the application

#include <Poco/Net/HTTPServer.h>
#include <Poco/Net/HTTPRequestHandler.h>
#include <Poco/Net/HTTPRequestHandlerFactory.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>
#include <Poco/Net/ServerSocket.h>
#include <Poco/Util/ServerApplication.h>

#include <Poco/Net/HTTPServerParams.h>
#include <Poco/Net/ServerSocket.h>
#include <Poco/Net/HTTPServer.h>
#include <Poco/Net/HTTPRequestHandlerFactory.h>

#include <Poco/Path.h>
#include <Poco/URI.h>
#include <Poco/Exception.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>
#include <Poco/Net/HTTPRequestHandler.h>

#include <Poco/Net/HTTPServerParams.h>
#include <Poco/Net/ServerSocket.h>
#include <Poco/Net/HTTPServer.h>
#include <Poco/Net/HTTPRequestHandlerFactory.h>
#include <Poco/Net/HTMLForm.h>
#include <Poco/Net/PartHandler.h>
#include <Poco/NullStream.h>
#include <Poco/StreamCopier.h>

#include <Poco/Net/FilePartSource.h>
#include <Poco/Net/StringPartSource.h>
#include <Poco/Net/PartSource.h>

#include <fstream>

#include "../Definitions.h"

using namespace Poco::Net;
using namespace Poco::Util;
using namespace std;

class MyRequestHandler : public HTTPRequestHandler
{
public:
    void handleRequest(HTTPServerRequest &request, HTTPServerResponse &response)
    {
        if (request.getURI() == "/api/data")
        {
            // handle API request
            response.setContentType("application/json");
            ostream &ostr = response.send();
            ostr << "{"
                 << "\"temperature\": " << 23.5 << ","
                 << "\"humidity\": " << 48.2 << ","
                 << "\"pressure\": " << 1013.1
                 << "}";
        }
        else
        {
            // serve static files
            string filename = "/path/to/your/www/directory" + request.getURI();
            ifstream file(filename);
            if (file.good())
            {
                response.sendFile(filename, "text/html");
            }
            else
            {
                response.setStatus(HTTPResponse::HTTP_NOT_FOUND);
                response.send() << "Not found";
            }
        }
    }
};

class MyRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
    HTTPRequestHandler *createRequestHandler(const HTTPServerRequest &)
    {
        return new MyRequestHandler;
    }
};

class MyServerApp : public Poco::Util::ServerApplication
{
protected:
    int main(const std::vector<std::string> &args) override
    {
        // Set server parameters
        HTTPServerParams *pParams = new HTTPServerParams;
        pParams->setMaxQueued(100);
        pParams->setMaxThreads(16);

        // Set-up a HTTP Server
        HTTPServer s(new MyRequestHandlerFactory, ServerSocket(8080), pParams);

        // Start the HTTPServer
        s.start();

        // Wait for the termination request
        waitForTerminationRequest();

        // Stop the HTTPServer
        s.stop();

        return Application::EXIT_OK;
    }
};

the IP address of the SOM is 192.168.0.158 port of the server is 8080.

do I need to configure some kind of access to this port in the vscode extension?

To clarify you’re accessing your web server from your application on port 8080, yes? Are both the web server and application inside the same container?

If they’re both inside the same container then they should be on the same networking stack. So you should be able to just access via localhost on port 8080, within the container. If you’re using the device IP this probably doesn’t work. By default a containers networking stack is isolated from the host system. This means it wouldn’t have the same internal IP address as the device. Again though if everything is on the same network than localhost should work.

I’d recommend familirizing yourself with how networking is handled in containers: Networking overview | Docker Documentation

Best Regards,
Jeremias

1 Like

Yes and No.

Thank you for the link. however, for this question I was able to access the server created by the application container by exposing port 8080 using the answer present at this location:

Ahh yes if you have the applications in separate containers then you need to expose the relevant ports to allow interaction between each container’s individual networking stack.

Best Regards,
Jeremias

Hello @jeremias.tx

I am trying to implement an example taken from the mongoose library which can be located at:

I am able to build the code and run the server and access the webpage however the UI doesnt show due to the fact that the server files are not being copied/mounted to the container

    devices:
      - "/dev/gpiochip4:/dev/gpiochip4"
      - "/dev/ttyACM0:/dev/ttyACM0"
      - "/dev/verdin-uart1:/dev/verdin-uart1"
      - "/dev/verdin-uart2:/dev/verdin-uart2"
    volumes:
      - "/var/run/dbus:/var/run/dbus"
      - "/var/run/sdp:/var/run/sdp"
      - "/home/ha-01/GeopaxApp/src/webserver:/webserver"

I am using this docker compose file to mount the volume containing the webserver files.

the folder webserver referred to here contains another folder named web_root.

Issue is that the mounted volume is unable to access the files as shown by the following docker commands:

ha-01@HA-01-PC:~/GeopaxApp$ docker exec -it 439d676cc2f5 ls -l /webserver
total 4
drwxr-xr-x 2 root root 4096 Jun 21 06:20 web_root
ha-01@HA-01-PC:~/GeopaxApp$ docker exec -it 439d676cc2f5 ls -l /webserver/web_root
total 0

from the above, it can be seen that the sub-folder named web_root is found but the files arent being found.

the source folder contains the requisite files as evident from:

ha-01@HA-01-PC:~/GeopaxApp/src/webserver/web_root$ ls
bundle.js  components.js  history.min.js  index.html  main.css  main.js

Please guide.

Hi @geopaxpvtltd !

Seems like you are mixing some concepts.

In your docker-compose.yaml excerpt, you have some target (Toradex module) related stuff (e.g. /dev/verdin-uart1) and host stuff (the /home/ha-01/GeopaxApp/src/webserver).

There is no (simple) way the container running on your PC (or on your module) would have access to both at the same time.

Having said that, getting started with containers can be indeed confusing.

Therefore, I would like to recommend this Docker Essentials course from Udemy: https://www.udemy.com/course/docker-essentials/. This helped me a lot when getting started with containers :slight_smile:

Also, Toradex has some on-demand presentations related to containers that might help you as well: Toradex | Embedded Computing Solutions - Webinars

Best regards,

1 Like

Okay, I think I get it now. I am taking the udemy course.

the container is actually running on the SOM. so if the folder is present in the SOM, only then it will be shared with the application container.

I found the files i made inside the container inside the SOM as well.

this leads me to my question, the server files are located on the host machine. do I need to manually copy those over to the SOM? can it be done automatically via the ApolloX extension when the binaries are copied over to the SOM inside the container? I am asking this because I want these files to be packaged with the container so they can be used by the application.

do I need to manually copy those over to the SOM? can it be done automatically via the ApolloX extension when the binaries are copied over to the SOM inside the container? I am asking this because I want these files to be packaged with the container so they can be used by the application.

Depends on your design. Do you want the files to live outside of the container? In that case yes you have to deploy the files to the device so that the container can bind-mount these in as a volume.

If you want these files to live inside the container you can modify the Dockerfile in your ApolloX project to copy files into the container, similar to how your application binary/files get copied into the container. In this way the files will be baked into the container by default. Details on this aspect of Dockerfiles can be seen here: https://docs.docker.com/engine/reference/builder/#copy

Best Regards,
Jeremias

1 Like

so the dockerfile can be modified manually? it is not automatically generated by the extension?

P.S. I was able to copy the files and server is running as expected. But my question still stands, is it supposed to be done manually with ApolloX?

so the dockerfile can be modified manually? it is not automatically generated by the extension?

The Dockerfile is automatically generated but you are allowed to modify it manually as well. This only applies to ApolloX, in the V1 extension any manual change would be overridden.

Best Regards,
Jeremias

1 Like

Hello @geopaxpvtltd ,
Were you able to solve your issue?

Best regards,
Josep

Yes @josep.tx.

Thank you for asking. It was mainly due to my lack of understanding of docker. the Udemy course helped a lot.

Best Regards,
Hassan.

1 Like