The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
You should run the service with an unprivilidged user e.g. joe
Please be careful that non root users can not bind port numbers from 1 to 1024


Firt make sure you some prerequisite modules installed
You can install them using e.g. the cpanm utility

	# First  install the cpanm itself
	curl -L --insecure https://cpanmin.us | perl - App::cpanminus
	
	# The rest modules
	cpanm Data::Dumper
	cpanm XML::Hash::XS
	cpanm JSON::XS
	cpanm YAML::XS
	cpanm Moo
	cpanm Plack
	cpanm Plack::Middleware::Deflater
	cpanm Starman
	cpanm Dancer2
	cpanm Dancer2::Plugin::WebService

or for every modules

	tar xvzf ....tar.gz
	cd ...
	perl Makefile.PL
	make
	make test
	make install
	
Assuming that you will start the application as a non privileged user e.g. joe
Create the user if not exists

	getent group  joe >/dev/null || groupadd joe
	getent passwd joe >/dev/null || useradd -g joe --no-log-init -c "Dancer2-Plugin-WebService user" -s /sbin/nologin joe
	lslogins -o USER,GROUP,UID,SHELL joe

Create the application e.g TestService inside e.g. the /opt folder

	cd /opt
	dancer2 gen --application TestService

Give ownership to joe

	mkdir            /var/log/TestService
	mkdir            /usr/local/sessions
	chown -R joe:joe /opt/TestService
	chown -R joe:joe /var/log/TestService
	chown -R joe:joe /usr/local/sessions

	chown -R joe:joe /usr/share/perl5/site_perl/Dancer2/Plugin/scripts

	chmod u+x /usr/share/perl5/site_perl/Dancer2/Plugin/scripts/LinuxOS/AuthUser.pl
	chmod u+x /usr/share/perl5/site_perl/Dancer2/Plugin/scripts/HttpBasic/users.pl
	chmod u+x /usr/share/perl5/site_perl/Dancer2/Plugin/scripts/HttpBasic/admins.pl

Use logrotate to housekeeping the log files
vi /etc/logrotate.d/TestService

	/var/log/TestService/*.log
	{
	create 640 joe joe
	compress
	missingok
	notifempty
	daily
	rotate 7
	}





If you want your routes ro provide geop ip information install the GeoIP package

At archlinux        pacman -S geoip geoip-database geoip-database-extra
At debian           apt-get install geoip-bin
At fedora, redhat   yum install geoip
At CentOS 5         rpm -Uvh http://mirrors.kernel.org/fedora-epel/5/i386/epel-release-5-4.noarch.rpm
At CentOS 6         rpm -Uvh http://mirrors.kernel.org/fedora-epel/6/i386/epel-release-6-8.noarch.rpm
                    yum repolist
                    yum install geoip







If you want compressed replies
vi /opt/TestService/bin/app.psgi

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

Or if you have slow CPU use uncompressed replies
vi /opt/TestService/bin/app.psgi
	
	#!/usr/bin/perl
	use FindBin;
	use lib "$FindBin::Bin/../lib";
	use TestService;	
	TestService->to_app;


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

  show_errors      : 1
  startup_info     : 1
  warnings         : 1 
  no_server_tokens : 0
  log              : "core"
  logger           : "file"
  engines          :
    logger         :
      File         :
        log_dir    : "/var/log/TestService"
        file_name  : "activity.log"






Configure your application settings
vi /opt/TestService/config.yml



appname      : TestService
environment  : production
plugins      :
  WebService :
    Version             : 1.0.4
    Owner               : Joe Lunchbucket, Joe.Lunchbucket@example.com
    Session directory   : /usr/local/sessions
    Session idle timout : 3600
    Default format      : json
    Command sudo        : /usr/bin/sudo
    Command rm          : /usr/bin/rm
    Routes              :
      test1             : public
      test2             : public
      test3             : private
      
    Allowed hosts:

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

    User must belong to one or more of the groups:

      - power
      - storage
      - network

    Authentication method:
      Always allow login for testing:
        Command  : MODULE_INSTALL_DIR/scripts/AlwaysOk/AlwaysOk.sh
        Active   : no
        Use sudo : no
      Linux native users:
        Command  : MODULE_INSTALL_DIR/scripts/LinuxOS/AuthUser.pl
        Active   : yes
        Use sudo : yes
      Basic Apache auth for simple users:
        Command  : MODULE_INSTALL_DIR/scripts/HttpBasic/users.pl
        Active   : no
        Use sudo : no
      Basic Apache auth for admins:
        Command  : MODULE_INSTALL_DIR/scripts/HttpBasic/admins.pl
        Active   : no
        Use sudo : no
      Active directory:
        Command  : MODULE_INSTALL_DIR/scripts/Active Directory/Active Directory.pl
        Active   : no
        Use sudo : no
      LDAP:
        Command  : MODULE_INSTALL_DIR/scripts/LDAP/LDAP.pl
        Active   : no
        Use sudo : no










Write your real code at   /opt/TestService/lib/TestService.pm   e.g.



  package TestService;
  use     strict;
  use     warnings;
  use     Dancer2;
  use     Dancer2::Plugin::WebService;
  our     $VERSION = setting('plugins')->{WebService}->{Version};

  any '/test_mirror'      => sub { RestReply('DATA_USER_SEND') };
  any '/test_get_one_key' => sub { RestReply('k1') };

  any '/test_get_data'    => sub {
  my ($var1, $var2) = get_data_user('k1', 'k2');
  RestReply( Total => ($var1 + $var2), Thought => 'Lets add !' )
  };

  any '/test_new_data'    => sub { 
  my %data = 
  set_data_user( new1 => 'N1', new2 => 'N2' );
  set_data_user( new3 => 'N3', new4 => 'N4' );
  del_data_user( 'new1' , 'new4' );
  RestReply('DATA_USER_ALL')
  };

  setting('plugins')->{'WebService'}->{'Routes'}->{'test_session'} = 'private';

  any '/test_session' => sub {
  my ($v1, $v2) = get_data_user('k1', 'k2');
	          set_data_session(s1 =>'L1', s2=>'L2', s3=>['L3a', 'L3b']);
	          del_data_session('s7', 's8');
  my @Some      = get_data_session('s1', 's2', 's3', 's7');
  my %All       = get_data_session();
  RestReply(k1=>$v1, k2=>$v2, SesData_A => $Some[2], SesData_b=> [ @Some[0..1] ], SesData_all=> { %All } )
  };

  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:65535 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 with the nginx

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/bin/site_perl/plackup

	[Service]
	Type=simple
	User=joe
	Group=joe
	ExecStart=/usr/bin/site_perl/plackup --host 127.0.0.1 --port 65535 --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=inherit 
	NoNewPrivileges=true
	PrivateTmp=true
	LimitNOFILE=infinity
	RestartPreventExitStatus=255
	Restart=on-failure
	RestartSec=60s
	NotifyAccess=all

	[Install]
	WantedBy=multi-user.target





start the service

	systemctl enable testservice.service
	systemctl cat    testservice
	systemctl start  testservice
	systemctl show --property=ActiveState testservice
	systemctl status testservice
	journalctl -xeu  testservice | less

to 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 joe /usr/bin/site_perl/plackup --host 127.0.0.1 --port 65535 --server Starman --workers=10 --env production -a /opt/TestService/bin/app.psgi

or during development

	cd /opt/TestService; sudo -u joe /usr/bin/site_perl/plackup --port 65535 -a /opt/TestService/bin/app.psgi --Reload /opt/TestService/lib,/opt/TestService/config.yml,/usr/share/perl5/site_perl/Dancer2/Plugin
	cd /opt/TestService; sudo -u joe /usr/bin/site_perl/plackup --port 65535 -a /opt/TestService/bin/app.psgi

or without Plack

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

quick test

	netstat -anp | grep :65535
	curl -X GET http://localhost:65535/info?to=human