appserver.io, a PHP application server

appserver.io is a multithreaded application server for PHP, writtenin PHP. Yes, pure PHP! If you know anything about PHP, you're probably thinking we might be crazy. Well, we aren't. We are dead serious (but we most certainly still love having fun!).

appserver.io overcomes some of the biggest overhead issues most PHP (CGI) programs have in common, through a blazingly fast and rock solid infrastructure and with concepts new to PHP. At the same time, appserver.io offers PHP developers the fundamental core features found in most popular frameworks today, yet not intending to be a framework at all. It is a suprizingly fun infrastructure for PHP development, allowing you to build powerful applications without needing the bulk of a PHP framework.

appserver.io includes great features like...

Its own performant Web Server and HTTP foundation.

A powerful Servlet Engine, with true multi-threading

A Dependency Injection Container, for building modern, modular and testable code

Multiple Persistence Containers, for sessions and other stateful components

A Message Queue System, for contolling the execution of long running tasks

A Timer Service, for running scheduled tasks

and much more.

appserver.io also supports Aspect Oriented Programming(AOP), which is a programming paradigm also found in the most popular frameworks today, like Laravel. AOP allows the separation of cross-cutting concerns within a program, allowing developers to create even more modular systems.

With appserver.io, it is our goal to establish a solution as the next standard for enterprise applications written in PHP. With your help, we can reach this goal.

Semantic Versioning

appserver.io follows semantic versioning. For the purpose of defining a public API we introduced appserver.io specific PSRs. These PSRs are the core to appserver.io's public API, but within their own definition and versioning, meaning that semantic versioning applies to these PSRs and not the appserver package itself.

Installation

appserver.io can be installed on several operating systems. It also supports several methods of acquiring the software. To get your appserver.io package you can do one of the following:

Download one of our releasesright from this repository which provide tested install packages

Grab any of our nightlies from our project page to getbleeding edge install packages, (and may also containg bugs - only for testing and not for production use!!)

Build your own package using ANT! To do so clone the runtime first. Then update at least the os.family and os.distribution build properties according to your environment and build the appserver with the ANT build and create-package target.

For OS specific steps and characteristics see below for tested environments.

Mac OS X

Runs and tested on Mac OS X 10.8.x and higher!

For Mac OS X > 10.8.x we provide a .pkg file for download that contains the runtime and the distribution. Double-clicking on the .pkg starts and guides you through the installation process.

Windows

Runs and tested on Windows 7 (32-bit) and higher!

As we deliver the Windows appserver as a .jar file you can download, a installed Java Runtime Environment (or JDKthat is) is a vital requirement for using it. If the JRE/JDK is not installed, you have to do sofirst. You can get the JRE from Oracle's download page.If this requirement is met you can start the installation by simply double-clicking the .jar archive.

Optionally you can download the .deb files and install them by double-clicking on them. This will invoke the system default package manager and guides you through the installation process. Please install the runtime first, as this is a dependency for the distribution.

Fedora

Runs and tested on versions Fedora 20 (64-bit) and higher!

We also provide .rpmfiles for Fedora, that you can download and start the installation process by double-clicking on it. This will start the systems default package manager and guides you through the installation process.

CentOS

Runs and tested on CentOS 6.5 (64-bit) and higher!

Installation and basic usage is the same as on Fedora, but we provide different packages. CentOS requires additional repositorieslike remi or EPEL tosatisfy additional dependencies.

Raspbian

As an experiment we offer a Raspbian and brought the appserver to an ARM environment. What shouldwe say, it worked! :D With os.distribution = raspbian you might give it a try and build ityourself. Plan for at least 5 hours though, as we currently do not offer prepared install package.

Basic Usage

The appserver will automatically start after your installation wizard (or package manager) finishesthe setup. You can use it without limitations after installation is completed..

Below you can find basic instructions on how to make use of the appserver. After the installation,you might want to have a look at the example application, which is also included with the installation. You can reach the app at http://127.0.0.1:9080/example

Start your favorite browser and have a look at what appserver can do. :) To enter the site, usethe default login appserver/appserver.i0.

Start and Stop Scripts

There are several standalone processes, which are needed for the properfunctioning of different features within appserver.

There are start and stop scripts included in appserver for all nix like operating systems.These work the same as on any other nix systems. They are:

appserver: The main process which will start the appserver itself

appserver-php5-fpm: php-fpm + appserver configuration. Our default FastCGI backend. Other FCGI system can be added the same way.

On a normal system, all three of these processes should run to enable the full feature set. Toultimately run the appserver, only the appserver process is needed. However, you will miss simple on-the-flydeployment (appserver-watcher) and might have problems with legacy applications.

Depending on the FastCGI backend you want to use, you might ditch appserver-php5-fpm for otherprocesses e.g. you could also use an hhvm backend.

Currently we support three different types of init scripts, which support the commands start, stop,status and restart (additional commands might be available on other systems).

Mac OS X (LAUNCHD)The LAUNCHD launch daemons are located within the appserver installation at /opt/appserver/sbin.They can be used with the schema /opt/appserver/sbin/<DAEMON> <COMMAND>

Debian, Raspbian, CentOS, ...(SystemV)Commonly known and located in /etc/init.d/ they too support the commands mentioned above providedin the form /etc/init.d/<DAEMON> <COMMAND>.

Fedora, ... (systemd)systemd init scripts can be used using the systemctl command with the syntax systemctl <COMMAND> <DAEMON>.

Windows

On Windows we sadly do not offer any of these scripts. After the installation, you can start theApplication Server with the server.bat file located within the root directory of your installation.Best thing to do would be starting a command prompt as an administrator and run the following commands(assuming default installation path):

HTTP(S) Server

The configuration of the HTTP(S) Server itself is mostly self-explanatory, so just have a look at the default configfile and, if you'd like, try to change the settings.Please make sure you restart the appserver after making any changes. :)A detailed overview of all configuration settings will follow ...

Configure a Virtual Host

Using virtual hosts, you can extend the default server configuration and produce a host specificenvironment for your app to run.

You can do so by adding a virtual host configuration to your global server configuration file. Seethe example for a XML based configuration below:

There are several ways in which this feature is used. You can get a rough idea when having alook at Apache modules mod_env andmod_setenvif which we adopted.

You can make definitions of environment variables dependent on REGEX based conditions which willbe performed on so called backreferences. These backreferences are request related server variableslike HTTP_USER_AGENT.

A condition has the format <REGEX_CONDITION>@$<BACKREFERENCE>. If the condition is empty theenvironment variable will be set every time.

The definition you can use has the form <NAME_OF_VAR>=<THE_VALUE_TO_SET>. The definition hassome specialities too:

Setting a var to null will unset the variable if it existed before

You can use backreferences for the value you want to set as well. But those are limited toenvironment variables of the PHP process

Values will be treated as strings

Servlet-Engine

Originally Java Servlets were Java's counterpart to other dynamic web technologies like PHP or theMicrosoft .NET platform. In contrast to PHP, a Servlet written in Java is not a script that willbe interpreted per request. Instead, it is a class, which is instantiated, when the Servlet Engine starts up.This means, the servlet class is already in memory and stays in memory.

In most cases, this is a major advantage compared to the common PHP way to constantly reload the script on eachrequest. Since most PHP applications are based on frameworks like Symfony or Laravel have grownimmensly during the last few years, the reloading of all the script files required by the application,slows down performance considerably. This is one of the reasons why caching is a majorpart of all good PHP frameworks. On one hand, caching improves performance enough sothe application responds to the request in an acceptable timeframe. On the other hand, it is also theorigin of many problems, such as how to invalidate parts of the cache during an applicationsruntime.

Servlets enable you to implement your application logic as you normally would, but without the need to worry about the expensivereloading process, which is common to normal PHP applications. A Servlet is a superfast and simple way to implement an entry point to handle HTTP requests, which allow you toexecute all performance critical tasks, like bootstrapping (with a simple method called init()), whenthe Servlet Engine starts up.

What is a Servlet

A Servlet is a simple class that has to extend from AppserverIo\Psr\Servlet\Http\HttpServlet.Your application logic can then be implemented by overwriting the service() method or betterby overwriting the request specific methods like doGet() if you want to handle a GET request.

Create a simple Servlet

Let's write a simple example and start with a famous Hello World servlet

and save it as /opt/appserver/webapps/myapp/WEB-INF/classes/Namespace/Module/HelloWorldServlet.php.

Is that all? Yes! Restart the application server and openhttp://127.0.0.1:9080/myapp/helloWorld.do in your favorite browser, and ... vóila :)

A restart is always required since you changed code in your Servlet, because the Servletwill be loaded and initialized when the the application server starts. Without a restartthe application server will not know you had made any changes.

Annotations

Since one of our main goals is to make configuration as simple as possible, we decided to useannotations wherever possible. As annotations are not supported natively by PHP, we provideannotation support over our lang package.

Beside the use of annotations in our application server components, it will also be possible to extend yourapplication with annotations by using the functionality appserver delivers out-of-the-box.

If you, for example, think about extending the actions of the controller component in yourMVC framework with a @Route annotation, you can do that in the following way

Most of the annotation implementations provided by our Enterprise BeansPSR and used for Dependency Injection, which will be described below,are based on that annotation implementation.

Dependency Injection

Dependency Injection(DI) enables developers to write cleaner, reusable and maintainablecode with less coupling by injecting necessary instances at runtime, instead of instantiating them inthe class itself. Within the application server, each application has its own scope and therefore itsown dependency injection container. This prevents your application from fatal errors like Cannot redeclare class ....

What can be injected

Generally everything! The application server itself doesn't use DI, instead it provides DI as aservice for the applications running within it. But, before you can let the DI container inject aninstance to your class, you have to register it. Registering a class for DI is pretty simple. Toregister a class in the DI container the most common way is to use annotations.

When the application server starts, it parses the META-INF/classes and WEB-INF/classes folderclasses with supported annotations. If a class is found, the class will be registered in theapplication servers naming directory under the name you specify in the annotations name Attribute,in this example MyStatefulSessionBean.

How to inject an instance

Basically DI can be a manual process where you inject an instance, needed by another class bypassing it to the constructor. Inside the application server, the injection is a process you can'tsee, it's more a kind of magic that happens behind the scenes. So instead of manually passing thenecessary instances to a classes constructor, the DI container will do that for you.

You simply have to tell the DI container what you need. Let's have a look at how that is done.

With the name attribute of the @EnterpriseBean annotation, you have the possibility to specify thename of the bean you registered before by annotating it. A more detailed description about theavailable annotations is part of the Persistence-Container.

This method is the preferred one, because it will be refactored not to use reflection in furtherversions.

Persistence-Container

As described in the introduction, the application is designed inside a runtime environment, likean application server as appserver.io is. The following example gives you a short introductionon how you can create a stateful session bean and the way you can invoke it's method on the client side.

First thing you can to do is create your SessionBean. What is a SessionBean? A SessionBean is basically a plain PHP class.However, you MUST not instantiate it directly, because the application server takes care of its completelifecycle. Therefore, if you need an instance of a SessionBean, you must ask the application serverto give you an instance.

The persistence container will give you a proxy to the session bean that allows you toinvoke all methods the SessionBean provides, just like you would do with a normal instance. But,the proxy also allows you to call this method over a network as remote method call. Using thepersistence container client makes it easy for you, if your SessionBean is on the sameapplication server instance or even on another appserver in your network. This gives you the possibilityto distribute the components of your application over your network, which means a great andseamless scalability.

You have to tell the persistence container what type of SessionBean you would like to have. This MUSTbe done by simply adding an annotation to the class doc block. The possible annotations thereforeare

@Singleton

@Stateless

@Stateful

@Singleton SessionBean

A SessionBean with a @Singleton annotation will be created only one time for each application.This means, whenever you'll request an instance, you'll receive the same one. If you set avariable in the SessionBean, it'll be available until you'll overwrite it, or the applicationserver has been restarted.

@Stateless SessionBean

Contrary to a singleton session bean, a SessionBean with a @Stateless annotation will alwaysbe instantiated, when you request it. It has NO state, and is only valid for the time you invoke a method onit.

@Stateful SessionBean

The @Stateful SessionBean is a compromise between the two other types. It is stateful for the sessionwith the ID you pass to the client, when you request the instance. A stateful SessionBean isuseful, for instance, if you want to implement something like a shopping cart. If you declare the shopping cartinstance, a class member of your SessionBean makes it persistent for your session lifetime.

Example

The following example shows you a really simple implementation of a stateful SessionBean providinga counter that'll be raised whenever you call the raiseMe() method.

Save the SessionBean in /opt/appserver/myapp/META-INF/classes/Namespace/Module/MyStatefulSessionBean.php.

As described above, you MUST not instantiate it directly. To request an instance of the SessionBeanyou MUST use the persistence container client. With the lookup() method you'll receive a proxy toyour SessionBean, on that you can invoke the methods as you can do with a real instance.

To develop our HelloWorldServlet further, let's raise the counter with each request to the servlet. Todo this, we have to refactor the doGet() method

As we use a @Stateful SessionBean in this example, we MUST start a session so the persistence container canbind the SessionBean. If you would have used a @Singleton SessionBean, the effect would be thepractically the same, but it would have been possible to start a SessionBean per session. As a consequence, each Servlet thatinvokes the raiseMe() method on the singleton SessionBean would raise the counter, meaning possibly every call to the server would raise the counter and not each particular call for a particular session.

Message-Queue

A Message-Queue provides the possibility to process long running tasks in an encapsulated context.For example, if you want to import a lot of products in your online shop, you can send amessage to the Message-Queue, which then will start the import process in the background withoutpreventing the calling process to continue.

Using a Message-Queue gives you the power to use threads without taking care of the pitfalls!

Got mail!

Before we can send a message, we have to specify what should happen, when we receive one! TheMessage-Queue allows you to specify so called Queues. Each Queue can have a receiver, whichmust be a so called MessageBean. A MessageBean is very similar to a @Stateless SessionBean,but has only a single point of entry, the onMessage() message method. Whenever a messageis sent to the queue, the Message-Queue simply pushes it onto the stack. In the background, aQueueWorker is running in another context and queries the stack for new messages. If a newmessage is available, it will be pulled from the stack, as a new instance of the receiver, which the Queueis bound to and will be instantiated to pass the message for processing.

Please note: beside the functionality you have to implement with the onMessage()message method, you must also use the annotation @MessageDriven on your class. You MUST annotate the MessageBean in this fashion,in order for the container to know about and register it on startup.

Pretty simple for running your import in a separate thread? But what about sending a message tothis Queue?

Send a message

Messages are POPOs (Plain Old PHP Objects) that can be sent over the network. So if you want to send a message, you haveto initialize the Message-Queue Client and specify which Queue you want to send the message to.

Again, we will extend our Servlet to start an import process on a POST request

To make the process easier, you can use the @Resource annotation to let the container inject a senderinstance, which we can use to send the name of the file containing the data to the Queue.

Timer-Service

In most of your projects you have the need to schedule tasks to be processed at regular intervalsor at a given dates in the future. As PHP itself is a scripting language, it lacks such functionalityand developers usually end up using utilities like CRON, when working on Mac OS X or a Linux distribution, which also requires low level access to the server. And, if youare working on Windows, it's even a bit more complicated. There is a tool called Scheduler in Windows, butusing it is not as simple to as CRON. Neither of these options are really "programmable" and this is where a Timer Service comes into the game and makes scheduling tasks within your appserver application a dream come true..

As CRON does, the Timer Service allows you to schedule processing of your functional tasks at a givendate or in regular intervals. In contrast to CRON however, it allows you to schedule processing the methodsof your Beans (which remember, are already processed and stored in memory).

How can this be done?

You might know the answer by now, simply by adding an annotation to your method, as follows

The @Schedule annotation on the invokedByTimer() method schedules the invocation of thismethod every minute without the need to have a CRON configured or running. Such Timers canalso be created programatically. If you want to know more about this functionality, have a look at our example.

AOP

Although in its early days, AOP used to be a buzzword. It has, however, become a development paradigm followed by many of the PHP frameworks out there today. It has been followed for many years already by other languages like Java. Since there is actually no stable PECL extension, nor is AOP part of the PHP core, creating such an environment creates a number of challenges to make applications based on AOP to perform well. Because of its nature, AOP needs to be deeply weaved into your code. Most of the solutions available for PHP solve that by generating so called proxy classes that wrap the original methods and allow to weave the advices before, after or around the original implementation.

Since in appserver, we're in a multi-threaded environment and performance is one of our main goals, we were notable to use anyone one of the available solutions. As we also need to generate proxy classes, we decidedto do that through an autoloader. And since we have enabled an autoloader as part of the appserver.io distribution, youdon't have to configure anything to use AOP in your code.

How to add an Advice

Integrating AOP in your app can be done in two ways. The first one is to define the pointcuts (and alsoadvices if you like) in the same class they will get woven into, the second method is to separate them. In the following section we want to describe the second approach.

Let's say we want to log all GET requests on our HelloWorldServlet without adding anycode to the servlet itself. To do this, we first have to create an Aspect class like

Store the class in /opt/appserver/myapp/META-INF/classes/Namespace/Module/LoggerAspect andrestart the application server.

To see the the log message, open the console (Linux/Mac OS X) and enter

$ tail -f /opt/appserver/var/log/appserver-errors.log

Then open http://127.0.0.1:9080/myapp/helloWorld.do in your favorite browser, and have a lookat the console.

AOP is a very powerful instrument to enrich your application with functionality with "controlled" coupling.But as in most cases, great power comes with great responsibility. So, it is reallynecessary to keep in mind, where your Aspect classes are and what they do. If not, someonewill wonder what happens and may need a good amount of time to figure out a problem. To avoid this, we'llprovide an XML based advice declaration in future versions.

Design-by-Contract

Beside AOP, Design-by-Contract is anotherinteresting approach we support out-of-the-box, when you think about the architecture of yoursoftware.

First introduced by Bertrand Meyer in connection with his design of the Eiffel programming language,Design-by-Contract allows you to define formal, precise and verifiable interface specifications ofsoftware components.

Design-by-Contract extends the ordinary definition of classes, abstract classes and interfaces byadding pre-/postconditions and invariants referred to as contracts. As Design-by-Contract is, asis AOP, not part of the PHP core, we also use annotations to specify these contracts.

What can be done?

As stated above, this library aims to bring you the power of Design by Contract, an approach to makeyour applications more robust and easier to debug. This contains basic features as:

Use your basic DocBlock annotations @param and @return as type hints (scalar and class/interfacebased), including special features like typed arrays using e. g. array<int> (currently only works for collections with complex types)

Depending on your configuration, if a method would try to set a string on the counter variable, theDesign-by-Contract implementation would either throw an exception or write an error message to ourlog file under /opt/appserver/var/log/appserver-errors.log.

Runtime Environment

The appserver.io runtime environment is delivered by the package runtime.This package provides a runtime which is system independent and encloses a thread-safecompiled PHP environment. Besides the most recent PHP 5.5.x version the package comes with following installedextensions:

Additionally, the PECL extensions XDebug and evare compiled as shared modules. XDebug is necessary to render detailed code coverage reports whenrunning unit and integration tests. ev will be used to integrate a timer service in one of the futureversions.

Configuration

We believe that the appserver should be highly configurable, so anyone interested can fiddlearound with it. Therefore, we provide a central configuration file located at /opt/appserver/etc/appserver.xml.

In the above example you can see three important components of the appserver architecture beingused. The container, server and aprotocol (if you did not read about our basic architectureyou should now). We are basically building up a container which holds a server using the websocketprotocol to handle incoming requests.

Container Configuration

A container is created by using the container element within the containers collectionof the appserver document element. Two parts of the XML create a specific container, in the system on startup:

The type attribute states a class extending our AbstractContainerThread, which defines acontainer to be a specific type of container.

The deployment element states a class containing preparations for starting up the container.It can be considered a hook, which will be invoked before the container will be available.

That is basically everything there is to do to create a new container. To make use of it, it hasto contain at least one server within its servers collection.

Server Configuration

The servers contained by our container can also be loosely drafted by the XML configuration andwill be instantiated on container boot-up. To enable a server you have to mention three basicattributes of the element:

The type specifies a class implementing the ServerInterface, which implements the basicbehaviour of the server on receiving a connection and how it will handle it.

The socket attribute specifies the type of socket the server should open. E.g. a stream orasynchronous socket

The serverContext specifies the server's source of configuration and container for runtimeinformation e.g. ServerVariables like DOCUMENT_ROOT

So we have our specific server which will open a certain port and operate in a defined context. Butto make the server handle a certain type of request, it needs to know which protocol to speak.

This can be done using the connectionHandler element. Certain server wrappers can handle certainprotocols. Therefore, we can use the protocols which a server wrapper, e.g. WebServer supports inform of connection handlers. WebServeroffers a HttpConnectionHandler class. By using it, the server is able to understand the HTTPprotocol.

Application Configuration

Beside the Container and Server configuration, it is also possible to configure an application. Each applicationcan have it's own autoloaders and managers. By default, each application found in the applicationservers webapp directory /opt/appserver/webapps will be initialized with the defaults, definedin /opt/appserver/etc/appserver/conf.d/context.xml

If your application doesn't use any of the defined class loaders or managers or you want to implementyour own managers, you can define them in a context.xml file, which you must include with yourapplication. Your own customized file, has to be stored in META-INF/context.xml. When the applicationserver starts, this file will be parsed and your application will be initialized with the class loadersand managers you have defined there.

Please be aware: the default class loaders and managers provide most of the functionalitydescribed above. So if you remove them from the context.xml, you have to expect unexpected and incorrect behaviour.

Module Configuration

The web server comes with a package of default modules. The functionality that allows us to configurea virtual host or environment variables, for example, is also provided by two very important modules.

Rewrite Module

The rewrite module can be used according to the \AppserverIo\WebServer\Interfaces\HttpModuleInterface interface.It needs an initial call of the init method and will process any request offered to the process method.The module is best used within the webserverproject, as it offers all the needed infrastructure.

Rules

Most important part of the rewrite module is the way in which it can perform rewrites. All rewrites arebased on rewrite rules which consist of three important parts:

condition string : Conditions, which have to be met in order for the rule to take effect.This is explained in more detail under condition syntax

target string : The target to rewrite the requested URI to. Within this string you can usebackreferences similarto the Apache mod_rewrite module with the difference that you have to use the $ syntax(instead of the $/%/%{} syntax of Apache).

Matching rule conditions, which you specifically pick out via regex are also part of available back-referencesas well as server and environment variables.

Simple example : A condition like (.+)@$X_REQUEST_URI would produce a back reference $1with the value /index for a requested URI /index. The target string $1/welcome.html wouldtherefore result in a rewrite to /index/welcome.html

flag string : You can use flags similar to mod_rewrite which are used to make rules react in acertain way or influence further processing. Learn more in the section on flage

Condition Syntax

The Syntax of possible conditions is roughly based on the possibilities of Apache's RewriteConditionand RewriteRule combined.

To make use of such a combination you can chain conditions together using the {OR} symbol forOR-combined, and the {AND} symbol for AND-combined conditions.

Please be aware that AND takes precedence over OR! Conditions can either be PCRE regex or certain fixedexpressions. So a condition string of ([A-Z]+\.txt){OR}^/([0-9]+){AND}-f would match only real files(through -f) which either begin with numbers or end with capital letters and the extension .txt.

As you might have noticed: Backslashes do not have to be escaped.

You might also be curious of the -f condition. This is a direct copy of Apaches -f RewriteCondition.We also support several other expressions to regex based conditions which are:

><COMPARE_STRING> : Is the operand lexically following <COMPARE_STRING>?

=<COMPARE_STRING> : Is the operand lexically equal to <COMPARE_STRING>?

-d : Is the operand a directory?

-f : Is the operand a real file?

-s : Is the operand a real file of a size greater than 0?

-l : Is the operand a symbolic link?

-x : Is the operand an executable file?

If you are wondering what the operand might be: it is whatever you want it to be! You can specifyany operand you like using the @ symbol. All conditions within a rule will use the next operand totheir right and if none is given the requested URI. For example:

([A-Z]+\.txt){OR}^/([0-9]+) Will take the requested URI for both conditions (note the {OR} symbol)

([A-Z]+\.txt){OR}^/([0-9]+)@$DOCUMENT_ROOT Will test both conditions against the document root

([A-Z]+\.txt)@$DOCUMENT_ROOT{OR}^/([0-9]+) Will only test the first one against the document rootand the second against the requested URI

You might have noted the $ symbol before DOCUMENT_ROOT and remembered it from the back-referencesyntax. That's because all Apache common server vars can be explicitly used as back-references too!

That does not work for you? Need the exact opposite? No problem!

All conditions, whether regex or expression based can be negated using the ! symbol in front ofthem! So !^([0-9]+) would match all strings which do NOT begin with a number and !-d would matchall non-directories.

Flags

Flags are used to further influence processing. You can specify as many flags per rewrite as you like,but be aware of their impact! Syntax for several flags is simple: just separate them with a , symbol.Flags which might accept a parameter can be assigned one by using the = symbol. Currently supportedflags are:

L : As rules are normally processed one after the other, the L flag will make the flagged rulethe last one processed if matched.

R : If this flag is set we will redirect the client to the URL specified in the target string. If this is just a URI, we will redirect to the same host. You might also specify a custom status code between 300 and 399 to indicate the reason for/kind of the redirect. Default is 301 akapermanent

M : Stands for map. Using this flag you can specify an external source (have a look at the Injectorclasses of the WebServer project) of a target map. With M=<MY_BACKREFERENCE> you can specify whatthe map's index has to be to match. This matching is done only if the rewrite condition matches and willbehave as another condition

Virtual-Host Module

The module can be used according to the \AppserverIo\WebServer\Interfaces\HttpModuleInterfaceinterface. It needs an initial call of the init method and will process any request offered tothe process method. The module is best used within the webserverproject as it offers all needed infrastructure.

If you need to configure a virtual host, it should look like thefollowing example, which enables a Magento installation under http://magento.dev:9080.

Configuration Defaults

You will see that we provide basic front-end implementations of services the appserver runtimeprovides. If you want to use these services yourself, you should have a look into the code of ourapps and read about app development.

You might be curious about the different ports we use. Per default, the appserver will open severalports at which it's services are available. As we do not want to block (or be blocked by) otherservices, we use ports in a higher range.

As a default, we use the following ports:

WebContainer

HTTP Server: 9080

HTTPS Server: 9443

Persistence-MQ-Container

Persistence-Container: 8585

Message-Queue: 8587

You can change the default port mapping by using the configuration file.If you are interested in our naming, you can see our container->server pattern, you might want tohave a deeper look into our architecture

Deployment

The deploy directory in the appserver.io Application Server distribution is the location end users can place theirdeployment content (e. g. phar files) to have it deployed into the server runtime.

Users, particularly those running production systems, are encouraged to use the appserver.io AS management APIs toupload and deploy deployment content.

Deployment Modes

The scanner actually only supports a manual deployment mode, which means that you have to restart the server to processdeployment of your content. In this mode, the scanner will not attempt to directly monitor the deployment content anddecide if or when the end user wishes the content to be deployed or undeployed. Instead, the scanner relies on a systemof marker files, with the user's addition or removal of a marker file serving as a sort of command telling the scannerto deploy, undeploy or redeploy content.

It is also possible to copy your unzipped content directly into the webapps folder. After restarting the webserveryour content will then be deployed without having any impact on the deployment scanner, because only zipped (.phar)content will be recognized.

Marker Files

The marker files always have the same name as the deployment content to which they relate, but with an additional filesuffix appended. For example, the marker file to indicate the example.phar file should be deployed is namedexample.phar.dodeploy. Different marker file suffixes have different meanings.

The relevant marker file types are:

Marker

Description

.dodeploy

Placed by the user to indicate that the given content should be deployed or redeployed into the runtime.

.deploying

Placed by the deployment scanner service to indicate that it has noticed a .dodeploy file and is in the process of deploying the content. This marker file will be deleted, when the deployment process completes.

.deployed

Placed by the deployment scanner service to indicate that the given content has been deployed into the runtime. If an end user deletes this file and no other marker is available, the content will be undeployed.

.failed

Placed by the deployment scanner service to indicate that the given content failed to deploy into the runtime. The content of the file will include some information about the cause of the failure. Note that, removing this file will make the deployment eligible for deployment again.

.undeploying

Placed by the deployment scanner service to indicate that it has noticed a .deployed file has been deleted and the content is being undeployed. This marker file will be deleted, when the undeployment process completes.

.undeployed

Placed by the deployment scanner service to indicate that the given content has been undeployed from the runtime. If this marker file is deleted by the user, it has no impact.

Basic workflows

All examples assume variable $AS points to the root of the appserver.io AS distribution.

Windows Notes

Note that the behavior of touch and echo are different, but the differences are not relevant to the usages.

Uninstall

Before uninstalling, you should stop all the services, which are still running (rpm-based packages will see to that themselves), otherwise there might be problems with existing pid-files on Linux and Mac for the next time you install it.

To uninstall the appserver on Linux, you might rely on your package management system.On Windows you can use the normal uninstall process provided by the operating system.

Under Mac OS X you can simply delete the /opt/appserver folder that containers all installed files.