Make sure you have the prerequisite modules installed.
e.g for Redhat/Centos 7.x

	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 

	cpanm XML::Hash::XS
	cpanm JSON::XS
	cpanm YAML::XS
	cpanm Moo
	cpanm Plack
	cpanm Plack::Middleware::Deflater
	cpanm Starman
	cpanm Template::Toolkit
	cpanm Dancer2
	cpanm Dancer2::Plugin::WebService

After install Dancer2::Plugin::WebService you should run it as a non privileged user e.g. dancer
Be careful, non root users can not bind ports up to 1024
Create the user and ownership

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

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

If there is a firewall open the listening port e.g. at Redhat

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

	# Redhat
	find /usr/local/share/perl5/Dancer2/Plugin/scripts      -regex ".*\.\(sh\|pl\)\$" -type f -exec chmod 755 {} \;	
	# Archlinux
	find /usr/share/perl5/site_perl/Dancer2/Plugin/scripts  -regex ".*\.\(sh\|pl\)\$" -type f -exec chmod 755 {} \;
	
If you want to use an authentication method that needs sudo, you must add the user running
the WebService ( dancer ) on a sudoers file e.g.

	vi /etc/sudoers.d/WebService

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

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
	}


Create a skeleton for your service e.g. at  /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


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              :
      secure            : private
      mirror            : public
      route1            : public
      route2            : public
      route3            : public
      error             : public
      get1              : public
      get2              : public

    Allowed hosts:

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

    User must belong to one or more of the groups:

      - powerusers
      - postfix
      - tape

    Authentication methods:

      - Name     : simple
        Active   : yes
        Command  : INTERNAL
        Users    :
          <any>  : secret4all
          user1  : <any>		
          user2  : pass2

      - Name     : Linux native users
        Active   : yes
        Command  : MODULE_INSTALL_DIR/scripts/LinuxOS/AuthUser.pl
        Use sudo : yes

      - Name     : Basic Apache auth for simple users
        Active   : no
        Command  : MODULE_INSTALL_DIR/scripts/HttpBasic/users.pl
        Use sudo : no

      - Name     : Basic Apache auth for admins
        Active   : no
        Command  : MODULE_INSTALL_DIR/scripts/HttpBasic/admins.pl
        Use sudo : no


Write your real 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;
	    } 
	}





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 -xeu     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; sudo -u dancer plackup --host 127.0.0.1 --port 3000 --server Starman --workers=10 --env production -a /opt/TestService/bin/app.psgi

or during development (Redhat)

	sudo -u dancer /usr/local/bin/plackup --port 3000 -a /opt/TestService/bin/app.psgi --Reload /opt/TestService/lib,/opt/TestService/config.yml,/usr/local/share/perl5/Dancer2/Plugin
	
	or without Plack

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

quick test

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