Maxdaemon Framework

Maxdaemon is a file-based web application server framework. It comprises a fast, lightweighted HTTP server with three kinds of CGI interfaces, a run-time system with showcase applications, a web server manager with a web browser surface to manage files, content, design and applications, a web server platform, as well as a development, test, integration, distribution and production environment.

The framework can be configured for various purposes, such as connecting Maxdaemon hosts over a network, and is specifically designed as a development and production environment for web applications written in Perl, as the HTTP server and the WebServer library are implemented in Perl, too.

Manual Scope

This manual is an overview of the use of Maxdaemon with Maxscape. It is neither comprehensive nor is it complete. You'll find the general Maxdaemon manual at Maxdaemon.org.

HTTP Server

An HTTP daemon is an interesting program. With the client/server network model a client computer sends a request to a server host that then returns a response back to the client. Graphical web browser clients and HTTP servers serving HTML documents, that is what we call the world wide web.

A client request has a protocol scheme (http, https, ..), points to a location on the server's file system and consists of request headers, request method (get, post, ..), form or multi-part data, the CGI (Common Gateway Interface) query string a.s.o.

Uniform Resource Locator: <scheme>://<FQDN>:<Port>/<file path><path info>?<query string>

A server response is generated by the means of the request parameters and the MIME type of the location that is pointed to by the file path. If the file path is a text, HTML, CSS, Javascript, image, audio, video, etc. file, this file is send back to the client.

In case of a request for an executable program, the HTTP daemon executes that CGI program, passing the parameters via the CGI interface, and then returns the dynamically generated content back to the client.

The generic concept of the CGI interface allows the HTTPD to communicate with application processes via program call parameters, environment variables and the interprocess communication using Unix Domain and TCP/IP sockets.

CGI, SCGI and DCGI Interfaces

The HTTP server implements three kinds of CGI interfaces for interprocess communication between the HTTP daemons and the application processes. The actual used CGI interface is transparent to the application code, because it uses the same client side of the CGI protocol.

CGI Interface

The CGI interface implements a fork/exec/pipe mechanism. An application program is executed once and the output is send to back to the HTTPD's client. The application program can be coded in any language and the HTTP server doesn't have to be restarted after application code changes.

CGI programs located anywhere below the document root directory are executed by the HTTPD without any further configuration. Well, the disadvantage of this interface is that it is simply to slow for big applications.

SCGI Interface

Applications using the SCGI interface are running within process daemons. The CGI's fork/exec mechanism is replaced by daemon that communicates with the HTTPD via Unix Domain or TCP/IP sockets. This has the advantage, that applications coded in an interpreter language, don't have to be recompiled and that database connections don't have to be (re)established on each request.

To use the SCGI interface place an SCGI script below the server's document root and configure it with an 'AddScript' directive in the server's configuration file. The usage is similar to that of FastCGI. The application process is launched by the HTTP daemon on request.

# Configuration file: /maxdaemon/server/<app server>/etc/maxdaemon<-version>.conf
=================================================================================
...
# TCP/IP port 8092 or UNIX domain socket name with 3 preforked SCGI workers.
AddScript scgi-script $MaxdaemonHome/server/<app server>/htdocs/app.scgi 8092 3
...

# Exemplary SCGI script: /maxdaemon/server/<app server>/htdocs/app.scgi
=======================================================================
...
my $Process = Maxdaemon::Process->new ();
my $SCGI_Interface = Maxdaemon::Daemon::SCGI_Client->new;
...
while (my $Client = $SCGI_Interface->accept)
{
  print $Process->execute;
}

DCGI Interface

Via the DCGI interface applications can directly be integrated within the HTTPD. This is similar to mod_perl with Apache, but without a Perl/C adapter, since the HTTPD is written in Perl. Because the inter-process communication between the daemon and the CGI application is dropped, the DCGI interface is pretty fast. A disadvantage is that if the application fails the daemon fails, too.

To integrate an application module, you can directly place an entry function or method call in the 'executeViaDCGI_Interface' method of the 'Maxdaemon::Daemon::HTTPD' class, though this is only recommended for applications that are part of the standard distribution.

A next place is the 'Main' method of the 'Maxdaemon::Module::Main' class. Within this method the runtime objects ($Process, $Page, $CGI, $User, ...) are already defined and can directly be used within application modules. This is only recommended for applications that are part of the standard distribution, because future distributions will override the 'Maxdaemon::Module::Main' class file.

The best way is to use the generic module plug-in mechanism. The plug-in mechanism looks for the presence of a 'ServerApplication.pm' file in the 'lib' directory of the application server and then calls the function named 'ServerApplication' of the 'Maxdaemon::<AppServer>' class, where <AppServer> is the name of the application server, defined in the configuration file.

Because the daemon creates the same environment as with CGI scripts, CGI applications works with DCGI like with the CGI interface.

# Application module: /maxscape/server/<AppServer>/lib/ServerApplication.pm:
=============================================================================

package Maxdaemon::<AppServer>;
use strict;

sub ServerApplication {
  my ($HTTPD, $Request, $Connection, $Configuration) = @_;

  return Maxdaemon::<AppServer>->new->MyApp ($HTTPD, $Request, $Client, $Configuration);
}

sub new {
  my $class = shift;
  my %parameter = @_;
  my $this = {};
  bless $this, $class;
  ...
  return $this;
}

sub MyApp {
  my $this = shift;
  my ($HTTPD, $Request, $Connection, $Configuration) = @_;
  ...
  return ($Content, $Header); # scalar and hash references
}
...

Configuration and Operation Modes

The HTTP daemon can be configured to run in various modes and supports quite a lot of features. Content and applications are stored on a standardized file system structure following Unix conventions. Each application server has its own indepandant directory tree. An application server consists of one ore more processes communicating with the HTTP server via the CGI interfaces. The HTTP server needs to be configured to run the process scripts.

The configuration files are Apache style and to configure the server, as well as application code. The main HTTPD configuration files are located below '~/etc'. The configuration file version is used to reflect the various network configuration possibilities. For example does '~/etc/maxdaemon.conf' configure the HTTPD to listen to the IP 127.0.0.1 on ports 8000 (HTTP) and 8001 (HTTPS). For more information see: Maxdaemon Configuration.

You can eighter use the 'sp' (set project) script to set the environment or pass the configuration as parameters to the Maxdaemon start/stop script. Use the 'sp' script to permanetly set up the configuration file version and the shell environment, e.g.:

# Use the configuration file: $MAXDAEMON_HOME/etc/maxdaemon-fqdn.conf:
> sp -c fqdn
> maxdaemon -vv restart

SSL Certificates Creation for Maxdaemon

To set up a name-based virtual SSL host, the required SSL certificates needs to be created. See the 'certificate' man pages, the 'certificate' HTML online manual and the SSL Certificates Creation chapter. for details. Here is an example with two name-based virtual hosts. The 'createAppServer' shell copies the 'Template' server's certificates by default, so you'll get a warning from Firefox: "The certificate is not valid for the name <virtual host name>.").

The creation of several name based SSL hosts is a bit tricky, as you have to define the complete list (subjectAltName) of all virtual hosts running on your server. 'subjectAltName' is the list of all virtual site names in the form of e.g. 'URI:w1.local.net,URI:w2.local.net,URI:w3.local.net'.

Example to create a certificate for a single host (even here use the '-a' option):

> certificate -w Example -a URI:example.local.net example.local.net

Example with two name-based virtual hosts:

> certificate -w <unique server name 1> -a "URI:<virtual host name 1>,URI:<virtual host name 2>" -s 00 <virtual host name 1>
> certificate -w <unique server name 2> -a "URI:<virtual host name 1>,URI:<virtual host name 2>" -s 01 <virtual host name 2>

Creation of certificates for the HTTPD, the 'Test' and the 'Template' servers:

 > certificate -a <subjectAltName> -s 00 <your host name>
 > certificate -w Test -a <subjectAltName> -s 01 <Test's virtual name>
 > certificate -w Template -a <subjectAltName> -s 02 <Template's virtual name>

Debug Messages, Access and Error Logs

Maxdaemon provides extensive debugging options to follow the program execution flow. The printed package name and the line number of a debug message can be used to find the corresponding source file and the surrounding code snippet. Thus it is easy to find and to make changes to the code. Debug messages are enabled by passing debug options to the 'maxdaemon' start script and are printed to STDERR, until the '-l' option is provided.

You can use the Tcsh alias 'de' to watch the error and 'da' to watch the access logs, defined in the 'maxdaemon.conf' files. Access logs are formated similar to the Apache style.

You can easily use this facility to print your own debug messages by adding them to the message hashes and call the related log functions. See the man pages or the on-line manual for more details.

> maxdaemon -vv -sl restart    # turns on debug messages on STDERR
> maxdaemon -vv -sl -l restart # turns on debug messages on the related error log
> de                           # Tcsh alias to watch the error logs
Reload Maxdaemon configuration: /opt/maxdaemon/daemon/etc/maxdaemon-maxdaemon.local.net.conf.
Restarting Maxdaemon...
<Launch-->>
<maxdaemon.pl: 119> Daemon launched.................: /opt/maxdaemon/daemon/sbin/maxdaemon.pl
<Configuratio: 129> Computer hostname (FQDN, IP)....: maxdaemon.local.net, 192.168.0.2.
<HTTPD.pm    : 145> Listening to name or IP.........: http://maxdaemon.local.net:80/
<HTTPD.pm    :2711> Set daemon GID to...............: maxdaemon (8002).
<HTTPD.pm    :2728> Set daemon UID to...............: maxdaemon (8002).

> maxdaemon -vv -sl restart
> da                           # Tcsh alias to watch the access logs
==> /opt/maxdaemon/daemon/var/logs/maxdaemon-access.log <==
192.168.0.1 - - [09/Apr/2018:19:08:51 +0000] "GET / HTTP/1.1" 200 168953 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0"

However what you do, there are not enough debug messages for all situations. So, you might want to use the shortcut 'pe ("");' instead of the more verbose 'print STDERR ("");' statement.

Web Sockets

WebSockets are a very interesting technology, because a server can push messages onto a client without prior request. WebSocket clients can receive server messages, instead of polling the server for replies. The server processes have to keep track of the client's sockets. This suggests an event driven model.

Maxdaemon's web socket support is new and experimental (set $::WEB_SOCKETS_SUPPORT=1 in 'Globals.pm' to enable). Notably, the process and connection management is basic and there is only a DCGI implementation, because SCGI scripts can't be upgraded to WebSockets, by now.

So far, the HTTPD simply forks itself, and the child process keeps track of the connection. If in the application server's 'ServerApplication.pm' file the function 'WebSocketCallback' is defined, then this function is executed within the WebSocket loop. Only text messages are implemented.

Here's the 'WebSocketCallback' of the MaxChat server that implements a little experimental WebSocket chat. The function writes a received message to a file and sends an 'ALRM' signal to other chat processes, which in return sends that message to their WebSocket clients. Its just a rough beginning...

File: $::MAXDAEMON_HOME/server/WebSocket/lib/ServerApplication.pm
==================================================================

sub WebSocketCallback {
  my $On = shift;
  my $WebSocket = shift;
  my $ClientMessage = shift;
  ...
  my $WebChat = Maxdaemon::WebSocket->new();

  if ($On eq 'OnMessage') {
    ...
  } elsif ($On eq 'OnSignal') {
    ...
  } elsif ($On eq 'OnClose') {
    ...
  } elsif ($On eq 'OnTimeout') {
    ...
  }
  return $ServerMessage;
}

Chat Mode

The 'Chat Mode' is merely an example how to implement a specific communication protocol. To communicate in 'Chat Mode', Maxdaemon needs to be installed on both ends. The 'minclient' script in interactive mode can then be used to send SSL encrypted messages to the other side, which can then be watch via the daemon's error log. Obviously this isn't very comfortable, but just a beginning and quite secure, because of the end to end SSL encryption. Sent and received messages should be placed in one window and a usable send message input shell should be provided.

Compatibility with Apache/FastCGI

If applications follow a few rules, it is no issue to run them with Maxdaemon, as well as with the Apache. So, you can develop and test with Maxdaemon and run your production server with an Apache/FastCGI configuration.

Runtime System

Normally, the runtime system comprises two HTTP daemon processes, one listening for HTTP and one for HTTPS requests and several application processes, depending on the configuration of the installation. The daemon and the applications processes communicate mainly via the CGI, DCGI or SCGI interfaces with each other. You can run as many HTTPDs as you like in parallel provided they are assigned to different ports or Ethernet interfaces.

Start/Restart/Stop Scripts

In the '/sbin' folder you'll find the Maxdaemon start/stop scripts. To turn on the debug mode use the '-vv' option, e.g. to find out on which IP and port the daemon is running. Provide the '-sl' option also, to easily find the corresponding lines in the source file.

To setup a wanted configuration, namely the Perl installation and the configuration files, the 'sp' shell script is quite useful to quickly set the environment.

> sp -p OSperl -c 127.0.0.1-8000-8001 # Perl installation of the OS
> maxdaemon -vv start
> maxdaemon stop
> exit
> sp -p optperl -c max                # Perl installation below '/opt'
> maxdaemon -vvvvv -sl restart
> maxdaemon stop
> exit
> sp -p maxperl -c max                # Perl installation below '/opt/maxdaemon'
> maxdaemon restart

Maxdaemon Configuration

Maxdaemon can be configured to run in various modes. The main configuration files are located below the '~/etc' directory and include the application server configuration files, which are places in their '~/server/<app server>etc' folders. Some configuration options are directly defined in the Perl modules (e.g. Globals.pm).

Configuration files have a version to distinguish the modes. You can either pass a configuration file directly to the daemon with the '-c' option or you can use the 'sp (set project)' script to set a wanted shell environment. The 'sp' shell script is meant to be adapted by you to set wanted shell environments.

# Set the environment to the Perl installation provided by the OS.
> sp -p OSperl

# Start/stop the server.
> maxdaemon -vv restart
<Launch-->>
  Daemon launched.................: /opt/maxdaemon/daemon/sbin/maxdaemon.pl
  Listening to name or IP.........: http://127.0.0.1:8000/
<Launch-->>
  Daemon launched.................: /opt/maxdaemon/daemon/sbin/maxdaemon.pl
  Listening to name or IP.........: https://127.0.0.1:8001/

> maxdaemon stop
# Exit the environment.
> exit

# use '/etc/maxdaemon-fqdn.conf'
> sp -c fqdn

> maxdaemon -vv restart
<Launch-->>
  Daemon launched.................: /opt/maxdaemon/daemon/sbin/maxdaemon.pl
  Listening to name or IP.........: http://www.local.net:8000/
<Launch-->>
  Daemon launched.................: /opt/maxdaemon/daemon/sbin/maxdaemon.pl
  Listening to name or IP.........: https://www.local.net:8001/

The default configuration file is 'maxdaemon.conf' configures the HTTPD to listen to the IP address '127.0.0.1' and the the ports 8000 (HTTP) and 8001 (HTTPS). The directives are shortly described within the file.

The name-based version 'maxdaemon-fqdn.conf configures the daemon to listen to the FQDNs of the computer's first Ethernet interface, on port 8000 for HTTP and on port 8001 for HTTPS requests. If you set the ports to 80/443 you must execute the start script from the UNIX root account.

The daemon can also be configured to listen to other Ethernet interfaces by passing the IP to the maxdaemon start script (-n, -i, -b options).

# File: \$MAXDAEMON_HOME/etc/maxdaemon-<configuration file version>.conf
=======================================================================

> me # tcsh alias for 'cd \$MAXDAEMON_HOME/etc'
> vi maxdaemon-<configuration file version>.conf
 ...
  HostName        - HostName is the HTTP address to listen to.
  AppServerName   - Unique application server name
  NameVirtualHost - One entry for each virtual host
  VirtualHost     - Virtual host name with port.
  ServerName      - Virtual Host name.
  Port            - Port to listen to.
  HTTPPort        - Port for HTTP requests.
  SSLPort         - Port for HTTPS requests.
  AddScript       - SCGI process with Port/socket
  User            - User under which Maxdaemon runs
  Group           - Group under which Maxdaemon runs
 ...
 include         - Includes an application server configuration file
 ...

Application Server

The unique 'AppServerName' denotes the complete set of entities (content, modules, files, virtual host name, database instances, etc.) belonging to that server. They live in a standardized directory tree containing all directories and files unique to that application (documents, scripts, access, error logs, PID files, ..).

The files of an application server are generally located below the '~/server' folder (see Server and Application Directory Structure) and have a unified directory structure.

<installation folder>/maxdaemon/daemon/server/MyApp
  bin      -  Scripts.
  cgi-bin  -  CGI scripts.
  etc      -  Configuration files.
  htdocs   -  'DocumentRoot' folder (e.g. scripts).
  lib      -  Libraries.
  man      -  man pages.
  tables   -  Database tables.
  var      -  Files that changedes (e.g. logs).

The Perl code of web applications are best executed within separate application processes. The application server daemons communicate with the HTTP deaemons via their CGI interface using fork/exec, resp. TCP/IP or UNIX domain sockets. So, an application server implements the generic functionality to provide the basic objects and fuctions to execute the application code and to operate the server.

Application Server Creation

To create/remove an application directory tree the 'createAppServer' shell script is provided. The script takes the 'Template' server as a template, therefore you can change the 'Template' app server to generate your desired requirements and design.

> createAppServer create <AppServerName> <VirtualHostName> <HTTP port> <HTTPS port> 
# Example (creates an application server below '~/server/Example'):
> createAppServer create Example example.local.net 80 443

Follow the instructions printed by the script. After this, the newly created app should be accessible via a browser. The most important files and folders are:

# App server configuration file:
~/server/<AppServerName>/etc/maxdaemon-<version>.conf
# CGI script:
~/server/<AppServerName>/htdocs/www.cgi
# SCGI script:
~/server/<AppServerName>/htdocs/www.scgi
# Index page template:
~/server/<AppServerName>/htdocs/www.phtml
# App server Perl modules:
~/server/<AppServerName>/lib/ServerApplication.pm
# App server default index element:
~/server/<AppServerName>/htdocs/element/Index.phtml
# Page tempate elements folder:
~/server/<AppServerName>/htdocs/template/

If properly configured, the app process should display a short description on how to work with your newly created app. You can display this description also via the 'Template' app, of course.

Application Server Configuration

The configuration files (maxdaemon-<version>.conf) of an application process are located below the application's 'etc' folder. The <version> must match the <version> of the main configuration file. Use the directives to configure the application process:

  • VirtualHost - Virtual host name with port.
  • ServerName - Virtual host name (FQDN).
  • Port, HTTPPort and SSLPort - Must be the HTTPD's values.
  • AddScript - SCGI process directive.
  • ...

The application process configuration file must be included in the main HTTPD's configuration file and the 'NameVirtualHost' directives have to be added, one for each 'VirtualHost' server. Note, that the 'NameVirtualHost' directives in the main HTTPD configuration file must match the 'VirtualHost' directives in the application's configuration file.

Note also, that a <virtual host name> is a FQDN (Full Qualified Domain Name, e.g. www.example.com) that cannot just be invented, but must be configured by the network configuration, either Intranet locally (e.g. (/etc/hosts, hostname, domainname) or with an Internet service provider on the Internet.

To configure an application process edit its configuration file and set the directives to the wanted values. Also, add the required directives to the main configuration file.

# Use the web surface or the following shell commands:

> ms # Tcsh alias for 'cd $MAXDAEMON_HOME/server'
> cd <AppServerName>/etc
> vi maxdaemon<-version>.conf

# File: ~/server/Example/etc/maxdaemon<-version>.conf
====================================================

<VirtualHost www.example.com:8000>
  ...
  VirtualHostName          www.example.com:8000
  ServerName               www.example.com
  AppServerName            Example
  SSL                      0
  ...
</VirtualHost>
...
<VirtualHost www.example.com:8001>
  ...
  VirtualHostName          www.example.com:8001
  ServerName               www.example.com
  AppServerName            Example
  SSL                      1
  ...
</VirtualHost>

> me # Tcsh alias for 'cd $MAXDAEMON_HOME/etc'
> vi maxdaemon<-version>.conf

# File: ~/etc/maxdaemon<-version>.conf
====================================================
...
NameVirtualHost          www.example.com:8000
NameVirtualHost          www.example.com:8001
...
include $MaxdaemonHome/server/Example/etc/maxdaemon<-version>.conf
...

SCGI scripts must be configured with an 'AddScript' directive. Make sure that the ports are unique.

# File: $MAXDAEMON_HOME/server/<virtual host name>/etc/maxdaemon-<version>.conf
===============================================================================
...
# Add a SCGI interface handler to configure a SCGI application process.
# Arguments are the 'port' and the number of process workers.

AddScript scgi-script $MaxdaemonHome/server/<AppServerName>/htdocs/app.scgi 8089 3
...

If configured properly, application processes are easily accessible via the web surface. Simply click on the scripts you want to run.

Appliction Server Start/Stop

Note, that the <virtual host name> must be configured by the network (see chapter 'Local Name-based Virtual Hosts').

> sp -p maxperl -c max
> maxdaemon -vv restart
<Launch-->>
<maxdaemon.pl: 119> Daemon launched.................: /opt/maxdaemon/daemon/sbin/maxdaemon.pl
<Configuratio: 129> Computer hostname (FQDN, IP)....: maxdaemon.local.net, 192.168.0.2.
...

To see the newly created process running, you might want to use the web surface. Go to the application process's document root and a click on the CGI resp. SCGI script. This will start the (SCGI) process, if all is configured properly.

Application Daemon Scripts

Application daemon scripts containing the process main loop are best placed below the application server's 'DocumentRoot' folder.

> ms # Tcsh alias for 'cd $MAXDAEMON_HOME/server'
> cd <AppServerName>/htdocs
> vi <script name>.scgi

# File: ~/server/<AppServerName>/htdocs/<script name>.scgi
========================================================================
...
my $SCGI_Interface = Maxdaemon::Daemon::SCGI_Client->new ();
...
while (my $Client = $SCGI_Interface->accept)
{
  my $Content = 'Hello world';

  print "Content-type: text/html$::CRLF$::CRLF" . $Content;
}

To make scripts generic and reusable encapsulate them in something like the 'Maxscape::Process' container class, then CGI/FCGI/SCGI scripts look quite similar, and need to be changed only once in a blue moon. Though an $App->run() method implementing all CGI interfaces is elegant, it is not really necessary, thereby avoiding unwanted dependencies.

# CGI, FastCGI script example:
...
while($FCGI_Request->Accept() >= 0)
{
  $Request = Maxscape::HTTP::Request->new();
  $Response = $Process->execute($Request);
  print $Response->HeaderAsString, $Response->Content;
  $Process->postProcess();
  $Process->cleanup();
}
...

If you want to integrate an existing script, you might want to start the development with the CGI interface and then change later to SCGI. You need to tweak your script to the Maxdaemon environment. E.g. exchange '#!/usr/bin/perl' with '#!/opt/maxdaemon/daemon/bin/perl' or '#!/usr/bin/env perl'.

Addressing Application Objects and Functions

The are several ways to map URIs (Uniform Recource Identifier) to control the behaviour of applications. The location of a script placed below the process document root (htdocs) is the path relative to that document root. Special applications functions can then be addressed via the CGI's QUERY_STRING, the PATH_INFO and other variables (e.g. HTTP headers):

URL:
====

scheme  net address  port  process script  path info  query string           hash tag
-------+------------------+---------------+----------+----------------------+--------
https://www.local.net:8080/user/index.scgi/Page.phtml?Element=foo&Action=bar#foobar

HTTP request and request header:
================================

GET /user/index.scgi/Page.phtml?Element=foo&Action=bar#foobar HTTP/1.1
Content-Type: text/html
Connection: keep-alive
Host: www.local.net:8080
User-Agent: Minclient
...

Application Programming and Content Generation

To separate source code and (HTML) text is always a good idea for several reasons, though it is sometimes not completely possible. If a piece of text becomes big, then it is definitely a candidate for being stored outside the source code, where it can be reused, also. Separation of content and source code introduces the possibility to distinguish between different content types and storage locations, as well as the definition of categories, pages, templates and elements.

A very nice feature of Perl is that variables and function/method calls can be embedded within an (HTML) text. You can even store this text in a database, fetch it at runtime and then execute it on the fly. So, unless you want to restrict the access rights to runtime objects, you don't need an additional parser to embed software in strings, text files or database fields.

This allows to define a 'parse' content/MIME type (.phtml), say an (HTML) text with embedded software that can be stored e.g. in a text file and then be red and evaluated at runtime. In return, this greatly helps to separate content from templates and the application code to better fit to the different views of content authors, designers and programmers.

In the example below, the '$Page' object is used to insert page elements into the HTML template, thereby abstracting where these elements are actually stored. Variables are passed to the template as members of the '$Page' object, via the '$Var' hash or can be imported into the programs name space.

Note, that application methods within Maxdaemon return content and HTTP headers as string and hash references and do not directly write to STDOUT or sockets.

The file based page, template, element system used by the web surface is quite simple and there to avoid the dependency on a (content) database, introduced by Maxscape.

# HTML page with embedded Perl example:
=======================================

<!DOCTYPE html>
<html>
<head>

@{[ $Page->Element (Name => 'Head', Type => 'parse') ]}

<title>$Page->{Variables}->{Title}</title>
</head>
<body>

@{[ $Page->Element (Name => 'Body', Type => 'parse'
                    Variables => {
                      RootLink      => $Var->{RootLink},
                      LoginLink     => $Var->{LoginLink},
                    },)
]}
</body>
</html>

There is a second class (Maxdaemon::PageByPathInfo) that generates a Page from a file pointed to by the PATH_INFO environment variable, where '$ENV{PATH_INFO}' is the file path. Because Perl variables can be pushed onto the evaluation name space, these variables can be embedded by their name into an Perl parsed HTML text. Note, that this class is in a beta state.

# Application module:
=====================
...
my $Page = Maxdaemon::PageByPathInfo->new;
...
$Page->embedVariables (Action => 'action', Object => 'object');
...

# File: Example.phtml
=====================

# Use pushed variables in Perl parsed '*.phtml' files by their name. E.g.:

<html>
...
An $Object may have an $Action!
...
</html>

For each page, pointed to by the path info variable, a callback function can be defined in the 'ServerApplication.pm' file, which is then called by the $Page object, automatically. '$$p{Name}' is the file name of a page without extension (phtml).

# File: $MAXDAEMON_HOME/server/<AppServer>/lib/ServerApplication.pm:
====================================================================

package Maxdaemon::<AppServer>;
...
sub PageContextCallback
{
  my ($Page, $p) = @_;

  if ($$p{Name} eq 'Example') {
    my $RefreshTime = 60;
    my $Counter = $Page->QueryString ('Counter');

    $Page->embedVariables (
      LifeStreamURL => "$RefreshTime; url=/page.scgi/Frame.phtml?Counter=$Counter",);
  }
  return '';
}
...

See the Maxdaemon Index Server below the '/server/Maxdaemon' folder and the '/index.scgi' script, as a example.

Runtime Objects - Using Maxdaemon Classes in Apps

The runtime system provides several objects that can be used within applications. E.g.:

  • Configuration - Server Configuration.
  • SCGI - SCGI Interface.
  • Page - Container for content related data.
  • CGI - Client side of the CGI interface.
  • Form - HTML forms.
  • User - User related data.
  • DirectoryTree - File system management.
  • ...

The classes are an excerpt of the Maxscape classes essential to implement the daemon, the web surface and the Maxdaemon applications. You'll find a complete list in the online man pages.

Below, the code of an example script is shown, how to use these classes in application scripts. It simply displays the file 'showEnv.phtml', which prints the script's environment. If, for example, the file name is replaced by a CGI variable, say 'Path', an arbitrary file can be displayed (href="?Path=/arbitraryFile.phtml").

# File: $MAXDAEMON_HOME/server/Template/htdocs/showEnv.scgi
========================================================================
...
my $SCGI_Interface = Maxdaemon::Daemon::SCGI_Client->new ();
...
while (my $Client = $SCGI_Interface->accept)
{
  my $CGI = Maxdaemon::CGI->new ();
  my $Page = Maxdaemon::Page->new (CGI => $CGI);
  
  my $RequestURI = $CGI->RequestURI;
  my $ServerName = $CGI->ServerName;
  my $DocumentRoot = $CGI->DocumentRoot;
  my $absoluteFilePath = $DocumentRoot . $RequestURI;

  my $DirectoryTree = Maxdaemon::DirectoryTree->new (DocumentRoot => $DocumentRoot,);
  my ($Content, $FileLinesNumber) = $DirectoryTree->printFile (FileName => '/showEnv.phtml');
  my $Content = $Page->parseText ($Content); # $Content contains text with embedded Perl code

  print "Content-type: text/html$::CRLF" . $::CRLF . $Content;
}

The 'showEnv.scgi' script is not configured by default. Note, that you might want to remove the 'showEnv.(s)cgi' scripts altogether, because they show the CGI environment.

Callback Function Plug-In

It is easy to integrate callback functions into the daemon. By default the 'rewriteURI_Callback' and the 'sendFileCallback' can be configured via the configuration file (/etc/maxdaemon.conf). With the first you can manipulate a request URI, while the second is called before a response is sent to a client, thus giving the possibility to manipulate the generated content.

# File $MAXDAEMON_HOME/server/<AppServer>/etc/maxdaemon.conf
=============================================================
...
rewriteURI_Callback    Maxdaemon::Module::Main::rewriteURI_Callback
...
# File $MAXDAEMON_HOME/lib/Maxdaemon/Module/Main.pm
===================================================
...
sub rewriteURI_Callback {
  my ($Request, $ServerName, $VirtualHostName, $AppServerName) = @_;

  my $RequestURI   = $Request->{RequestURI};
  my $relativePath = $Request->{relativePath};
  my $QueryString  = $Request->{QueryString};
  my $MimeType     = $Request->{MimeType};

  if ($Request->{FileExtension} eq 'phtml')
  {
    # e.g. /manual/Index.phtml to /?Action=show+file&Path=/manual/Index.phtml
    my $UserDir = ($relativePath =~ //user// ? "/user/" : /);
    $RequestURI   =~ s/^(${UserDir}manual$::SL.*)/?Action=show+file&Path=$1/;
    $MimeType     = 'application/x-httpd-dcgi';
    $relativePath = $UserDir;
    $QueryString  = "Action=show file&Path=$1";
    $QueryString  =~ s/?/&/;
  }
  $Request->{RequestURI}   = $RequestURI;
  $Request->{relativePath} = $relativePath;
  $Request->{QueryString}  = $QueryString;
  $Request->{MimeType}     = $MimeType;
  return $Request;
}
...

Control Daemon

The control daemon is an example for the use of Maxdaemon as a general purpose daemon with a special communication protocol. Here the 'SystemControlCallback' function implements a simple database user authentification. The 'ServerSocketTimeout' directive can be used to periodically execute a 'ServerSocketTimeoutCallback' function.

# File: $MAXDAEMON_HOME/server/ControlDaemon/etc/maxdaemon-<version>.conf

# 1: only message, 2: full HTTP server
SystemControlDaemon      1
SystemControlCallback    Maxdaemon::Module::ControlDaemon::ControlCallback

# ServerSocketTimeout and ServerSocketTimeoutCallback
# ServerSocketTimeout    10.0
# ServerSocketTimeoutCallback Maxdaemon::Module::ControlDaemon::ServerSocketTimeoutCallback
...

# File: $MAXDAEMON_HOME/lib/Maxdaemon/Module/ControlDaemon.pm
...
sub ControlCallback {
  my ($HTTPD, $Request, $Client) = @_;

  my $AppServerName = $HTTPD->{Configuration}->getValue ('AppServerName');

  if (!defined ($Cursor)) {
    $DB->registerDatabase ($AppServerName);
    $Cursor = $DB->connectAppDatabase ($AppServerName);
    if (!$Cursor) {
      logError ('ControlDaemon.connect', "AppServerName ($AppServerName)");
    }
  }
  ...
}
...

In the '/sbin' folder you'll find the maxcontrol start/stop script. See the maxcontrol online man page.

  • maxcontrol start | restart | stop
  • man maxcontrol

To install the Control Daemon download 'maxdaemon-ControlDaemon-1.0.0-distribution.tgz' and untar that file in the Maxdaemon 'root' folder. Note, that you need a database and the DBI/DBD package to use this daemon for database authentification.

Database Authentication Daemon

To authenticate users stored in a database table instead of in a file, set the 'AuthBasicProvider' to 'ControlDaemon', and define the 'Database Name', 'Host', 'User', 'Password' variables via the '%Databases' hash (in 'DatabaseConfiguration.pm'):

# File: $MAXDAEMON_HOME/server/ControlDaemon/etc/maxdaemon.conf:
...
<Directory /user/>
  # Check if a user has logged in.
  checkUserAuthorization   1

  # Basic authorization
  AuthType                 Basic

  # Browser basic authorization prompt
  AuthName                 Maxdaemon HTTPS server login:

  # Get password from ControlDaemon.
  AuthBasicProvider        ControlDaemon
  ...
<Directory>
...
# File: $MAXDAEMON_HOME/lib/SiteLocal/DatabaseConfiguration.pm:
...
sub configureDatabase {

  my $DatabaseProduct = 'mysql';

  my %Databases = (
     'MaxAgent' =>
       {
         Name => 'Maxdaemon', Host => 'localhost', User => 'Maxdaemon', Password => 'MyPW',
       },
     'ControlDaemon' =>
       {
         Name => 'Maxdaemon', Host => 'localhost', User => 'Maxdaemon', Password => 'MyPW',
       },
  );
  return ($DatabaseProduct, \%Databases);
}
...

The control daemon then looks up the database, as defined by the 'configureDatabase' function in the 'SiteLocal::DatabaseConfiguration' package. Of course, the database must be configured beforehand, see Maxdaemon-utf8.sql.

 # MySQL database example;
 
 > su - mysql
 mysql> mysql -p -uroot

 mysql> create database Maxdaemon;
 mysql> connect mysql;
 
 # create MySQL user
 mysql> insert into user (Host,User,Password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Reload_priv,Shutdown_priv,Process_priv,File_priv,Grant_priv,References_priv,Index_priv,Alter_priv,Show_db_priv,Super_priv,Create_tmp_table_priv,Lock_tables_priv,Execute_priv,Repl_slave_priv,Repl_client_priv,Create_view_priv,Show_view_priv,Create_routine_priv,Alter_routine_priv,Create_user_priv,Event_priv,Trigger_priv,Create_tablespace_priv) values ('localhost','Maxdaemon',password('MyPW'),'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y' );

 # Create MySQL db
 mysql> insert into db (host,db,user,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Grant_priv,References_priv,Index_priv,Alter_priv) values ('localhost','Maxdaemon','Maxdaemon','Y', 'Y', 'Y', 'Y', 'N', 'N', 'N', 'N', 'N', 'N');

 mysql>quit

 > mh # Tcsh alias for 'cd $MAXDAEMON_HOME'
 # create database tables
 > cat server/ControlDaemon/tables/Maxdaemon-utf8.sql | mysql -uroot -p
 > mysqladmin -udba -p reload

Maxdeamon Applications

Web sites and services are implemented with Maxdaemon application servers. An application server consists of one ore more process daemons connected to the HTTP server via the configured CGI interface. A Maxdaemon installation includes several default applications (Maxdaemon (Webserver Manager), Test, Template, ControlDaemon, etc.).

Webserver Browser Surface to communicate with Remote Hosts

Maxdaemon includes a file system management server with which you can administer the server's, as well as the remote host's file system with a web browser.

Although this surface is not a content management system, it can be used to edit a web site's content and the server software. It can be configured to grant access to any file of a (remote) host without a login shell. Of course, permissions can be restricted and are controlled via various parameters like UNIX user/group, node permissions, surface configuration, user name and actions. To access files outside the 'DocumentRoot', simply add a symbolic link at the wanted location.

Features and Functionality

The surface works quite similar to a file explorer. There are some differences due to the HTTP client server model and the HTML/CGI implementation style. Working on local and remote hosts is transparent and the in-build features differ. Although it is not a content management system, it can be used to edit files on (remote) hosts, web sites, as well as the web server's software and content, indeed. The main file system management functions are provided:

  • display - Respond requests.
  • edit - Edit files by (MIME) type
  • new - Create files and folders
  • change - Change files
  • copy - Copy files
  • move - Rename and move nodes
  • remove - Delete nodes
  • upload - Upload files
  • search - Search for strings

Directory Tree Document Root

The 'DocumentRoot' of the web surface server's directory tree is set to the home folder of a Maxdaemon installation ('<installation directory>/maxdaemon/daemon'), which is actually a folder link to a special Maxdaemon version (e.g. 1.0.0). Therefore any file of the daemon and the installed application servers ('/server') can directly be displayed/edited. In the following the '/' refers to this folder ($MAXDAEMON_HOME). The symbolic link '/root' leads to the installation directory ($MAXDAEMON_ROOT), where merely local host specific parts, like the UNIX user home, are placed.

Display Files And Execute Scripts

The surface default page displays the server's file system below whatever the 'DocumentRoot' is set to. Click on folder hyperlinks to traverse the server's directory tree. Click on file links to display, listen to and view the file content or to run server side application scripts. The action that is performed by the server is mainly determined by the surface/HTTPD configuration, the file's MIME type, the surface user, the HTTP headers and CGI variables. For example, clicking a script of type 'application/x-httpd-cgi' will execute it via the CGI interface of the HTTP daemon.

Create, Edit and Change Files

It is easy to add static content the to the server. Simply go to the wanted folder of the document tree, click 'edit' and enter the file name. Choose an appropriate file extension, because it determines the file handling at runtime. To edit files with the surface makes only sense with human readable file content, and only the very basic file system operations are implemented, so far. Creation of symbolic links to include files or folders outside the document tree, and changing file owner/group/permission are not supported.

The effort to implement/integrate applications depends on their complexity, of course. In the simplest case just put a CGI script within the directory tree or the 'cgi-bin' folder and then click on it.

The editing functions are implemented with HTML form <textarea> tags, which are quite flexible in nature. You like WYSIWYG? Simply add one of these nice Javascript editors. I wonder if there is one that supports mixing of multiple languages like Perl and HTML. Anyway, to edit (HTML source) text via the surface often makes sense, but with scripts I mostly prefer the Vi editor. There are a few caveats when editing HTML with a <textarea> form tag. Namely, that the &*;'s are replaced by Firefox, and that a <textarea> tag in a <textarea> form field crashes the form. For more, see the 'Maxdaemon::DirectoryTree::escapeTextAreaBug' method.

To ease HTML form handling, the surface page header can be hidden (☰) to make more space and the button bar can be fixed to a position to minimize nasty form field scrolling. By using the browser's text search function, one can work quite rapidly, although the 'textarea' form field scrolls on top of the page, when changes are submitted.

Copy, Move and Delete

To copy, move or delete files go to the file's source folder, select the source file via the radio button, enter the destination path and submit the wanted action. The destination path name follows UNIX conventions. So, '../' points to the parent directory.

Upload Files

Go to the desired folder, click the (ugly default) 'upload' button to upload a file to the remote server. Note, that the file permission will be '-rw-r-----'. Uploads are only allowed to registered members, by default.

Search for Strings

One of the crucial aspects of any software project is to know resp. to find the (storage) places of project entities and the speed to possibly change them. In the simplest case you are searching for a short string in a bunch of files and maybe databases.

Maxdaemon has two solutions to this challenge. Firstly, since in '/Manifest.txt' all files of the server are listed, the 'gp' script just 'grep's these files for the string and lists the matching file names and lines. Secondly, as Git is used to track the development, Git's search function is utilized.

Configuration Modes and Files

The surface and the HTTP daemon have various configuration modes and options. Have a look at the following files for more information on configuration directives of the surface:

  • • $MAXDAEMON_HOME/etc/DirectoryTree.conf
  • • $MAXDAEMON_HOME/etc/maxdaemon<-version>.conf

For example, if you want to edit/change a file with a MIME type not listed so far, add a new 'AddEditMimeType' directive in '/etc/DirectoryTree.conf'.

Adapting the Surface

To change or add points to the pulldown menu, edit the file '$MAXDAEMON_HOME/page/element/PulldownMenu.phtml'. List your application servers in '$MAXDAEMON_HOME/page/AppSitesMenu.phtml' for fast access.

Themes, Look and Feel

The basic surface version is implemented useing only HTML/CSS/CGI and does't depend on Javascript libraries, what is good for portabillity reasons over times. Well, the form widgets doesn't look that nice. Fortunatly, is it quite easy to change to other themes by integrating one of these nice user interface Javascript libraries (e.g. jQuery-UI). By now, there are two default themes resp. button style to choose via the menu (☰) and you can change the look and feel by tweaking the CSS style sheets under the '$MAXDAEMON_HOME/css' folder to add more themes on your own.

Web Surface User Accounts

To be able to log into the Maxdaemon web surface, you need to create a Maxdaemon web surface user account:

> createUserLogin create <user id>

Note, that all registered users have access and can change any files within the scope of the UNIX user and groups under which Maxdaemon is running!

CGI Interfaces

The surface can be executed via all three CGI interfaces of the HTTP daemon. To run the surface via the CGI, respectively the SCGI interface, simply click on the '/www.cgi' resp. the '/www.scgi' scripts in the '/', resp. the '/user' folders. Clicking the '/user/www.(s)cgi' script will pop up a login form for registered users (basic authentication).

Template Application Server

The distribution contains a 'Template' application server, which is used as a template for application server creation with the 'createAppServer' shell script. The script creates the general directory structure and copies essential files. To tailor server creation to your requirements, add resp. change the files and directories and adapt the 'createAppServer' script accordingly. See the 'Template' server running.

Test Server

The distribution also contains a 'Test' application server to get accustomed to Maxdaemon and to start programming right away. Have a look at the Work Flow Examples.

Manual Server

The 'Manual Server' is at the beginning of a decent manual. Note, that this server is a special case, in that the SCGI script is '~/index.scgi' and that the configuration files are located below '~/etc'.

MaxChat Server

The 'MaxChat Server' is a prototype of a 'WebSocket' chat. If you are interessted to work on that chat, let me know. You can download the Chat via the download page.

LifeStream Server

The 'LifeStream Server' is a prototype of a life stream application using jQuery and Ajax. If you are interessted to work on that life stream prototype, let me know. You can download the life stream app via the download page.

Maxscape Application Servers

The Maxscape Application Servers, including the Content Database Administration Server, normaly running in an Apache/FastCGI configuration are doing fine with Maxdaemon's DCGI, CGI and SCGI interfaces.

Development and Integration Environment

To develop a program is not always an easy task. First and all above, you need to have the full control over your source code, content and data, and you have to understand the subject, of course. This tends to become more difficult when projects gets bigger and when the number of people involved, increases. Anyway, there are some simple rules to ease the process concerning (web) programming:

  • Have a complete list of all project files and data and have search functions to easily find and change them. Good choices are CVS or even better its offspring Git.
  • Have some kind of a version management mechanism to restore previous versions.
  • Try to have only one version of each entity (file, text, object, function, etc).
  • Minimize the code and reuse as much as you can..
  • Keep anything as simple as possible, because the easy things are hard to do.
  • Minimize the effort to make any kind of changes to the system.
  • Separate generic from application specific parts.
  • Separate text, templates and source code.
  • Have well defined interfaces between components and part systems.
  • Write wrapper functions around external interfaces.
  • Choose the appropriate tools to accomplish special tasks.

Maintainability of a code base greatly depends on the speed with which changing environments can be incorporated, and therefore how fast code changes can be accomplished.

According to Perl's motto "There's more than one way to do it." and the three principal virtues of a Perl programmer (laziness, impatience and hubris), Maxdaemon relies on the good old UNIX tools (sh, vi, make, grep, find, xterm, git, rpm, ..), some shell scripts (makefile, gp, certificate, createAppServer, etc.), Firefox and the Maxdaemon web surface.

Web Server Platform

To run a web server a basic system (web server platform) is required. Namely the operating system (OS, e.g. Linux), an HTTP daemon (e.g. Apache), a programming language (e.g. Perl), an encryption component (e.g. Openssl) and most possibly a database (e.g. Mysql, Mariadb, Oracle).

Operating System Setup

The Maxdaemon Framework is developed and tested only under Ubuntu, so far. A portation to another UNIX should be possible with little changes. A Windows port might need quite a bit of work.

Best is to use the tools provided by the OS. Otherwise you have to build the required parts by yourself. Several helpful components can be installed by the update mechanism of the OS, e.g. for Ubuntu:

apt-get update
apt-get upgrade

apt-get -y install analog aptitude autoconf bison cmake curl cvs Expat ffmpeg \
g++ git iptables libaio-dev libav-tools libjpeg62-dev libncurses5-dev libpng12-dev \
libtool libxpm-dev libxvidcore4 libfaac0 locate lynx man-db net-tools nmap rcconf \
rpm tcsh vim whois zlib1g-dev

Webserver Platform Build

To ease the build of components on your own, the RPM (Red Hat Package Manager) is used. All conmonents should be installed below the '/opt' folder. Therefore a RPM repository is provided, which contains the RPM spec and RPM source files. The RPM source files (Apache, Perl, ..) are not changed at all and provided for convenience, only. Maybe there are newer versions at their official download sites.

To install the RPM folders download 'Maxscape-Platform-Build-RPM-Repository.tgz' and untar that file in the Maxdaemon 'root' ($MAXDAEMON_ROOT) folder. Then follow the instructions in the 'README.txt' file.

> su - root
> ln -s $MAXDAEMON_ROOT/rpmbuild rpmbuild
> mr # tcsh alias for 'cd $MAXDAEMON_ROOT'
> tar zxvf <download directory>/Maxscape-Platform-Build-RPM-Repository.tgz
> cd rpmbuild
> cat README.txt

The build is developed and tested under Ubuntu (14, 16). The goal would be to adapt the SPEC files to work on any possible OS. Therefore the RPM repository is published under the LGPL (GNU LESSER GENERAL PUBLIC LICENSE). Please send us your modifications and enhancements, so that we can publish them.

Open SSL Build

Though the OS Openssl installation can most probably be used for HTTPS communication, it might be not sufficient to build Perl with an encryption source code filter. If your OS also doesn't provide the Openssl include C header files, you should build your own Openssl installations (/opt/ssl/<Openssl version>):

> rsp # alias for 'cd $MAXDAEMON_ROOT/rpmbuild/SPECS'

# For Filter::Crypto (which doesn't compile correctly with openssl-1.1.0g)
> rpmbuild -ba -vv openssl-1.0.2n.spec

# For Apache, NetSSLeay, SSL certificates, ..
> rpmbuild -ba -vv openssl-1.1.0g.spec
> rpmbuild -bi -vv openssl-1.1.0g.spec

To incorporate the Openssl installation in your Maxdaemon directory tree, simply copy the files to the $MAXDAEMON_ROOT/ssl/ folder and adapt the 'sp' script accordingly.

Perl Interpreter and CPAN Build

There are several reasons that you might want to build your own Perl interpreter. For example, to install the latest Perl release, to install an extended set of CPAN modules or to incorporate special features, like source code filters to encrypt the Perl sources e.g. for production systems to hide e.g. passwords.

To build an own Perl Interpreter set the build environment with the 'sp' script and execute the perl-5.26.1.spec file, which builds and installs several CPAN modules (FCGI, libwww-perl, Data::Dumper, GD, Plack, Mojolicious, ..). Edit the Perl spec file to add more or to remove not wanted packages.

Maxdaemon itself only requires the Net-SSLeay (HTTPS communication), the Filter-Crypto (Perl source code encryption) and possibly the DBI/DBD (database interface) packages.

To experiment with the Perl build, Perl's 'Policy.sh' and 'config.sh' files are good places. See the spec file for the use of this feature with RPM.

# set the build environment (SSL_ROOT, APACHE_ROOT, ..)
> sp -p optperl
> cd $MAXDAEMON_ROOT/rpmbuild/SPECS
> vi perl-5.26.1.spec
> rpmbuild -ba -vv perl-5.26.1.spec

If you like to include your Perl version within the Maxdaemon directory tree, simply copy the related files using the makefile (cd /opt/maxdaemon; make copy-perl-opt-to-maxdaemon) and set the PERL5LIB accordingly (best use the 'sp -p maxperl' script).

Perl Source Code Encryption (Filter-Crypto Package)

For production servers it is wise to encrypt the Perl sources to hide, for example, the passwords from unwanted viewers. Basically, two Perl versions are installed, one with which Perl source files can be encrypted ('/opt/perl/5.26.1-crypt_file-decrypt') and one only with the decrypt function (/opt/perl/'5.26.1'). You'll find the difference in '$RPM_SOURCE_DIR/maxdaemon-Perl-5.26.1-crypt_file-decrypt.tgz', after the build.

# Filter::Crypto pass phrase file is:
# $RPM_SOURCE_DIR/CipherConfig.h

# Perl executable to encrypt Perl source files is:
# /opt/perl/5.26.1-crypt_file-decrypt/bin/perl-crypt_file-decrypt

# Perl executable to only decrypt Perl source files is:
# /opt/perl/5.26.1/bin/perl

> man Filter::Crypto 
> ln -s /opt/perl/5.26.1-crypt_file-decrypt/bin/crypt_file /opt/maxdaemon/bin/crypt_file

# Encrypt a Perl source with 'crypt_file'
> crypt_file --in-place <Perl source file>

Apache Build

For heavy loaded production systems you might want to use Apache instead of the Maxdaemon HTTPD. The apache-2.4.29.spec RPM spec file will help you to build a prefork version with mod_ssl, mod_fcgi and mod_perl.

> sp -p optperl # Sets the build environment (SSL_ROOT, APACHE_ROOT, ..)
> cd $MAXDAEMON_ROOT/rpmbuild/SPECS
> vi apache-2.4.29.spec

> rpmbuild -ba -vv apache-2.4.29.spec
> rpmbuild -bi -vv apache-2.4.29.spec
> rpmbuild -ba mod_perl-2.0.10.spec
> rpmbuild -bi mod_perl-2.0.10.spec

# Exchange the decrypt and thread-multi Perl versions, because I havn't been
# able to build mod_perl with the static decrypt Perl installation
cd /opt/perl
rm -rf ./5.26.1-x86_64-linux-thread-multi
mv 5.26.1 5.26.1-x86_64-linux-thread-multi
mv 5.26.1-decrypt 5.26.1

Of course, you have to configure the apache configuration via the httpd.conf file (/opt/apache/2.4.29/conf/httpd.conf). Also, set the permissions of your (FCGI) scripts and the FCGI UNIX domain sockets (/opt/apache/2.4.29/logs/fcgidsock) correctly. Then you can start the Apache with the 'apachectl start|restart|stop' script.

(Rational) Database

To use a database the Perl database interface DBI/DBD packages have to be installed. If you like Oracle, Postgress or another database, the related DBD packages have to be installed, best by creating own RPM spec files and executing them instead of the MySQL DBD spec file, within the Perl 'perl-5.26.1.spec'.

Under Ubuntu a MySQL database is or can be installed, which easily can be used. Of course, the MySQL data directory needs to be initialized (mysql_install_db), the database users and instances needs to be created and the data models have to be defined (see the Database Authentication Daemon example).

Visit Maxscape.com for more details on how a (rational) database can enhance content management and web application server programming.

Content Tracker (CMS)

Content trackers like CVS and its more comfortable offspring Git are very useful tools. Therefore Git is used to track the Maxdaemon development. To install a local Git repository see the 'git-install.sh' script.

Server and Application Directory Structure

Maxdaemon provides a unified directory structure to ease web server management and to share application modules between several applications, as well as with the daemon software. Each folder has its own purpose and the directory tree is structured according to UNIX conventions. So, configuration files are located in 'etc', executables in 'bin', daemons in 'sbin' and modules below 'lib' folders.

Generally, all parts of an installation are located below the 'maxdaemon' root directory. Exceptions are optional third party products like Apache, SSL and databases, which are best located under the '/opt' folder. The directory structure reflects the purposes of the parts and follows UNIX conventions (etc, bin, sbin, lib, ..).

<installation folder>/maxdaemon
  .git         -  Git content tracker repository.
  1.0.0        -  Maxdaemon version 1.0.0.
  bck          -  Backup folder.
  bin          -  General scripts.
  daemon       -  Link to the actual Maxdaemon version.
  etc          -  Environment and boot scripts.
  home         -  Maxdaemon UNIX user home.
  perl         -  Local Perl language interpreter.
  rpmbuild     -  RPM (Red Hat Package Manager) repository.
  templates    -  Useful templates.
  tmp          -  Temporary files.
  License.txt  -  Distribution License.
  makefile     -  Installation and backup makefile.

A basic installation consists of the 'root' tree and the 'home' sub-tree. The 'root' tree comprises the nodes local to the host, like the UNIX user, the backup directory and the folders containing special Maxdaemon versions. The 'daemon' symbolic link is used to point to the current Maxdaemon version and is referred to by 'home' ('~/'), because 'home' is the 'DocumentRoot' of the web surface server, even though this is a bit confusing. Note, that in this context '~/' does't mean the UNIX user home.

<installation folder>/maxdaemon/daemon
  bin           -  Management scripts.
  cgi-bin       -  CGI scripts.
  css           -  CSS style sheets.
  etc           -  Configuration files.
  javascript    -  Javascript scripts.
  lib           -  Modules and packages.
  man           -  Maxdaemon man pages.
  manual        -  HTML man pages.
  media         -  Images, audios and videos.
  page          -  Page templates and elements.
  root          -  Link to the root folder.
  sbin          -  Daemons and start scripts.
  server        -  Applications servers.
  user          -  Folder link for registered users.
  var           -  Log, temp, stat and pid files.
  index.scgi    -  Maxdaemon manual SCGI script.
  Manifest.txt  -  Maxdaemon manifest.
  www.cgi       -  Surface CGI script.
  www.scgi      -  Surface SCGI script.

All application servers are located below the '~/server' directory and have a similar structure. Several Tcsh aliases are defined for quick navigation within the directory tree.

To come to know about the file system structure, simply browse through this server's directory tree with the web surface. If you set the display style to 'Head', a short summary of each node is shown. If you set the display depth ('Depth') high enough, the whole server file system is displayed.

Content/Application Management

Because the web surface makes the basic file management functions accessible via a web browser, some kind of content management functionality is provided, but this can hardly be called a content management system. If you are interested in that area, have a look at Maxscape, which uses a (rational) database as the content/application repository, in addition to the server's file system. Storing web content and software in a database, opens up a whole new world of possibilities and adds the power of the SQL language and rational databases to content management and application programming.

Shell Tools

Besides the File System Management surface there are a few, nonetheless quite helpful little tools, namely the "makefile", "sp.sh", "gp.sh", "createAppServer.sh", "createUserLogin", "certificate.sh","makeManual.sh", "minclient.pl", the Tcsh aliases and the RPM spec files (see the online man pages), when working with a command line shell. Shell scripts are written to work with 'bash', but might work with other shells (e.g. 'sh', 'dash', ..), too.

Manifest or How To Find Text and Code Pieces

The complete list of all files is stored in 'Manifest.txt', which is used for several purposes. Firstly, it contains the headlines that are displayed by the web surface in 'Head' display mode. Secondly, it may contain the display and edit permissions for each file of the server. Add all your source files to the 'Manifest.txt' to take advantage of that feature. To configure it, the following variables must be the set:

# File: $MAXDAEMON_HOME/lib/Maxdaemon/Globals.pm

$::USE_MANIFEST_PERMISSIONS    = 1; # Use permissions defined in the 'Manifest.txt'.
$::STRICT_MANIFEST_PERMISSIONS = 0; # Access denied for all nodes not defined in 'Manifest.txt'.

# File: $MAXDAEMON_HOME/Manifest.txt
...
# Example: Hide 'bin/certificate.sh'.
bin/certificate.sh - Creates SSL certificates for name-based virtual server. - h
...

Strict permissions means that files not listed in '/Manifest.txt' are not accessible, altogether, if strict is not set, manifest permission are not applied to those files. Note, that the 'Manifest' permission feature is only experimental, so far.

Thirdly, '~/Manifest.txt' is used by the 'gp' shell command to find out where a piece of text or code is stored.

> gp '<search string>'

For example, imagine the situation that you want to change the string 'help' in all files and directory names to 'manual'. Well, first get a list of all files, feed an editor with that list, use the editor's search function to find the string, go through each file and change 'help' to 'manual' with the search/replace function of your editor. With Vim enter the following commands:

> gp -e help
/maxdaemon/bin/certificate.sh /maxdaemon/../bin/gp.sh /maxdaemon/page/element/SurfaceIntroduction.html /maxdaemon/page/element/MaxdaemonOverview.html

# copy above output, enter v (alias to vim) and paste.
# Use Vim's search and replace functions to change 'help' to 'manual'.
> v /maxdaemon/bin/certificate.sh /maxdaemon/../bin/gp.sh /maxdaemon/page/element/SurfaceIntroduction.html /maxdaemon/page/element/MaxdaemonOverview.html

# 'mh' is a Tcsh alias for 'cd $MAXDAEMON_HOME'.
> mh
# 'f' is a Tcsh alias for 'find . -name <string>'.
> f help
./help
./user/help

# Change file, links, resp. folder names. 
> mv ./help ./manual
> mv ./user/help ./user/manual

Alternatively, you can find a string with the search function of the web surface, also displaying the list of files, containing the searched string. Though in this case, it will take more time, because of the search/replace feature of Vi, but fine to get an overview.

Desktop, X-terms and Web Surface

While Vi or an equivalent editor is mostly the best tool to edit software, documents can often more easily be edited with a (HTML) text editor or a web browser's 'textarea' form field.

So, to efficiently work with Maxdaemon, arrange the computer desktop so that you have one virtual desktop for the X-terms e.g. to edit the programs and to (re)start the daemon and another desktop for the web browser tabs to display the developed pages and to edit content and embedded software.

Download, Installation and Configuation

Downloads

Downloads are available via the Maxscape downloads page.

Quick Glance Installation

To take a quick glance at Maxdaemon, you might want to install Maxdaemon under your UNIX user account. The makefile helps you to set your environment and gives you some installation hints, only.

# You'll need an account on a Unix host with tcsh, wget or curl, md5sum, tar, make, Perl
# and a web browser for the installation and operation. Use Firefox for ease of use. 

# Downloaded the Maxdaemon distribution to your downloads directory (e.g.: ~/Downloads)
# using a web browser or downloaded it via a terminal with e.g. curl.
# Create an account at http://maxscape.com/ to get your credentials <UserId:Password>:
> curl -ku <UserId:Password> https://maxscape.local.net/User/Downloads/maxdaemon-home-source-distribution-1.0.0.tar.gz --output ~/Downloads/maxdaemon-home-source-distribution-1.0.0.tar.gz

# Check the md5sum:
> md5sum ~/Downloads/maxdaemon-home-source-distribution-1.0.0.tar.gz

# Change to the directory under which to install Maxdaemon (best: ~/):
> cd

# Untar the the distribution:
> tar zxvf ~/Downloads/maxdaemon-home-source-distribution-1.0.0.tar.gz
maxdaemon/
...

# Install, configure and start Maxdaemon.
> cd maxdaemon/1.0.0
> make install_quick_glance
Installing Maxdaemon for you.
...

# Set the Maxdaemon shell environment, temporarily:
> ./bin/sp

# Start Maxdaemon (use options [-vv -sl] for debug mode):
> maxdaemon start
Starting Maxdaemon Application Server.
...

# Open your browser and enter the location 'http://localhost:8000'.
# Login to the web surface as 'Max' with the password '123456'.

# Display access logs:
> da
...
192.168.0.3 - - [10/Aug/2025:07:32:43 +0000] "GET / HTTP/1.1" 200 10380 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0"
...

# Restart the server.
> maxdaemon restart
Restarting Maxdaemon Application Servers.
...

# Stop the server.
> maxdaemon stop
...

# Change or remove the web surface password of 'Max'!

Now, enter 'http://127.0.0.1:8000/' in your browser, and the Maxdaemon surface should show up. The SSL daemon has the address 'http://127.0.0.1:8001/'.

If your browser already has stored a certificate with the name '127.0.0.1' for the server '127.0.0.1:8001', delete that certificate via the browser's Certificate Manager and use another serial number, if '00' dosn't work.

Note, that when executing Maxdaemon as a 'non-root' user, you will not be able to use the default HTTP(S) ports (default HTTP port is 80, default HTTPS port is 443), because they are preserved for (change) root daemons. To run servers on TCP/IP port numbers below 1024 root permissions are required and you can't set up a name based virtual server.

Advanced Installation

To set up a fully fledged virtual name-based server might take some time. Firstly, you'll need to set up your operating system and to provide the required components, that are not part of your OS.

  • Operating system set up.
  • Setup host and domain names.
  • Configure the network interface.
  • Choose UNIX user account and groups.
  • Choose installation directory.
  • Untar Maxdaemon Tar file(s).
  • Configure and start Maxdaemon.

To run a fully featured development or production server, an own UNIX account (maxdaemon:maxdaemon) is recommended, best placed in the '/opt' folder. Each application server has an own standardized directory structure located below the 'server' folder. Most configuration modes and options are configured by directives in configuration files (maxdaemon<-version>.conf) placed in the related 'etc' directories.

UNIX User Account and Groups

There are three kinds of UNIX user accounts under which Maxdaemon can be installed (supported by the makefile):

  • Install under an own 'maxdaemon' account (recommended).
  • Install as user 'root'.
  • Install as a 'non-root' user.

Install Maxdaemon as User 'root'

Even if you want to execute Maxdaemon as user 'root', I recommend to install Maxdaemon under an own account. This way development can be done under the 'maxdaemon' user, while Maxdaemon can be started by the 'root' user, respectively by an '/etc/init.d/maxdaemon' script at boot time (see the '/opt/maxdaemon/etc/maxdaemon.etc.init.d.sh' example script). Set the 'User' and 'Group' entries in the '~/etc/maxdaemon.conf' file to the UID/GID names under which you want to run Maxdaemon.

Maxdaemon UNIX Account

If you have root permission, it is best to create an own UNIX account, say maxdaemon. Assuming that there is no user 'maxdaemon (UID=8002)' and no group 'maxdaemon (GID=8002)' on your computer so far (choose other user(UID)/group(GID), if you like), you need to create the 'maxdaemon' user and the 'maxdaemon' group. The makefile does not automate this, because I don't want to fiddle with your computer's '/etc/passwd' and '/etc/group' files. Also assuming that you have untared the distribution tar file under '/opt', enter the next lines.

If you use 'sudo', the following lines must be preceeded by it. To bypass 'sudo' enter 'sudo passwd root' and be a bit careful what you are doing. Provided that there are no UID/GID 8002/8002 on your computer, do:

 > su - root
 > groupadd -g 8002 maxdaemon
 > useradd -u 8002 -s /bin/sh -d /opt/maxdaemon/home -g maxdaemon maxdaemon
 > passwd maxdaemon

Now, you can login to your newly created 'maxdaemon' account (su - maxdaemon).

Maxdaemon Installation Steps

I recommend to install Maxdaemon below the '/opt' directory. If this is not wanted or possible choose another. Go to that directory and untar the distribution file, then you will find the installation, below the maxdaemon directory.

> su - root
> cd <Installation directory> # best '/opt'
> tar zxvf <Download directory>/maxdaemon-root-1.0.0-distribution-<version>.tgz
> su - maxdaemon
> mr # tcsh alias for 'cd $MAXDAEMON_ROOT'
> make info # prints some information about your installation
> createUserLogin create <user name>
> certificate -a URI:<FQDN> -s 00 <FQDN> # FQDN is given by 'hostname --fqdn'
> sp -p OSperl -c fqdn
> maxdaemon -vv start

Now, enter 'http://<FQDN>:8000/' in your browser, and the Maxdaemon surface should show up. The SSL daemon has the address 'http://<FQDN>:8001/'.

Because we have started Maxdaemon from our UNIX maxdaemon account, we'll get the error 'Set EGID/RGID: Operation' not permitted. To get ride of this warning, comment out the 'User' and 'Group' directives, in the configuration file (~/etc/maxdaemon-fqdn.conf).

If we start Maxdaemon from the UNIX root account, the HTTP(S) will run with the user/groups defined by the 'User' and 'Group' directives.

Shell Environment

To work with Maxdaemon from your UNIX root account the shell environment needs to be configured, which is defined in the global profile and tcshrc files. If you include them in your root account's '~/.profile' and '~/.tcshrc' resource files, the variables are then set when you login, automatically.

<Installation directory>/maxdaemon/etc/profile # Maxdaemon global profile
<Installation directory>/maxdaemon/etc/tcshrc  # Maxdaemon global tcshrc

At least define the 'MAXDAEMON_INSTALLATION_ROOT' variable in your '~/.profile'. Assuming that you have installed Maxdaemon under the '/opt' folder, add the following lines to your '~/.profile'. If you don't want to pollute your environment, only export the 'MAXDAEMON_INSTALLATION_ROOT' variable and use (maybe adapt) the 'sp' (set project) script, to set the environment.

# File: ~/.profile

MAXDAEMON_INSTALLATION_ROOT=/opt/maxdaemon; export MAXDAEMON_INSTALLATION_ROOT;

if [ -f $MAXDAEMON_INSTALLATION_ROOT/maxdaemon/etc/profile ]; then
  . $MAXDAEMON_INSTALLATION_ROOT/maxdaemonetc/profile
else
  echo "Maxdaemon profile ($MAXDAEMON_INSTALLATION_ROOT/maxdaemon/etc/profile) not found!"
fi

tcsh
if [ $? != 0 ]; then
  echo "You should install and use tcsh with Maxdaemon, in order to be able"
  echo "to use the Maxdaemon tcsh aliases."
  sh
fi

The global profile ($MAXDAEMON_ROOT/etc/profile) defines the following shell environment variables and sets the PATH and MANPATH for Maxdaemon:

> env|grep MAX
MAXDAEMON_INSTALLATION_ROOT=/opt/maxdaemon
MAXDAEMON_NAME=maxdaemon
MAXDAEMON_VERSION=1.0.0
MAXDAEMON_ROOT=$MAXDAEMON_INSTALLATION_ROOT/$MAXDAEMON_NAME
MAXDAEMON_MANPATH_OS_ORIG=
MAXDAEMON_HOME=$MAXDAEMON_ROOT/daemon
MAXDAEMON_PATH_OS_ORIG=/usr/local/bin:/usr/bin:/bin:
MAXDAEMON_TMP_DIR=/opt/maxdaemon/daemon/var/tmp
MAXDAEMON_CONF_FILE_VERSION=

> echo $PATH 
/opt/maxdaemon/daemon/bin:/opt/maxdaemon/daemon/sbin:/opt/maxdaemon/bin:/bin:/bin:/usr/local/bin:/usr/bin:/bin:
> echo $MANPATH
/opt/maxdaemon/daemon/man:

To control the various configuration modes the 'sp' (set project) shell script is provided. This script is meant to be adapted by you, to set your project's evironment.

# Uses the Perl installation ($MAXDAEMON_ROOT/perl) provided by Maxdaemon (only for Ubuntu!)
# and the configuration file: '$MAXDAEMON_HOME/etc/maxdaemon-127.0.0.1-8000-8001.conf'.

> sp -p maxperl -c 127.0.0.1-8000-8001

> ls -l /opt/maxdaemon/daemon/bin/perl
lrwxrwxrwx ... /opt/maxdaemon/daemon/bin/perl -> /opt/maxdaemon/perl/5.26.1/bin/perl

> wp # which project
Project is......................: maxdaemon
Environtment variables are......:
Maxdaemon installation directory: /opt
Maxdaemon name..................: maxdaemon
Maxdaemon home..................: /opt/maxdaemon/maxdaemon/daemon
Maxdaemon root..................: /opt/maxdaemon/maxdaemon
Maxdaemon version...............: 1.0.0
Maxdaemon temporary folder......: /opt/maxdaemon/maxdaemon/daemon/var/tmp
Maxdaemon configuration file....: /opt/maxdaemon/maxdaemon/daemon/etc/maxdaemon-127.0.0.1-8000-8001.conf.
MAXDAEMON_INSTALLATION_ROOT.....: /opt/maxdaemon
PERL_VERSION....................: 5.26.1
PERL_ROOT.......................: /opt/maxdaemon/perl/5.26.1
PERL_BIN........................: /opt/maxdaemon/perl/5.26.1/bin
PERL5LIB........................: /opt/maxdaemon/perl/5.26.1/lib/5.26.1:/opt/maxdaemon/perl/5.26.1/lib/5.26.1/x86_64-linux:/opt/maxdaemon/perl/5.26.1/lib/site_perl/5.26.1:/opt/maxdaemon/perl/5.26.1/lib/site_perl/5.26.1/x86_64-linux
SSL_VERSION.....................: 1.1.0g
SSL_ROOT........................: /opt/maxdaemon/ssl/1.1.0g
SSL_BIN.........................: /opt/maxdaemon/ssl/1.1.0g/bin
APACHE_VERSION..................: 2.4.29
APACHE_ROOT.....................: /opt/apache/2.4.29
APACHE_BIN......................: /opt/apache/2.4.29/bin
DATABASE_TYPE...................: mysql-maxscape
MYSQL_VERSION...................: 5.5.39
MYSQL_ROOT......................: /opt/mysql/5.5.39/usr
MYSQL_BIN.......................: /opt/mysql/5.5.39/usr/bin
PATH............................: /opt/maxdaemon/daemon/bin:/opt/maxdaemon/daemon/sbin:/opt/maxdaemon/bin:/opt/maxdaemon/perl/5.26.1/bin:/opt/maxdaemon/ssl/1.1.0g/bin:/opt/apache/2.4.29/bin:/opt/mysql/5.5.39/usr/bin:/opt/mysql/5.5.39/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MANPATH.........................: /opt/maxdaemon/daemon/man:/opt/maxdaemon/perl/5.26.1/man:/opt/maxdaemon/ssl/1.1.0g/man:/opt/apache/2.4.29/man:/opt/mysql/5.5.39/usr/share/man:
LD_LIBRARY_PATH.................: /opt/maxdaemon/ssl/1.1.0g/lib
Perl executable is..............: lrwxrwxrwx 1 root root 35 Apr 11 11:44 /opt/maxdaemon/daemon/bin/perl -> /opt/maxdaemon/perl/5.26.1/bin/perl

Network Prerequisites

An HTTP daemon requires some prerequisites to run properly. Namely, the IP address of the Ethernet/PPP interface and the host and domain names (FQDNs) under which you want to access the daemon. Various modes can be configured:

  • Localhost (e.g. http://localhost:8000/, http://127.0.0.1:8000/).
  • IP-based host (e.g. http://192.168.0.1:8000/).
  • Name-based virtual host (e.g. https://www.local.net/).

Localhost

For development and test purposes you can configure the daemon to listen to the local loopback device, but the server cannot be reached via a network. This is the default configuration after installation (http://127.0.0.1:8000/).

IP-based Host

You can configure the Maxdaemon to listen to the IP address of your Ethernet/PPP interfaces. If the network is configured accordingly, the daemon is then accessible via the IP address. By the way, an HTTPD answering requests to an IP address is quite interesting, if the IP address is the dynamic address of the pppd (Point-to-Point Protocol Daemon) interface address. This enables end devices (e.g. mobil phones) to directly communicate with each other, provided they know their antagonist, maybe exchanged by a 'connect dynamic pppd IPs' switch server.

Name-based Virtual Hosts

To run a name-based virtual host daemon, the FQDNs (Full Qualified Domain Name) of all virtual hosts have to be configured by an Internet service provider or can be configured locally, for development and test purposes.. In both cases a 'hostname --fqdn' should yield a FQDN e.g.:

  > hostname --fqdn
  www.local.net # example FQDN

In combination with the ports, this FQDN can then be used as the URL under which Maxdaemon and the web surface can be accessed, e.g.:

  http://www.local.net:8000/ # HTTP requests
  https://www.local.net:8001/ # HTTPS requests

Host and Server Configuration

Host Name and IP Configuration

It is assumed, that the IP address of the host dev.local.net is 192.168.0.3, a second ethernet device with the IP 192.168.0.4 is configured with the host name dev.local.net. To set up a the host name and IP address do something like:

> su - root
> vi /etc/hosts                                # add IP and hostnames
  192.168.0.3     dev.local.net dev
  192.168.0.4     devdaemon.local.net devdaemon
> hostnamectl set-hostname dev                 # add hostname, changes /etc/hostname

# Shell session - temporarily
> ifconfig eth0 192.168.0.3 netmask 255.255.255.0 up
> ifconfig eth0:1 192.168.0.4 netmask 255.255.255.0 up # second Ethernet device

# Boot - permanent
> vi /etc/network/interfaces # Add the following lines:
  iface eth0 inet static
  address 192.168.0.3
  netmask 255.255.255.0

  # Add a second interface:
  iface eth0:1 inet static
  address 192.168.0.4
  netmask 255.255.255.0
  auto eth0 eth0:1

# Then restart the Ethernet interface:
> /sbin/ifdown eth0
> /sbin/ifup eth0
> /sbin/ifup eth0:1

# Show ethernet configuration
> ifconfig
eth0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.0.3  netmask 255.255.255.0  broadcast 192.168.0.255
        ether 00:24:8c:95:47:3a  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0:1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.0.4  netmask 255.255.255.0  broadcast 192.168.0.255
        ether 00:24:8c:95:47:3a  txqueuelen 1000  (Ethernet)

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10>host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 24951  bytes 1518667 (1.5 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 24951  bytes 1518667 (1.5 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# Maxscape configuration
> vi /maxscape/etc/httpd-2.4.29.conf # IP setup
Listen 192.168.0.3:80
Listen 192.168.0.3:2080

<IfModule ssl_module>
  Listen 192.168.0.3:443
</IfModule>

# change the hostnames
> vi /maxscape/server/*/etc/httpd-2.4.29.conf

> vi /maxscape/etc/License # add entry
my %License = (
#>LICENSE_STRING
  'dev.local.net/?%%?/192.168.0.3'  =#> 'Max;3.00;2024;350;msql:mysql:oracle:;',
#>/LICENSE_STRING<
);

> vi /maxscape/server/WebServer/etc/maxscape.conf
<item key="Page.postOnLocalHost">https://dev.local.net:2080/User/www.fcg</item>

# edit max's management server's home page...

# Maxdaemon configuration
> vi $MAXDAEMON_INSTALLATION_ROOT/maxdaemon/etc/profile
HOST_NAME=`hostname`
DOMAIN_NAME=`domainname`
if [ "$HOST_NAME" = "dev" -a "$DOMAIN_NAME" = "local.net" ]; then
  MAXDAEMON_HOST_IP=192.168.0.4
  MAXDAEMON_HOST_NAME=devdaemon.local.net
fi

Local Name-based Virtual Hosts

For development and test purposes, FQDNs can easily be configured locally. To configure a FQDN locally, some lines in the '/etc/hosts' file might be enough. Maybe you need to configure the Ethernet device (e.g. with 'ifconfig eth0', '/sbin/ifdown eth0', '/sbin/ifup eth0', '/bin/domainname local.net', '/etc/rc.local', /etc/network/interfaces).

> vi /etc/hosts
...
192.168.0.1     www.local.net
192.168.0.1     www-2.local.net
...
192.168.0.2     maxdaemon.local.net
192.168.0.2     test.local.net
192.168.0.2     template.local.net
...

Note, that to run a name-based virtual host, the 'hostname' and the 'domainname' of the host must be set properly. For example:

# Set your Ethernet network interface IP to e.g. '192.168.0.1',
# if it isn't configured, already:

# Shell session - temporarily
> su - root
> ifconfig eth0 192.168.0.1 netmask 255.255.255.0 up
> ifconfig eth0:1 192.168.0.2 netmask 255.255.255.0 up # second Ethernet device

# Boot - permanent
> su - root
> vi /etc/network/interfaces

# Add the following lines:
iface eth0 inet static
address 192.168.0.1
netmask 255.255.255.0
auto eth0

# Maybe add a second interface:
# iface eth0:1 inet static
# address 192.168.0.2
# netmask 255.255.255.0
# auto eth0 eth0:1

# Then restart the Ethernet interface:
> /sbin/ifdown eth0
> /sbin/ifup eth0
> # /sbin/ifup eth0:1
> ifconfig
eth0      Link encap:Ethernet  HWaddr 00:24:8c:95:22:68  
          inet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

If eth0:1 is configured:
eth0:1    Link encap:Ethernet  HWaddr 00:24:8c:95:22:68  
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
 ...

Define the server's domainname, if it isn't configured, already:
> domainname local.net

A good place for these commands at boot time is '/etc/rc.local':
> vi /etc/rc.local
# add the following lines:
/sbin/ifup eth0
/bin/domainname local.net

Now, define the FQDN's locally in '/etc/hosts':
> vi /etc/hosts
...
192.168.0.1     www.local.net
192.168.0.1     www1.local.net
...
192.168.0.1     wwwn.local.net
...

Running Maxdaemon as 'root' and at Boot Time

To start Maxdaemon as the 'root' user and at boot time, the Maxdaemon shell environment needs to be configured:

# File: ~/.profile
==================

MAXDAEMON_INSTALLATION_ROOT=/opt/maxdaemon; export MAXDAEMON_INSTALLATION_ROOT;

There are several ways to do that, and there is a distinction between login and boot shells. To set the required enviroment for Maxdaemon to the root user login shell, you can either execute the Maxdaemon profile in your '~/.profile' or you can call the 'sp' script from the command line. The 'sp' command launches the 'tcsh' shell (if available), in order to make use of the Maxdaemon 'tcsh' aliases:

# Assumes a Perl installation below /opt/perl/<Perl version>
> sp -p optperl -c fqdn
> maxdaemon restart

To launch Maxdaemon at boot time see the example script: maxdaemon.etc.init.d.sh or man maxdaemon.etc.init.d.sh.

SSL Certificate Creation

The HTTPS protocol requires SSL certificates that must be known by the HTTP server. To create them, you can use the 'certificate' script.

# Maxdaemon SSL certificate directory: 
> certificate 127.0.0.1
> ls /maxdaemon/etc/ssl
ca.crt ca.csr ca.key ca.key.crypt server.crt server.csr server.key server.key.crypt

# Application server SSL certificate directory: 
> certificate -w <application server> 127.0.0.1
> ls /maxdaemon/server/<application server>/etc/ssl
ca.crt ca.csr ca.key ca.key.crypt server.crt server.csr server.key server.key.crypt

The creation of several name based SSL hosts is a bit tricky, as you need to know the complete list of all virtual host names, beforehand. This list must then be passed to each call of the 'certificate' script, using the '-a <List of all virtual host names>' option.

To only create a SSL certificate for the Maxdaemon web surface, and if your virtual host name (FQDN) is 'www.local.net', enter (use another serial number, if '00' dosn't work):

> certificate -a URI:www.local.net -s 00 www.local.net

# Or if you have no FQDN configured, e.g.:
> certificate -a URI:127.0.0.1 -s 00 127.0.0.1
> certificate -a URI:192.168.0.1 -s 00 192.168.0.1

# Or do it by hand, if you don't want a name-based virtual SSL host:
> cd <ssl folder>
> openssl genrsa -des3 -out server.pass.key 1024
> openssl req -new -key server.pass.key -out server.csr
> openssl rsa -in server.pass.key -out server.key
> openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt

To create the SSL certificates for the Maxdaemon web surface and the 'Test' and 'Template' application server examples, enter:

# maxdaemon.local.net   - Maxdaemon's web surface FQDN
# test.local.net        - 'Test's virtual host name
# template.local.net    - 'Template's virtual host name
# List of virtual hosts = "URI:maxdaemon.local.net,URI:test.local.net,URI:template.local.net"

> certificate -a <List of virtual hosts> -s 00 maxdaemon.local.net
> certificate -w Test -a <List of virtual hosts> -s <> 01 test.local.net
> certificate -w Template -a <List of virtual hosts>  -s 02 template.local.net

Don't be surprised, when you get a warning from Firefox that your certificate isn't trusted, because it is 'self-signed'. Some browsers refuses 'self-signed' certificates altogether. Self-signed simply means that the certificate isn't authorized by a third party. Buy a certificate to get ride of that warning.

Note, that you might have to delete your browser's Maxdaemon certificates (see browser preferences), if you reinstall Maxdaemon. Otherwise your browser might refuse to connect the Maxdaemon SSL server! Sometimes my firefox gets confused with its certificates, then I simply delete the '~/.mozilla/firefox/*.default' 'cert8.db' and 'cert_override.txt' files. Beware that this deletes all your certificates besides the default ones!

Work Flow Examples

Please note, that actual changes via the web surface are preserved for registered users by default. On production sites you might want to disable the public surface, altogether. Have in mind also, that the surface is meant to be an addition to shells and other tools, not a replacement. To (re)start/stop the server you definitely need a command line shell.

Static Content

Publishing static content is as simple as placing the related text and media files in an application server's document tree. If you have files with MIME types not listed in the global HTTPD MIME type configuration file ('~/etc/mime_types.conf'), it is mostly sufficient to add them with an 'AddType' directive entry.

Lets exercise some examples. Assuming you are working on the 'Test' application server, traverse to the Test server's 'DocumentRoot'. Maybe, choose the 'Edit Layout' via the menu (☰), to hide the surface page header and to fix the action button bar.

As a registerd user you would have logged in first, to be able to actually make changes. Click the 'new file' button and enter a file name, whereby the file name extension determines, how the file is rendered at runtime. An extension correlates to its MIME type, which then determines the server's action.

Say, your file name is 'MyTest.txt'. Enter some text, click 'change' and then right-click the base name of the shown file path and say 'Open Link in New Tab' (Firefox) to display the your page in another browser tab (display tab). Alternatively, click on the menu symbol (☰) to open another tab. Because the file extension is 'txt' the content is believed to be of MIME type 'text/plain'. Therefore the server sends the following response:

HTTP/1.1 200 OK
date: Sun, 1 Apr 2018 00:18:42 GMT
server: Maxdaemon/1.0.0
content-type: text/plain; charset=utf-8;
content-length: 22
last-modified: Sun, 1 Apr 2018 00:18:42 GMT
connection: close

Hallo, this is some text.

The server's response consists of the HTTP headers and the actually displayed page. Because the content type is 'text/plain', the browser just displays what you have written without rendering it.

For the next example, leave 'MyTest.txt' by clicking the 'htdocs' part of the shown file path, which leads you back to Test's document root. Now, create a file with an 'html' extension, say 'MyTest.html'. Maybe copy and paste the source code from elsewhere. If you need a HTML tag template, you might want to use the HTML help via the '?' menu) to copy and paste the desired tag.

To edit an existing file, press the 'edit' button and select the wanted file via the radio widget. Edit the file and then press 'change' to store the changes. When working with big files, select a text snipped that you can search for with the browser's search function, before you press 'change' to leave out nasty page scrolling.

For not registered users changes are disabled, so I have copied and pasted the following HTML code, which is based on the Holy Grail example from developer.mozilla.org, beforehand. Best use Firefox for this example, as other browsers might need a '-webkit' in front of some CSS properties.

By the way, writing HTML source code is easier than most laymen might think. Often is it simpler than using a WYSIWYG editor that tries to hide the difficulties and at least more flexible (see the experimental Maxdaemon::WYSIWYG class for using an WYSIWYG editor).

File: ~/server/Test/htdocs/MyTest.html:
=======================================

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Page Title</title>
  </head>
  <body>
    <header>Header</header>
    <main>
      <nav>Navigation</nav>
      <article>Article</article>
      <aside>Aside</aside>
    </main>
    <footer>Footer</footer>
  </body>
</html>

Click 'change' and display the result in another browser tab. The basic parts of a web page are shown. To make it look more nicely, we add a style sheet (place it in between the <head> tag):

<style type="text/css">
    body {
        margin: 0px;
        padding: 0px;
        font: 24px Helvetica;
        background: #999999;
    }
    main {
        min-height: 800px;
        margin: 0px;
        padding: 0px;
        display: flex;
        flex-flow: row;
    }
    main > article {
        margin: 4px;
        padding: 5px;
        background: #dddd88;
        flex: 3 1 60%;
        order: 2;
    }
    main > nav {
        margin: 4px 4px 4px 0px;
        padding: 5px;
        background: #ccccff;
        flex: 1 6 20%;
        order: 1;
    }
    main > aside {
        margin: 4px 0px 4px 4px;
        padding: 5px;
        background: #ccccff;
        flex: 1 6 20%;
        order: 3;
    }
    header, footer {
        display: block;
        margin: 0px;
        padding: 5px;
        min-height: 100px;
        background: #ffeebb;
    }
    /* Too narrow to support three columns */
    @media all and (max-width: 640px) {
        header, footer {
            font: 16px Helvetica;
        }
        main {
            font: 16px Helvetica;
            flex-direction: column;
        }
        main > article, main > nav, main > aside {
            margin: 4px 0px;
            order: 0; /* Return to document order */
        }
        main > nav, main > aside, header, footer {
            min-height: 50px;
            max-height: 50px;
        }
    }
  </style>

Reload the page in the display tab. Note, that this page is responsive, so when displayed on a screen with less than 640 pixel the order of the page parts and the font size adapt to the view port of the screen (shrink your browser window for a test).

Dynamic Content

Though the last example doesn't seem to be so static, the content is. So, for dynamic pages, we use CGI scripts to generate the content on the fly. The most simple Perl CGI script is shown below:

File: /server/Template/htdocs/hello.cgi
=======================================

#!/opt/maxdaemon/daemon/bin/perl

package main;
use strict;

my $CRLF = "\015\012";

my $Header  = "Content-type: text/plain$::CRLF";
my $Content = 'Hello world.';

print $Header . $::CRLF . $Content;
1;

Copy this file with a command line shell in an Xterm or the surface.

Web surface:
============

Go to the '~/server/Template/htdocs' folder, click 'copy file', select 'hello.cgi'
via the radio button, enter the destination path in the input field (/server/Test/htdocs/hello.cgi)
and click 'copy file', again.

Command line:
=============

> su - maxdaemon
> ms # tcsh alias for 'cd $MAXDAEMON_HOME/server'
> cp -p Template/htdocs/hello.cgi Test/htdocs/MyTest.cgi
> cd Test/htdocs
> vi MyTest.cgi

After this, the surface displays an hyper link ('MyTest.cgi') below the '/server/Template/htdocs' folder. Click on it, to display 'Hello world.' and then edit the script. Take the author, copyright, a.s.o and the perlpod at the end of the file as a template for your data. You can later add the script's perlpod to the on-line man pages by adding two lines to '~/bin/makeManual.sh'.

Next, we want to combine the above HTML example with a CGI script. So, we create a new file, say 'MyTest+HTML.cgi' by copying 'hello.cgi.

There are numerous ways to generate content within a CGI programming environment, indeed. In a first attempt, we could copy the HTML text into the CGI script and make it a Perl variable that we then print. Obviously, this is not a to good idea, because the content (HTML text) and the application code (script) are mixed in the same file.

Instead, we better read the text from a file (e.g. 'MyTest+CSS.html') then we have separate storage places for the content and the application script. In the example below, the 'Maxdaemon::PageByPathInfo' class is used to do just that.

To adapt the code to the CGI environment, we have to consider under which application server we like to run the script. Normally, because we are working on the 'Test' application server, we have configured a name-based virtual host (e.g. 'test.local.net'), beforehand. The address is then 'http://test.local.net/MyTest+HTML.cgi'.

For test purposes, we can run it also under the 'Maxdaemon' surface server via the address 'http://maxdaemon.local.net/server/Test/htdocs/MyTest+HTML.cgi', but then we need to tell the 'generatePage' method via the 'PageRoot' parameter where to find the pages to be displayed.

Please note the call of the 'pe' (print to error log) function. It prints a message to the error log file, which is either STDERR or the error log of the related application server. For development you might also want to use the 'pd' resp. 'pdd' functions (see: 'Globals' man page).

To watch the output, open a Xterm, restart the server and reload the page in the browser.

File: /server/Test/htdocs/MyTest+HTML.cgi
=========================================

#!/opt/maxdaemon/daemon/bin/perl
###############################################################################
package main;
use strict;

sub BEGIN {
  # Tell Perl where to find Maxdaemon.
  unshift(@INC, "$ENV{MAXDAEMON_HOME}/lib");
  eval ("use Maxdaemon::Globals;");
  Maxdaemon::Globals::checkProjectEnvironment(0);
}
use Maxdaemon::PageByPathInfo;

###############################################################################

my $DocumentRoot = $ENV{DOCUMENT_ROOT};
my $PageRoot = '';

if ($DocumentRoot eq "$::MAXDAEMON_HOME") {
  $PageRoot = "$DocumentRoot/server/Test/htdocs";
}
elsif ($DocumentRoot eq "$::MAXDAEMON_HOME/server/Test/htdocs") {
  # $PageRoot = '';
} else {
  pe ("MyScript: DocumentRoot ($DocumentRoot) not found!");
}

pe ("MyScript: PageRoot=$PageRoot.");

my ($Content, $HTTP_Header, $Status) = Maxdaemon::PageByPathInfo->new->generatePage (
      PageRoot        => $PageRoot,
      defaultPageName => '/MyTest+CSS.html',
);

print $$HTTP_Header . $$Content;
1;
__END__
###############################################################################

Tcsh Shell in a Xterm:
======================

> maxdaemon restart       # print diagnostics to STDERR
or
> maxdaemon -l restart    # print diagnostics to the server's error log

> de # tcsh alias to displays the error logs:
MyScript: PageRoot=/opt/maxdaemon/daemon/server/Test/htdocs.

> da # tcsh alias to displays the access logs:
==> /opt/maxdaemon/daemon/var/logs/maxdaemon-access.log <==
192.168.0.1 - - [04/Apr/2018:14:11:07 +0000] "GET /server/Test/htdocs/MyTest+HTML.cgi HTTP/1.1" 200 1735 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0"

Now, we fill our page with life by adding Perl code to the (HTML) text. Therefore we create a file with the extension '.phtml' (Perl parsed HTML). So, copy 'MyTest.html' to 'MyTest+CSS.phtml'.

There are several ways to embed Perl code within a text file. One is to read the file into a string variable and let Perl's 'eval' function do the variable substitution and the execution of the embedded function calls. Then the text has become a Perl string that is evaluated by the Perl interpreter. An additional parser is then not required, instead Perl is doing the job, and even better Perl's string evaluation is pretty fast.

How the embedded variables are substituted and which methods are called is defined by the (lexical) context in which the string is evaluated. This gives us the possibility to pass variable values and objects from the script into the text.

Well, when we now execute the script by reloading the page we get an error, because Perl believes that '@media' in the HTML text is an undeclared array. Therefore, we need to escape characters special to the Perl interpreter (e.g. $, @) with a backslash.

There are several possibilities to name, store and pass embedded variables. When the string evaluation takes place in the scope of the 'Maxdaemon::PageByPathInfo' class, we can define variables/objects as members of the '$Page' object.

To embed the '$CGI->Query ('Article')' method call within the document text, we simply use a so called closure (@{[ <your function/method call> ]}). Thank you Perl!

To make the page really dynamic, we also add a CGI interface object and use the CGI query string to control the script behaviour.

File: /server/Test/htdocs/MyTest+CSS.phtml:
===========================================
...
<header>$Page->{Data}->{header}</header>
...
<article>@{[ $Page->{CGI}->Query ('Article') ]}</article>
...
<footer>$Page->{Data}->{Footer}</footer>
...

File: /server/Test/htdocs/MyTest+PHTML.cgi
==========================================
...
use Maxdaemon::PageByPathInfo;
use Maxdaemon::CGI;
...
my $Page = Maxdaemon::PageByPathInfo->new;
my $CGI = Maxdaemon::CGI->new;

$Page->{CGI} = $CGI;

$Page->{CGI}->Query ('Article')
  || ($Page->{CGI}->{Article} = "Append '?Article=DynamicArticle' to the location");

$Page->{Data}->{Header} = "Generated Page Header";
$Page->{Data}->{footer} = "Generated Page Footer";

my ($Content, $HTTP_Header, $Status) = $Page->generatePage (
      PageRoot          => $PageRoot,
      defaultPageName   => '/MyTest+CSS.phtml',
);
...

Browser location e.g.:
======================

http://maxdaemon.local.net/server/Test/htdocs/MyTest+PHTML.cgi?Article=DynamicArticle

or use the path info (e.g. PATH_INFO=/MyTest.phtml) to address a special page:

http://maxdaemon.local.net/server/Test/htdocs/MyTest+PHTML.cgi/MyTest+CSS.phtml?Article=Hello world

By now, we have created a basic tool kit to implement dynamic pages. The layout is defined by the (responsive) style sheet and separated from the (HTML) content. By embedding Perl variables and method calls within the document, the (HTML/CSS) text is (greatly) separated from the CGI script code, also. So, we can think in terms of a (dynamic) text with an embedded API instead of pondering about a program that outputs the text.

The next steps are to turn 'MyTest.cgi' into a SCGI, maybe a DCGI and/or a FCGI (for Apache) script to optimize the execution speed and to implement an application, of course. For a more elaborated example, have a look at the '~/server/Test/htdocs/www.cgi' CGI and the '~/server/Test/htdocs/www.scgi' SCGI scripts (e.g.: http://test.local.net/).

Each part of the page is now stored in an own file, so these parts can easily be reused by other pages. Candidates that might be reused are located below the 'template' and parts that contains real content below the 'element' folders.

File: ~/server/Test/htdocs/www.phtml:
====================================

<!DOCTYPE html>
<html>

  <head>
    @{[ $Page->Template (Name => 'DocumentHeader', Type => 'parse') ]}
  </head>

  <body>
    <header>
      @{[ $Page->Template (Name => 'PageHeader', Type => 'parse') ]}
    </header>
    <main>
      <nav>
        @{[ $Page->Template (Name => 'PageNavigation', Type => 'parse') ]}
      </nav>
      <article>
        @{[ $Page->Element (Name => 'Index', Type => 'parse') ]}
      </article>
      <aside>
        @{[ $Page->Template (Name => 'PageAside', Type => 'parse') ]}
      </aside>
    </main>
    <footer>
      @{[ $Page->Template (Name => 'PageFooter', Type => 'parse') ]}
    </footer>
  </body>
</html>

File: ~/server/Test/htdocs/template/DocumentHeader.phtml:
========================================================

<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Test Page</title>
<link href="$Page->{Data}->{FolderPrefix}/css/www.css" rel="stylesheet" type="text/css"/>

<script src="$Page->{Data}->{FolderPrefix}/javascript/Maxscape/Typewriter.js" type="text/javascript"></script>
<script src="$Page->{Data}->{FolderPrefix}/javascript/Maxscape/Clock.js" type="text/javascript"></script>

File: ~/server/Test/htdocs/template/PageHeader.phtml:
====================================================

<table id="PageHeaderTable" width="100%" summary="Header Table" cellpadding="0" cellspacing="0">
  <tr>
   <td style="padding: 10px 10px 0px 0px; height: 80px;" align="left" valign="bottom">
     <a id="PageHeaderTableText" href="/www.scgi">$Page->{Data}->{Header}</a>
   </td>

   <td align="right" valign="top">
   </td>
 </tr>
</table>

File: ~/server/Test/htdocs/template/PageNavigation.phtml:
========================================================

Navigation

File: ~/server/Test/htdocs/element/Index.phtml:
=============================================

<h2>Test CGI Script</h2>
...

File: ~/server/Test/htdocs/template/PageAside.phtml:
===================================================

<canvas id="canvas" width="150" height="150"></canvas>
  <script type="text/javascript">
    window.requestAnimationFrame (clock);
</script>

File: ~/server/Test/htdocs/template/PageFooter.phtml:
===================================================

$Page->{Data}->{Footer}

Application Module Plug-in

Normally, a main script is not a good place for application modules, which should better be placed e.g. in the 'ServerApplication.pm' file that is imported, if it exists. So, if an appliction server is created with the 'createAppServer' script, the file '~/server/<app server name>/lib/ServerApplication.pm' contains a package (Maxdaemon::<app server name>) that can be used as a starting point to implement an applications.

The 'PageContextCallback' method is used to push variables into the name space of pages and page elements/templates, so that they can be embedded in '*.phtml' files by their name (see Maxdaemon::PageByPathInfo, also).

File: ~/server/<app server name>/lib/ServerApplication.pm:
=========================================================

sub PageContextCallback {
  my $Page = shift;
  my $p = shift;

  $Page->embedVariables (
    VariableName => 'variable name',
  );

  return '';
}

Use a variable in '*.phtml' files by name:
==========================================

<html>
...
Simply use a variable by the $VariableName.
...
</html>

Third Party Products

Maxdaemon uses the following third party products:

Product Authors License
Perl Larry Wall and the Perl community Perl Artistic
Openssl The OpenSSL Project Authors The License
Cwd Perl 5 porters (Maintained by Ken Williams) Perl Artistic
Data::Dumper Gurusamy Sarathy Perl Artistic
Digest::MD5 Gisle Aas, Neil Winton and RSA Data Security, Inc. Perl Artistic
Encode Dan Kogai Perl Artistic
Fcntl ? ?
File::Basename ? ?
File::Copy Aaron Sherman and Charles Baile Perl Artistic
Filter::Crypto Steve Hay Perl Artistic or GPL
Getopt::Long Johan Vromans Perl Artistic or GPL
IO::Socket Graham Barr, Lincoln Stein and the Perl Porters Perl Artistic
IO::Socket::INET6 Graham Barr, Rafael Martinez Torres, Shlomi Fish and Euro6IX project. Perl Artistic
IO::Socket::UNIX Graham Barr Perl Artistic
MIME::Base64 Gisle Aas Perl Artistic
Net::Domain Graham Barr, David Sundstrom and Steve Hay Perl Artistic
Net::hostent Tom Christiansen ?
Net::SSLeay Sampo Kellomaeki, Florian Ragwitz and Mike McCauley Perl Artistic 2.0
Pod::Usage Marek Rouchal and Brad Appleton ?
POSIX ? ?
RPM Marc Ewing, Jeff Johnson, Erik Troan Red Hat ?
Socket Perl 5 Porters and Paul Evans ?
Time::HiRes Douglas E. Wegscheid, Jarkko Hietaniemi and Andrew Main Perl Artistic

The Maxdaemon distribution also contains the following software packages that are used in example and test applications or just for convenience:

Product Authors License
Apache Apache Software Foundation Apache License
Apache::LogFormat::Compiler Masahiro Nagano Perl Artistic
HTTP::Entity::Parser Masahiro Nagano and Tokuhiro Matsuno Perl Artistic
bareword::filehandles Dagfinn Ilmari Mannsåker Perl Artistic
Catalyst::Runtime Perl Artistic
CGI Lincoln D. Stein and others ?
CGI::Fast Lincoln D. Stein Perl Artistic
CGI::Simple ? ?
CGI::Struct Matthew Fuller Perl Artistic
Class::Data::Inheritable Damian Conway, Michael G Schwern and Tony Bowden Perl Artistic
Class::Load Shawn M Moore Perl Artistic
Class::Inspector Adam Kennedy Perl Artistic
Class::Method::Modifiers Shawn M Moore Perl Artistic
Clone Ray Finch Perl Artistic
Cookie::Baker Masahiro Nagano Perl Artistic
Data::Dump Gisle Aas and Gurusamy Sarathy Perl Artistic
Data::Dumper::Concise Matt S. Trout and Arthur Axel Perl Artistic
Data::OptList Ricardo Signes Perl Artistic
Dancer Alexis Sukrieh Perl Artistic
DBI/DBD Tim Bunce Perl Artistic
DBD::mysql Patrick Galbraith, Michiel Beijen and others Perl Artistic
Devel::GlobalDestruction Yuval Kogman, Florian Ragwitz, Jesse Luehrs, Peter Rabbitson, Arthur Axel, 'fREW' Schmidt, Elizabeth Mattijsen and Greham Knop Perl Artistic
Devel::StackTrace Dave Rolsky Perl Artistic 2.0
Devel::StackTrace::AsHTML Tatsuhiko Miyagawa and Shawn M Moore Perl Artistic
Devel::Hide Adriano R. Ferreira Perl Artistic
Encode::Locale Gisle Aas Perl Artistic
ExtUtils::Config Ken Williams and Leon Timmermans Perl Artistic
ExtUtils::Helpers Ken Williams and Leon Timmermans Perl Artistic
ExtUtils::InstallPaths Ken Williams and Leon Timmermans Perl Artistic
FCGI Open Market, Inc. Free
FCGI::ProcManager James E Jurach Jr and Gareth Kirwan GNU Lesser General Public License
File::Remove Shlomi Fish Perl Artistic
Filesys::Notify::Simple Tatsuhiko Miyagawa Perl Artistic
File::Listing Gisle Aas Perl Artistic
File::ShareDir Adam Kennedy Perl Artistic
GD Lincoln D. Stein Perl Artistic
gitweb Kay Sievers, Christian Gierke GPLv2
Hash::Merge by David Golden, Ricardo Signes, Adam Kennedy and Contributors Perl Artistic
Hash::MultiValue Tatsuhiko Miyagawa, Aristotle Pagaltzis and Hans Dieter Pearcey Perl Artistic
HTML::Parser Gisle Aas and Michael A. Chase Perl Artistic
HTTP::Cookies Gisle Aas Perl Artistic
HTTP::Body Christian Hansen, Sebastian Riedel, Christian Walde and Torsten Raudssus Perl Artistic
HTTP::Daemon Gisle Aas Perl Artistic
HTTP::Negotiate Gisle Aas Perl Artistic
HTTP::Request::AsCGI Christian Hansen, Hans Dieter Pearcey Perl Artistic
HTTP::Server::Simple Jesse Vincent, Marcus Ramberg, Sam Vilain Perl Artistic
HTTP::Server::Simple::PSGI Tokuhiro Matsuno, Kazuhiro Osawa and Tatsuhiko Miyagawa Perl Artistic
HTTP::Headers::Fast Tatsuhiko Miyagawa Perl Artistic
HTTP::Message Gisle Aas Perl Artistic
HTTP::Date Gisle Aas Perl Artistic
inc::latest David Golden and Eric Wilhelm Apache License 2.0
indirect Vincent Pit Perl Artistic
IO ? ?
IO::Socket::IP Paul Evans ?
IO::Socket::SSL Marko Asplund, Peter Behroozi and Steffen Ullrich Perl Artistic
IPC::Signal Roderick Schertler ?
IPC::Shareable Benjamin Sugars ?
jQuery Sebastian Senf and jQuery Foundation MIT & GPL
JSON Makamaka Hannyaharamitu and Marc Lehmann Perl Artistic
JSON::MaybeXS Matt S. Trout Perl Artistic
jQuery-ui jQuery Foundation and contributors See LICENSE.txt file
List::MoreUtils Tassilo von Parseval and by Jens Rehsack Perl Artistic
LWP::MediaTypes Gisle Aas Perl Artistic
LWP::Protocol::https Gisle Aas Perl Artistic
LWP (libwww) Gisle Aas and Martijn Koster Perl Artistic
libgd See COPYING file See COPYING file
MIME::Types Mark Overmeer Perl Artistic
mod_perl ? Apache License
Module::Runtime Andrew Main Perl Artistic
Module::Build Ken Williams Perl Artistic
Module::Install Adam Kennedy, Audrey Tang and Brian Ingerson Perl Artistic
Module::ScanDeps Audrey Tang and Steffen Mueller Perl Artistic
Module::Install::ExtraTests Ricardo Signes Perl Artistic
Module::Install::AuthorTests Ricardo Signes Perl Artistic
Moo Matt S. Trout Perl Artistic
Mojolicious Sebastian Riedel and others Perl Artistic
MooseX::Getopt Stevan Little Perl Artistic
MRO::Compat Brandon L. Black Perl Artistic
Mysql ? GPL 2 or Commercial license by Oracle
Module::Build::Tiny Leon Timmermans and David Golden Perl Artistic
namespace::autoclean Florian Ragwitz Perl Artistic
namespace::clean Robert 'phaylon' Sedlacek, Florian Ragwitz, Jesse Luehrs, Peter Rabbitson and Father Chrysostomos Perl Artistic
Net::HTTP Gisle Aas Perl Artistic
Net::Server Paul Seamons Perl Artistic
Net::Server::HTTP Paul Seamons Perl Artistic
Parallel::Prefork ß ?
Server::Starter Kazuho Oku Perl Artistic
Path::Class Ken Williams Perl Artistic
Plack Tatsuhiko Miyagawa, Tokuhiro Matsuno, Jesse Luehrs, Tomas Doran and Graham Knop Perl Artistic
POSIX::strftime::Compiler Masahiro Nagano Perl Artistic
PSGI Tatsuhiko Miyagawa Creative Commons license by-sa
Role::Tiny Matt S. Trout Perl Artistic
Server::Starter Kazuho Oku Perl Artistic
Starlet Kazuho Oku, Miyagawa, Kazeburo and Tomohiro Takezawa Perl Artistic
Starman Tatsuhiko Miyagawa Perl Artistic
Safe::Isa Matt S. Trout Perl Artistic
Stream::Buffered Tatsuhiko Miyagawa Perl Artistic
Sub::Quote Matt S. Trout Perl Artistic
Syntax::Keyword::Gather Arthur Axel, "fREW" Schmidt and Damian Conway Perl Artistic
Test::Requires Tokuhiro Matsuno Perl Artistic
Test::Most ? ?
Test::SharedFork Tokuhiro Matsuno Perl Artistic
Test::TCP Tokuhiro Matsuno Perl Artistic
Test::NoWarnings Fergal Daly and Adam Kennedy Perl Artistic
Test::YAML Ingy döt Net Perl Artistic
Try::Tiny Yuval Kogman and Jesse Luehrs MIT (X11) License
Socket6 ? ?
strictures Matt S. Trout Perl Artistic
Sub::Exporter::Progressive Arthur Axel Perl Artistic
Task::Weaken Adam Kennedy Perl Artistic
TermReadKey Kenneth Albanowsk, Kenneth Albanowski, Jonathan Stowe and others Perl Artistic
Test::RequiresInternet Mark Allen Perl Artistic
Test::Fatal Ricardo Signes Perl Artistic
Text::SimpleTable Sebastian Riedel and Marcus Ramberg Perl Artistic
Time::ParseDate David Muir Sharnoff and Google Inc. Free
URI Gisle Aas, Tim Bunce, Roy Fielding and Martijn Koster Perl Artistic
warnings::illegalproto Arthur Axel "fREW" Schmidt Perl Artistic
Web::Simple Matt S. Trout Perl Artistic
WWW::Form::UrlEncoded Masahiro Nagano Perl Artistic
WWW::RobotRules Gisle Aas and Martijn Koster Perl Artistic
XML::Dumper Mike Wong Perl Artistic
XML::Parser Larry Wall, Clark Cooper and Matt Sergeant
YAML Ingy döt Net Perl Artistic
YAML::Tiny Adam Kennedy Perl Artistic

Limitations

Maxdaemon is developed and tested under Ubuntu Linux, but should run under other Unix derivations with minor changes, too. There is no Windows version, so far. Please note, that the Maxdaemon HTTPD is published for the first time and has never been used or tested by anybody else than myself. So, at this point in time, I recommend to use an Apache/FastCGI or another configuration on mission critical production sites as the main HTTP daemon. For more limitations have a look at the 'To Do' list.

Also note, that this manual page is a draft. It is neither comprehensive nor is it complete, and there is only this Denglish version, so far. Nevertheless the code mostly speaks for itself and there are quite a few useful comments and hints in the code.

Bugs

  1. I am sure that there are quite a few. It would be nice, if you tell me about them.
  2. Error log messages of apps are in some situations written to main error log.
  3. In a few situations, the server isn't stopped properly. Use the 'killall perl ' or 'kill -9 <process ids>' commands.

To Do

  1. Portation to other operating systems than Ubuntu.
  2. Speed optimization.
  3. Configuration directives needs to be documented, decently.
  4. Configuration error handling needs to be worked out.
  5. The configuration structure hash should be made global (shm?).
  6. A real reload for maxdaemon restart, instead off killing.
  7. An automatic restart of SCGI processes after changes.
  8. Application process management should be evolved.
  9. An own logger daemon would be nice.
  10. Server seek mode for audio and video files (Maybe solved).
  11. Add Transfer-encoding handling.
  12. Add more generic 'WebSocket' support.
  13. Manifest permissions should be worked out.
  14. Adapt sources for all databases supported by DBI/DBD.
  15. DBD packages for other databases than Mysql.
  16. Add the user id cash to the control daemon.
  17. StatusMessage doesn't only belong to the Maxdaemon::Request class.
  18. Read the SSL encrypted key file instead of 'server.key'.
  19. Allow configuration file encrytion.
  20. SCGI client/server communication protocol optimization..
  21. SCGI client modules in other languages (PHP, C, Java, ..).
  22. SCGI keep-alive mode (reuse sockets to clients, instead of re-connect).
  23. Restart SCGI scripts on change.
  24. Javascript Editor for 'textarea' form fields.
  25. SSL/TLS handling should be worked out.
  26. Either the network code should be reviewed or/and exchanged IO::Socket::*.
  27. IPv6 support should be added (see above to do).
  28. Unicode handling should be worked out.
  29. Web Sockets HTTPS and process management required.
  30. Concurrent development extension for the web surface.
  31. Enhance set of web surface MIME type icons.
  32. Web surface handling (e.g. select Javascript handlers).
  33. Add WYSIWYGP code editor to web surface form <textarea> tag.
  34. A 'lock file' mechanism for concurrent editing via the web surface.
  35. Set up a real development server.
  36. Speed up the 'gp' script by using git.
  37. A decent manual.
  38. Don't show select buttons for non editable mime types..
  39. Solve the 'MH-todo:' comments in the sources.
  40. A lot more that can be done (see Limitations) ...

Copyright and License

The Maxdaemon 1.0.0 distribution is licensed under the terms of the: Maxdaemon Copyright and License.

Authors

Maxdaemon is written by Max (Dipl.-Ing Ernst Robert Maximilian Heinzelmann). The implementation is inspired by the Perl man pages, many modules of the Perl CPAN archives (CGI, FCGI, Socket, Socket::IO, Net::SSLeay, Filter::Crypto, DBD/DBI, LWP, ..), SelfHTML, Webmin, Mojolicious, the Apache HTTPD, FastCGI, Mysql and many other sources.

The program code includes ideas from the work of Larry Wall, Steven E. Brenner Tim Bunce, Gisle Aas, Lincoln Stein, Gurusamy Sarathy, Sampo Kellomaeki, Florian Ragwitz, Mike McCauley, Paul Evans, Steve Hay, Kellomaeki, Johan Vromans, Werner Bosse, Jamie Cameron, Sebastian Riedel, the Perl 5 Porters, the 'lwp' authors, the CPAN, the Apache, Mozilla, OpenSSL developers, Linus and the Linux people, just to name a few.

History

I began to write the predessor of Maxdaemon on 2000-01-02 from scratch, to have a control daemon for Maxscape's user authorization, process control and Licenses, what was quite fast achieved. Because the idea of replacing the Apache by an HTTPD written in Perl is so tempting, I redesigned this control daemon to perform as an HTTP daemon for Maxscape in 2014. Only in August 2017 I touched upon it again, to implement a more generic HTTPD that also supports name-based virtual SSL hosts, Unicode utf-8, a replacement for FastCGI and to develop and integrate Maxscape's file management web surface.

Table of Content

1
next ∙ previous ∙ Top ∙ Join ∙ Contact © Maxscape