Make sure you have the prerequisite modules installed.

Packages for Redhat/Centos

	yum install perl-devel perl-ExtUtils-ParseXS perl-ExtUtils-Install perl-ExtUtils-MakeMaker perl-ExtUtils-Manifest perl-Test-Harness
	yum install perl-CPAN perl-CPAN-Meta perl-CPAN-Meta-Requirements perl-CPAN-Meta-YAML perl-CPANPLUS-Dist-Build perl-Parse-CPAN-Meta perl-Test-CPAN-Meta perl-CPAN-Changes perl-CPANPLUS perl-Module-Signature perl-Version-Requirements perl-YAML
	yum install perl-Data-Dumper
	yum install perl-App-cpanminus 

Packages for Archlinux

	pacman -S perl-data-dump
	pacman -S cpanminus

Modules to install from cpan

	cpanm XML::Hash::XS
	cpanm JSON::XS
	cpanm YAML::XS
	cpanm Moo
	cpanm ExtUtils::Config
	cpanm IO::HTML
	cpanm HTTP::Headers
	cpanm HTTP::Entity::Parser
	cpanm HTTP::Request::Common
	cpanm Net::Server
	cpanm Plack
	cpanm Plack::Middleware::Deflater
	cpanm Starman
	cpanm Template::Toolkit
	cpanm Dancer2
	cpanm Dancer2::Plugin::WebService

Use logrotate for housekeeping the log files
vi /etc/logrotate.d/WebService

	/var/log/WebService/*.log {
	create 640 dancer dancer
	compress
	missingok
	notifempty
	daily
	rotate 7
	}

You should your run your service as a non privileged user e.g. dancer.
Be careful, non root users can not bind ports up to 1024
Create the user if not exist

	getent group  dancer >/dev/null || groupadd dancer
	getent passwd dancer >/dev/null || useradd -g dancer -l -M -c "Dancer2 WebService" -s $(which nologin) dancer

Create the Persistent data and log directories. You can change them if you want

	mkdir /var/lib/WebService
	mkdir /var/log/WebService

	chown -R dancer:dancer /var/lib/WebService
	chown -R dancer:dancer /var/log/WebService

If you have a firewall you should create a rule for the listening port e.g. at Redhat

	firewall-cmd --zone=public --permanent --add-port=3000/tcp
	firewall-cmd --reload
	firewall-cmd --list-all

If you are running the service as user dancer, and want to want to use an authentication method that needs root, add dancer user to sudoers e.g.

	vi /etc/sudoers

		#includedir /etc/sudoers.d

	vi /etc/sudoers.d/WebService

		dancer ALL=NOPASSWD: /usr/local/share/perl5/Dancer2/Plugin/scripts/LinuxOS/AuthUser.pl

Make sure the authorization scripts are executable

	# Redhat
	find /usr/local/share/perl5/Dancer2/Plugin      -regex ".*\.\(sh\|pl\)\$" -type f -exec chmod 755 {} \;	
	# Archlinux
	find /usr/share/perl5/site_perl/Dancer2/Plugin  -regex ".*\.\(sh\|pl\)\$" -type f -exec chmod 755 {} \;

quick view the Dancer2::Plugin::WebService documentation as web page

	install darkhttpd (once)
	pod2html --infile=/opt/Dancer2-Plugin-WebService/lib/Dancer2/Plugin/WebService.pm --outfile=/tmp/index.html --title="Dancer2 WebService" --verbose
	darkhttpd /tmp --addr 0.0.0.0 --port 80 --chroot --index index.html
	yourbrowser http://yourserver

Create your application with the name e.g.  TestService  at the directory  /opt/TestService

	dancer2 gen --application TestService --directory TestService --path /opt --overwrite
	chown -R dancer:dancer /opt/TestService

Use compressed http if you have fast CPU and large replies
vi /opt/TestService/bin/app.psgi

	#!/usr/bin/env perl
	use FindBin;
	use lib "$FindBin::Bin/../lib";
	use TestService;
	use Plack::Builder;
	builder { enable 'Deflater'; TestService->to_app }


Configure the production enviroment
vi /opt/TestService/environments/production.yml

    # logger    : file, console
    # log level : core, debug, info, warning, error

    startup_info     : 1
    show_errors      : 1
    warnings         : 1
    no_server_tokens : 0

    logger           : 'console'
    log              : 'file'
    engines:
      logger:
        file:
          log_format : '{"ts":"%{%Y-%m-%d %H:%M:%S}t","host":"%h","level":"%L","message":"%m"}'
          log_dir    : '/var/log/WebService'
          file_name  : 'TestService.log'
        console:
          log_format : '{"ts":"%{%Y-%m-%d %H:%M:%S}t","host":"%h","level":"%L","message":"%m"}'





Configure your application settings, changing the values to your needs
vi /opt/TestService/config.yml


# enviroment related settings should go to /environments yml files

version                 : 4.1.3
environment             : production
charset                 : UTF-8
plugins                 :
  WebService            :
    Owner               : dancer Lunchbucket, dancer.Lunchbucket@example.com
    Session directory   : /var/lib/WebService
    Session idle timout : 3600
    Default format      : json
    Routes              :
      INeedLogin        : private
      summer            : public
      winter            : public

    Allowed hosts:
    - 127.*
    - 10.*
    - 172.??.?.*
    - 192.168.1.23
    - 4.?.?.??
    - ????:????:????:6d00:20c:29ff:*:ffa3
    - "*"

    Authentication methods:
    - Name     : simple
      Active   : yes
      Command  : INTERNAL
      Accounts :
        <any>  : secret4all
        user1  : <any>		
        user2  : pass2

    - Name      : Linux native users
      Active    : false
      Command   : MODULE_INSTALL_DIR/AuthScripts/LinuxNative.pl
      Arguments : [ ]
      Groups    : [root, ldap , gluster , ceph]
      Use sudo  : true

    - Name      : Basic Apache auth for simple users
      Active    : true
      Command   : MODULE_INSTALL_DIR/AuthScripts/HttpBasic.sh
      Arguments : [ "/etc/htpasswd" ]
      Groups    : [ ]
      Use sudo  : no


Write your rest service code at   /opt/TestService/lib/TestService.pm   e.g.
vi /opt/TestService/lib/TestService.pm


package	TestService;
use		Dancer2;
use		Dancer2::Plugin::WebService;
use		strict;
use		warnings;

any '/mirror' => sub { reply 'SEND_DATA' };
get '/route1' => sub { reply };
any '/route2' => sub { reply 'k1' };
get '/route3' => sub { reply 'k1'=>'v1', 'k2'=>'v2' };

get '/error'  => sub { reply 'k1', 'v1', 'error', '37', 'errormessage', 'fever' };

any '/get1'   => sub { my  %all = get_data_post;
                 reply %all };

any '/get2'   => sub { my ($v1, $v2) = get_data_post('k1', 'k2');
                 reply 'foo'=>$v1 , 'boo'=>$v2
                 };

any '/secure' => sub {
                 my %send = get_data_post;
                            set_data_session('s1'=>'L1', 's2'=>'L2', 's3'=>['L3a', 'L3b']);
                            del_data_session('s2', 's8', 's9');
                 my %All  = get_data_session();
                 my @Some = get_data_session('s1', 's7');

                 reply( send=>{%send}, ses_all=>{%All}, s1=>$Some[0], s7=>$Some[1] )
                 };
dance;








If you are using nginx web server to reverse proxy you service 
from port 80 or for adding https protection ( port 443 )
Add at your nginx.conf something similar to

	...
	upstream TestService { server 127.0.0.1:3000 fail_timeout=0; keepalive 1024; }
	...
	server
	{
	server_name      anotherdimension.mooo.com;
	listen           80;
	listen           443 ssl;
	root             /tmp;
	proxy_redirect   off;
	proxy_set_header Host      $host;
	proxy_set_header X-Real-IP $remote_addr; # needed for real client IP pass as server enviroment variable HTTP_X_REAL_IP

	    location /
	    {
	    fastcgi_param REMOTE_ADDR X-Real-IP;
	    proxy_pass http://TestService;
	    } 
	}



plackup executable is usually at the following locations

    /usr/local/bin/plackup        # RedHat
    /usr/bin/site_perl/plackup    # Archlinux


It is a good idea tou start your application as Linux service
We bind at port 127.0.0.1 because we usually publish such services
using the the nginx as reverse proxy

vi /usr/lib/systemd/system/testservice.service


[Unit]
Description=Perl Dancer2 restful web service
Documentation=https://metacpan.org/pod/Dancer2
After=network.target
ConditionPathExists=/usr/local/bin/plackup

[Service]
Type=simple
User=dancer
Group=dancer
ExecStart=/usr/local/bin/plackup --host 127.0.0.1 --port 3000 --server Starman --workers=10 --env production -a /opt/TestService/bin/app.psgi
# for Archlinux   ExecStart=/usr/bin/site_perl/plackup --host 127.0.0.1 --port 3000 --server Starman --workers=10 --env production -a /opt/TestService/bin/app.psgi
ExecStop=/bin/kill -s QUIT $MAINPID
WorkingDirectory=/opt/TestService
KillMode=mixed
KillSignal=QUIT
StandardOutput=journal
StandardError=journal
NoNewPrivileges=true
PrivateTmp=true
LimitNOFILE=infinity
Restart=on-failure
RestartSec=60s


[Install]
WantedBy=multi-user.target


start the service

	systemctl enable    testservice.service
	systemctl cat       testservice
	systemctl start     testservice
	systemctl is-active testservice
	systemctl status    testservice
	journalctl -xelu    testservice | less

delete the service

	systemctl stop      testservice
	systemctl disable   testservice.service
	rm /usr/lib/systemd/system/testservice.service

start the application manual

	cd /opt/TestService

	# production
	sudo -u dancer plackup --host 0.0.0.0 --port 3000 --server Starman --workers=5 --env production -a /opt/TestService/bin/app.psgi
	
	# development
	sudo -u dancer plackup --host 0.0.0.0 --port 3000 --server HTTP::Server::PSGI --env development --Reload /opt/TestService/lib/TestService.pm,/opt/TestService/config.yml -a /opt/TestService/bin/app.psgi
	sudo -u dancer plackup --host 0.0.0.0 --port 3000 --server HTTP::Server::PSGI --env development --Reload /opt/TestService/lib/TestService.pm,/opt/TestService/config.yml,/opt/Dancer2-Plugin-WebService/lib/Dancer2/Plugin/WebService.pm -a /opt/TestService/bin/app.psgi

	# without Plack
	sudo -u dancer perl /opt/TestService/bin/app.psgi

quick test

	ss -tln 'sport = :3000'
	curl -X GET http://localhost:3000/WebService?to=human