Skip to content

Installation and Quickstart

WebDyne will install and run on any modern Linux system that has a recent version of Perl installed and is capable of installing Perl modules via CPAN. Installation via Docker is also supported.

When installing WebDyne there are two components which are required before you can begin serving PSP files:

  • The core WebDyne Perl modules

  • A web server or application configured to use WebDyne.

WebDyne will work with Apache mod_perl, PAGI or PSGI compatible web servers (such as Plack, Starman etc.).

Docker containers with pre-built versions of WebDyne are also available.

Quickstart

If using PSGI you can start a quick web server by creating a simple app.psp file:

#  Save this as app.psp
#
<start_html>
My first WebDyne page. Server time: <? localtime ?>

Then test install:

#  Install WebDyne
#
$ cpanm WebDyne

#  Render the file to STDOUT to see the HTML and check basic installation
#
$ wdrender app.psp

#  Install Plack if not already done.
#
$ cpanm Plack

#  Check all working
#
$ webdyne.psgi --test

#  Start serving only a single PSP file
#
$ webdyne.psgi app.psp

# Start serving files from the current directory. Directory requests use WebDyne's
# built-in index page by default.
#
$ webdyne.psgi .

# Start but listen on non-default port, only on localhost
#
$ webdyne.psgi --port=5001 --host=127.0.0.1

Connect your browser to the host and you should see the WebDyne output.

You can shortcut install of Plack/Starman versions via:

#  Install WebDyne Plack (PSGI)
#
$ cpanm Task::WebDyne::Plack


#  Or Starman. Note if Starman install fails you may need to force install of Net::Server via
#  cpanm --force Net::Server
#  and try again
#
$ cpanm Task::WebDyne::Starman

CPAN or CPANMinus Install

Install from the Perl CPAN library using cpan or cpanm utilities. Installs dependencies if required (also from CPAN).

Destination of the installed files is dependent on the local CPAN configuration, however in most cases it will be to the Perl site library location. WebDyne supports installation to an alternate location using the PREFIX option in CPAN. Binaries are usually installed to /usr/bin or /usr/local/bin, but may vary by distribution/local configuration.

Assuming your CPAN environment is setup correctly you can run the command:

perl -MCPAN -e "install WebDyne"

Or (with cpanminus if installed)

cpanm WebDyne

This will install the base WebDyne modules, which includes the Apache config utility and PSGI and PAGI versions. Note that Apache or PSGI/PAGI servers and dependencies (such as Plack or Starman) are not installed by default and need to be installed separately - see the relevant section, or just run:

cpanm Task::WebDyne::Plack

to get everything needed to run with Plack/PSGI. For PAGI run:

cpanm Task::WebDyne::PAGI

If using Apache you will need to configure your system to use WebDyne to serve files with the .psp extension - see Apache install section.

Runtime Choices

PSGI

Ensure that Plack is installed on your system via CPAN after installing WebDyne:

# Via CPAN
#
perl -MCPAN -e 'install Plack'

# Modern systems
#
cpan Plack

# Or better via CPANM
#
cpanm Plack

# Or just do the whole lot in one hit. For WebDyne + Plack
#
cpanm Task::WebDyne::Plack

# Or WebDyne + Plack + Starman. Note if Starman install fails you may need to force install of
# Net::Server via :
# cpanm --force Net::Server
#
cpanm Task::WebDyne::Starman

you can then start a basic WebDyne server by running the webdyne.psgi command with the --test parameter

webdyne.psgi --test

This will start a PSGI web server on your machine listening to port 5000 (or port 5001 on a Mac). Open a connection to http://127.0.0.1:5000/ or the IP address of your server in your web browser to view the test page and validate the WebDyne is working correctly:

Once verified as working correctly you can serve WebDyne content from a particular directory - or from a single file - using the syntax:

#  To serve up all files in a directory. Directory requests use WebDyne's built-in
#  index page by default.
#
$ webdyne.psgi <directory>

#  E.g serve files in /var/www/html. By default WebDyne will display its built-in
#  index page if no filename is specified.
#
$ webdyne.psgi /var/www/html

#  Or just a single app.psp file. Only this file will be served regardless of URL
#
$ webdyne.psgi /var/www/html/time.psp

Tip

Starting WebDyne this way enables wrapper-managed index handling and full error messages with code backtraces if any errors are encountered. Use --index=FILE or DOCUMENT_DEFAULT to nominate a site-local default page, or --no-index to rely on the underlying request layer default document behavior.

To start with plackup:

#  Start WebDyne via plackup in the current directory. A file named app.psp must exist,
#  directory indexing will not be performed.
#
DOCUMENT_ROOT=. plackup `which webdyne.psgi`

#  Start serving a single file
#
DOCUMENT_ROOT=./time.psp plackup /opt/perl5/bin/webdyne.psgi

#  Start with some Plack middleware added
#
DOCUMENT_ROOT=./time.psp  plackup -e 'enable Plack::Middleware::Debug' `which webdyne.psgi`

The above starts a single-threaded web server using Plack. To start the more performant Starman server (assuming installed):

#  Start Starman instance. Substitute port + document root and location of webdyne.psgi
#  as appropriate for your system.
#
$ DOCUMENT_ROOT=/var/www/html starman --port 5001 /usr/local/bin/webdyne.psgi

Note

Plack (via webdyne.psgi or plackup) and Starman versions of WebDyne will serve basic static files such as css, js, jpg etc. If you want more control over non PSP files you should use a traditional web server front end to serve those assets. Also note the Starman and plackup instances of WebDyne do not support the --test option or indexing - it assumes you are running in a production environment and have checked everything with the Plack implementation of webdyne.psgi first.

Numerous options can be set from the command line via environment variables, including WebDyne configuration. See relevant section for all WebDyne configuration options but assuming a local file webdyne.conf.pl:

#  Start instance webdyne.psgi using local config file
#
$ WEBDYNE_CONF=./webdyne.conf.pl webdyne.psgi --port=5012 .

WebDyne can be incorporated into a traditional app.psgi startup file for PSGI in the following form. In this example any file with a .psp extension is routed to WebDyne for rendering

#  Save as app.psgi
#
use strict;
use warnings;
use Plack::Builder;
use WebDyne::PSGI;

my $home_app = sub {
    return [
        200,
        [ 'Content-Type' => 'text/plain' ],
        [ "Welcome to the Home Page\n" ]
    ];
};

my $webdyne_app = WebDyne::PSGI->new(
    root  => '.',
    index => 1,
)->to_app;

builder {
    sub {
        my $env = shift;
        # Serve any URL ending in .psp through WebDyne
        if ($env->{PATH_INFO} =~ /\.psp$/i) {
            return $webdyne_app->($env);
        }

        return $home_app->($env);
    };
};

Save as app.psgi and start with command line:

#  Assuming app.psgi in current directory
#
plackup


#  Or if named differently
#
plackup myapp.psgi

Or you can mount all files from a particular directory against the WebDyne render engine.

use strict;
use warnings;
use Plack::Builder;
use WebDyne::PSGI;

# Main app for /
my $home_app = sub {
    return [
        200,
        [ 'Content-Type' => 'text/plain' ],
        [ "Welcome to the Home Page\n" ]
    ];
};

# Mount everything using builder
builder {
    mount '/'         => $home_app;
    mount '/webdyne'  => WebDyne::PSGI->new( root => '.')->to_app;
};

PAGI

WebDyne can also run as a PAGI application. PAGI support covers normal HTTP requests and, when using a PAGI server with the relevant scope support, server-sent events, WebSocket connections and application lifespan events.

Ensure that PAGI is installed on your system via CPAN after installing WebDyne:

# Via CPAN
#
perl -MCPAN -e 'install PAGI'

# Modern systems
#
cpan PAGI

# Or better via CPANM
#
cpanm PAGI

# Or just do the whole lot in one hit. For WebDyne + PAGI
#
cpanm Task::WebDyne::PAGI

you can then start a basic WebDyne server by running the webdyne.pagi command with the --test parameter

webdyne.pagi --test

This will start a PAGI web server on your machine listening to port 5000 (or port 5001 on a Mac). When started through webdyne.pagi the server binds to 0.0.0.0 unless a host is specified on the command line. Open a connection to http://127.0.0.1:5000/ (or the IP address of your server) in your web browser to view the test page and validate the WebDyne is working correctly:

Once verified as working correctly you can serve WebDyne content from a particular directory - or from a single file - using the syntax:

#  To serve up all files in a directory. Directory requests use WebDyne's built-in
#  index page by default.
#
$ webdyne.pagi <directory>

#  E.g serve files in /var/www/html. By default WebDyne will display its built-in
#  index page if no filename is specified.
#
$ webdyne.pagi /var/www/html

#  Or just a single app.psp file. Only this file will be served regardless of URL
#
$ webdyne.pagi /var/www/html/time.psp

Tip

Starting WebDyne this way enables wrapper-managed index handling and full error messages with code backtraces if any errors are encountered. Use --index=FILE or DOCUMENT_DEFAULT to nominate a site-local default page, or --no-index to rely on the underlying request layer default document behavior.

To start with pagi-server:

#  Start WebDyne via pagi-server in the current directory. A file named app.psp must exist,
#  directory indexing will not be performed.
#
DOCUMENT_ROOT=. pagi-server --app `which webdyne.pagi` --port=5000 --host=0.0.0.0

#  Start serving a single file
#
DOCUMENT_ROOT=./time.psp pagi-server /opt/perl5/bin/webdyne.pagi

The above starts a single-threaded web server using PAGI.

Note

PAGI (via webdyne.pagi or pagi-server) versions of WebDyne will serve basic static files such as css, js, jpg etc. If you want more control over non PSP files you should use a traditional web server front end to serve those assets.

Numerous options can be set from the command line via environment variables, including WebDyne configuration. See relevant section for all WebDyne configuration options but assuming a local file webdyne.conf.pl:

#  Start instance webdyne.pagi using local config file
#
$ WEBDYNE_CONF=./webdyne.conf.pl webdyne.pagi --port=5012 .

WebDyne can be incorporated into a traditional app.pagi/app.pl startup file for PAGI in the following form. In this example any file with a .psp extension is routed to WebDyne for rendering:

use strict;
use warnings;
use Future::AsyncAwait;
use experimental 'signatures';

use PAGI::Middleware::Builder;
use WebDyne::PAGI;

my $home_app = async sub ($scope, $receive, $send) {
    die "Unsupported scope type: $scope->{type}"
        unless $scope->{type} eq 'http';

    await $send->({
        type    => 'http.response.start',
        status  => 200,
        headers => [
            [ 'content-type', 'text/plain' ],
        ],
    });

    await $send->({
        type => 'http.response.body',
        body => "Welcome to the Home Page\n",
        more => 0,
    });
};

my $webdyne_app = WebDyne::PAGI->new(
    root  => '.',
)->to_app;

builder {
    async sub ($scope, $receive, $send) {
        if (($scope->{path} // '') =~ /\.psp$/i) {
            return await $webdyne_app->($scope, $receive, $send);
        }

        return await $home_app->($scope, $receive, $send);
    };
};

Apache mod_perl

If using Apache with mod_perl you can initialise WebDyne using the wdapacheinit command. This will attempt to auto-discover where the Apache binary and configuration files are, then add a suitable webdyne.conf file to the apache configuration. Apache will need to be restarted for the new configuration file to take effect. This will need to be done as a the root user.

[root@localhost ~]# wdapacheinit

[install] - Installation source directory '/usr'.
[install] - Creating cache directory '/var/cache/webdyne'.

[install] - Writing Apache config file '/etc/httpd/conf.d/webdyne.conf'.
[install] - Writing Webdyne config file '/etc/httpd/conf.d/webdyne_conf.pl'.
[install] - Apache uses conf.d directory - not changing httpd.conf file.
[install] - Granting Apache (apache.apache) ownership of cache directory '/var/cache/webdyne'.
[install] - Install completed.

[root@localhost ~]# systemctl restart httpd

By default WebDyne will create a cache directory in /var/cache/webdyne on Linux systems when a default CPAN install is done (no PREFIX specified). If a PREFIX is specified the cache directory will be created as $PREFIX/cache. Use the wdapacheinit --cache command-line option to specify an alternate location.

Once wdapacheinit has been run the Apache server should be reloaded or restarted. Use a method appropriate for your Linux distribution.

[root@localhost ~]# systemctl httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]

Manual Apache Configuration

If the wdapacheinit command does not work as expected on your system then the Apache configuration files can be modified manually.

Include the following section in the Apache httpd.conf file (or create a webdyne.conf file if you distribution supports conf.d style configuration files). The following configuration files are written with Apache 2.4 syntax - adjust path and syntax as required:

#  Need mod_perl, load up if not already done. Adjust path according to your distro.
#
<IfModule !mod_perl.c>
LoadModule perl_module "/etc/httpd/modules/mod_perl.so"
</IfModule>

#  Uncomment and update if using a local::lib location for Perl modules
#
#PerlSwitches -I/opt/perl -I/opt/otherperl

#  Preload the WebDyne and WebDyne::Compile module
#
PerlModule    WebDyne WebDyne::Compile

#  Associate psp files with WebDyne
#
AddHandler    modperl    .psp
PerlHandler   WebDyne

#  Set a directory for storage of cache files. Make sure this exists already is writable by the
#  Apache daemon process.
#
PerlSetVar    WEBDYNE_CACHE_DN    '/opt/webdyne/cache'

#  Allow Apache to access the cache directory if it needs to serve pre-compiled pages from there.
#
<Directory "/opt/webdyne/cache">
Require all granted
</Directory>

# Put variables in a separate file - best
#
PerlRequire conf.d/webdyne_constant.pl

#  Or use <Perl> sections - but warning, certbot doesn't like this syntax in http conf files
#
<Perl>

#  Error display/extended display on/off. Set to 1 to enable, 0 to disable
#
$WebDyne::WEBDYNE_ERROR_SHOW=1;
$WebDyne::WEBDYNE_ERROR_SHOW_EXTENDED=1;
</Perl>

Important

Substitute directory paths in the above example for the relevant/correct/appropriate ones on your system.

Create the cache directory and assign ownership and permission appropriate for your distribution (group name will vary by distribution - locate the correct one for your distribution)

[root@localhost ~]# mkdir /opt/webdyne/cache
[root@localhost ~]# chgrp apache /opt/webdyne/cache
[root@localhost ~]# chmod 770 /opt/webdyne/cache

Restart Apache and check for any errors.

Development Apache Runner

A convenience utility webdyne.apache is supplied which starts a single-threaded instance of Apache on port 5000 to render WebDyne pages. It works in the same way as the PSGI and PAGI startup scripts outlined later

#  Start an Apache test instance on a single .psp file
#
$ perl -Ilib bin/webdyne.apache ./time.psp
/usr/sbin/httpd -D ONE_PROCESS -d /tmp/webdyne_apache_ol2EWnkb -f /tmp/webdyne_apache_ol2EWnkb/conf/httpd.conf -D APACHE2 -D APACHE2_4 -D PERL_USEITHREADS
using Apache/2.4.62 (event MPM)

waiting 60 seconds for server to start: .
[Sat May 02 16:56:20.700397 2026] [core:trace3] [pid 356673:tid 356673] core.c(3505): Setting LogLevel for all modules to trace8
[Sat May 02 16:56:21.115354 2026] [mpm_event:debug] [pid 356673:tid 356717] event.c(2402): AH02471: start_threads: Using epoll (wakeable)

waiting 60 seconds for server to start: ok (waited 0 secs)
server localhost:5000 started


#  Start an instance to with a simple directory index on the current directory
#
$ perl -Ilib bin/webdyne.apache .

Docker

Docker containers are available from the Github Container Registry. Install the default Docker container (based on Debian) via:

#  Default debian version
#
$ docker pull ghcr.io/aspeer/webdyne:latest

#  Or Alpine/Fedora/Perl versions
#
# docker pull ghcr.io/aspeer/webdyne:alpine
# docker pull ghcr.io/aspeer/webdyne:fedora

Start the docker container with the command:

$ docker run -e PORT=5002 -p 5002:5002 --name=webdyne ghcr.io/aspeer/webdyne:latest

This will start WebDyne running on port 5002 on the host. Connecting to that location should show the server localtime test page

By default the container starts WebDyne with starman using the PSGI runner. The server implementation can be selected with the WEBDYNE_SERVER environment variable.

#  Run with the default PSGI/Starman server
#
$ docker run -e PORT=5002 -p 5002:5002 --name=webdyne ghcr.io/aspeer/webdyne:latest

#  Run with the PAGI server
#
$ docker run -e WEBDYNE_SERVER=pagi -e PORT=5002 -p 5002:5002 --name=webdyne ghcr.io/aspeer/webdyne:latest

To mount a local page and serve it through the docker container use the command:

$ docker run -v $(pwd):/app:ro -e PORT=5011 -e DOCUMENT_ROOT=/app -p 5011:5011 --name webdyne ghcr.io/aspeer/webdyne:latest

This will tell docker to mount the local directory into the docker container. Because the container starts WebDyne through starman or pagi-server, the default document is app.psp unless DOCUMENT_DEFAULT is set. If there is a cpanfile in the mount directory any modules will be installed into the docker container automatically.

When the container is started without an explicit command, the default entrypoint uses the following environment variables:

PORT

The TCP port the selected server listens on inside the container. If omitted, the entrypoint uses 8080. The docker -p mapping should map the same container port, for example -e PORT=5002 -p 5002:5002.

WEBDYNE_SERVER

Selects the server used by the default container command. Supported values are psgi and pagi. If omitted, psgi is used. psgi runs starman -MWebDyne with webdyne.psgi. pagi runs pagi-server with webdyne.pagi, enabling PAGI request handling such as SSE and WebSocket support where the application uses those features. Any other value causes the entrypoint to exit with an error.

DOCUMENT_ROOT

The WebDyne document root passed through to webdyne.psgi or webdyne.pagi. The published images default this to /app. Override it when mounting application files somewhere else in the container.

DOCUMENT_DEFAULT

The default document to serve from DOCUMENT_ROOT. If omitted, the command wrappers enable WebDyne's built-in default index behavior, which uses app.psp in the published Docker images.

WEBDYNE_CACHE_DN

The WebDyne compile/cache directory. The published images set this to /opt/webdyne/cache by default via the image's PERL_CARTON_PATH. Override it if the cache should live on a mounted volume or another writable directory.

PERL_CARTON_PATH

The local Perl installation prefix inside the image. The published images default this to /opt/webdyne and use it to set PERL5LIB, PATH, the default WEBDYNE_CACHE_DN, and the path to the bundled webdyne.psgi and webdyne.pagi wrappers. This is normally only changed when building a custom image.

See the Docker Runtime Server Tuning reference section for server worker, timeout and connection limit environment variables.