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 Cpanel::JSON::XS
  cpanm YAML::XS
  cpanm YAML::Syck
  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.

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

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 {} \;

If you are running the service as user dancer, and want to want to use an authentication method that needs root privileges
give the appropriate privileges	using the sudoers e.g
vi /etc/sudoers

  dancer ALL=(ALL:ALL) NOPASSWD: /usr/share/perl5/site_perl/Dancer2/Plugin/AuthScripts/linux.sh

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 settings are at   environments/*.yml

environment             : development
plugins                 :
  WebService            :
    Default format      : json
    Session directory   : /var/lib/WebService
    Session idle timeout: 86400
    Routes              :
      mirror            : { Protected: false }
      somekeys          : { Protected: false }
      data1             : { Protected: false }
      data3             : { Protected: false }
      INeedLogin_store  : { Protected: true, Groups: [ ftp , storage ] }
      INeedLogin_delete : { Protected: true, Groups: log }
      INeedLogin_read   : { Protected: true }

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

    Authentication methods:
    - Name     : INTERNAL
      Active   : false
      Accounts :
        user1  : pass1
        user2  : <any>
        <any>  : Secret4All

    - Name     : Linux native users
      Active   : true
      Command  : MODULE_INSTALL_DIR/AuthScripts/linux.sh
      Arguments: [ ]
      Use sudo : true

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





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


package	MyApi;
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


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 -a /opt/TestService/bin/app.psgi --Reload /opt/TestService/lib/TestService.pm,/opt/TestService/config.yml,/opt/Dancer2-Plugin-WebService/lib/Dancer2/Plugin/WebService.pm

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

quick test

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








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
