The appserver.io DNS server is NOT a fully featured DNS server that can be used in production mode, it has been designed and implemented to make development a bit more comfortable. In the context of appserver.io, by default it uses the virtual host configuration to resolve the DNS names without the need to add each of them to the
/etc/hosts file. So, whenever a new virtual host configuration will be added to the
etc/appserver/conf.d/virtual-hosts.xml or in a application's
META-INF/containers.xml file, the DNS name can be resolved by the DNS server, after it has been restarted.
The DNS server is built and configured like any other server component using our multithreaded server framework. Let's have a look at the main configuration of the DNS server component in
<server name="dns" type="\AppserverIo\Server\Servers\MultiThreadedServer" worker="\AppserverIo\DnsServer\Workers\UdpThreadWorker" socket="\AppserverIo\Server\Sockets\StreamSocket" serverContext="\AppserverIo\Server\Contexts\ServerContext" requestContext="\AppserverIo\Server\Contexts\RequestContext" loggerName="System">
The only difference to the HTTP server configuration is the different worker, as a DNS server is NOT using the TCP, but the UDP protocol.
There are several attributes to configure for a server component, which are described in the following table.
||The name of the server component used for reference and logging purposes.|
||The server type implementation classname based on
||The worker queue implementation classname based on
||The socket implementation classname based on
||The server context implementation classname based on
||The request context implementation classname based on
||The logger instance to use in the server's context.|
In the following section, the server params used to configure the DNS server are described. The DNS server node in
etc/appserver/appserver.xml needs the following params.
<params> <param name="admin" type="string">email@example.com</param> <param name="software" type="string">appserver/1.1.1 (darwin) PHP/5.6.17</param> <param name="transport" type="string">tcp</param> <param name="address" type="string">127.0.0.1</param> <param name="port" type="integer">9053</param> <param name="flags" type="string">STREAM_SERVER_BIND</param> <param name="documentRoot" type="string">var</param> <param name="workerNumber" type="integer">64</param> <param name="workerAcceptMin" type="integer">3</param> <param name="workerAcceptMax" type="integer">8</param> </params>
They are used to define several key/value pairs for the DNS server implementation. Beside the
flags param, all of them are common to all servers. Their descriptions can be found within the server configuration documentation
The description for the DNS server specific param is available below.
||string||Flag, that overrides the default flags, and is necessary to create an UDP connection.|
As we want to handle requests based on a specific protocol, the server needs a mechanism to understand and manage those requests properly.
For our DNS server, we use the
\AppserverIo\DnsServer\ConnectionHandlers\DnsConnectionHandler implementation, which implements the
\AppserverIo\Server\Interfaces\ConnectionHandlerInterface and follows the DNS specification.
The connection handler can be configured in the
etc/appserver/appserver.xml in the DNS server node like
<connectionHandlers> <connectionHandler type="\AppserverIo\DnsServer\ConnectionHandlers\DnsConnectionHandler" /> </connectionHandlers>
As mentioned in the beginning, we use our multithreaded server framework. to build the DNS server on. It allows you to provide modules for request and response processing. In contrast to the HTTP server, the DNS server actually doesn't need and provide any hooks. If you want to write you own module, e. g. to load DNS records from a different source (although the storage provider would be the right place for that), the modules would be processed in the given order.
As the DNS server actually only need exactly one module, the
\AppserverIo\DnsServer\Modules\CoreModule, there is not much to describe how it has to be configured. So the module configuration in the DNS server node looks like
<modules> <module type="\AppserverIo\DnsServer\Modules\CoreModule"> <params> <param name="resolverFactory" type="string">\AppserverIo\Appserver\Core\Modules\StorageProvider\SystemConfigurationResolverFactory</param> <param name="defaultTTL" type="integer">300</param> </params> </module> </modules>
The possible module params, depending on the configured storage provider, are described below.
||string||The class name of the factory that initializes the storage provider.|
||string||Beside using the configured virtual host, a JSON file can be used to load the DNS records from (needs the JSON storage provider).|
||integer||The default TTL for a DNS record to be cached.|
Addionally the DNS server package provides an interface called
\AppserverIo\DnsServer\Interfaces\DnsModuleInterface, which has to be implemented by every module providing DNS related functionality.
The only module available is described in the table below.
The core module tries to resolve DNS request by loading the available DNS records with the configured storage provider.
The storage provider is not configured directly. Instead a factory class, implementing the
AppserverIo\DnsServer\Interfaces\ResolverFactoryInterface, has to be given. By default, in the appserver.io context the class
\AppserverIo\Appserver\Core\Modules\StorageProvider\SystemConfigurationResolverFactory initializes a storage provider that uses the virtual from the system configuration as source for the DNS records.
Another possibility will be a JSON file, that can provide complete DNS records instead of the A or AAAA types only. The JSON storage provider is part of the DNS server package and can be configured by using the apropriate storage provider, like
<modules> <module type="\AppserverIo\DnsServer\Modules\CoreModule"> <params> <param name="resolverFactory" type="string">\AppserverIo\DnsServer\StorageProvider\StandardResolverFactory</param> <param name="recordFile" type="string">etc/dns_record.json</param> <param name="defaultTTL" type="integer">300</param> </params> </module> </modules>
whereas the file with DNS records has to be available in the directory
/opt/appserver/etc/dns_record.json, assuming appserver.io is running on a Linux or a Mac OS X installation.
Why do i have to activate the DNS server? By default, a DNS server has to listen to port
53. As we don't know a DNS server like dnsmasq has already been installed on the target system, we decided to let our DNS server listen to port 9053 by default. This means, that the DNS server is running indeed, but it will not be used to resolving DNS queries.
To activate the appserver.io internal DNS server, the following steps are necessary
- Switch the port from
etc/appserver/appserver.xmlby changing the
- Restart appserver.io with the default start/stop scripts
The DNS server should now listen to port
53 and should be ready to resolve DNS queries. To make sure everything works invoke the following command
dig @127.0.0.1 example.dev
trying to resolve the DNS entry for the appserver.io example application from the DNS server. The result should look like
; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 example.dev ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42150 ;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;example.dev. IN A ;; ANSWER SECTION: example.dev. 300 IN A 127.0.0.1 ;; Query time: 6 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Sat Apr 2 11:49:31 2016 ;; MSG SIZE rcvd: 56
The DNS server is now completely set up. Finally it is necessary that the OS is aware of the nameserver. So, how to configure a nameserver on the various operating systems? Each OS has it's own solution, so it's not possible to list them all here. To give you an idea, we described a solution for Mac OS X here.
Mac OS X provides a resolver, that can be configured either by a file
/etc/resolve.conf or by specifying additional DNS nameserver in files below the directory
/etc/resolver. The seconde approach is the preferred one, because the
/etc/resolv.conf file is autogenerated and will be overwritten when someone makes changes in the Mac OS X network preferences.
To let the appserver.io DNS server resolve all domain names with the suffix
.dev, e. g.
example.dev a file
/etc/resolver/dev with the following content
has to be created. This can be done by invoking the following command on the console
$ sudo sh -c " echo 'nameserver 127.0.0.1' >> /etc/resolver/dev"
Vòila, pointing the browser to
http://example.dev:9080 should now open the appserver.io example application!