During this meeting Ferenc Erki, the lead developer of Rex helped us with various tasks using Rex.

We started where we left of last time when FErki gave us an introduction to Rex.

Before the meeting

I've created a Rexfile to set up the environment as we had it when we finished the first session.

  • Created a pair of private/public keys that will be used in these examples. Locally I saved them in ~/.ssh/rex. I have manually uploaded the public key to Digital Ocean and call it Rex.
  • Create A Droplet with Ubuntu 20.04 in New York 1. Hostname code-maven-rex. This will me the management machine during the meeting.
  • Also create 2 Droplets with Ubuntu 20.04 in New York 1 Hostname ubu-1 and ubu-2 using the Rex public key
  • On the management server: Install Rex using apt-get, copy the .ssh/config file and copy the files we created in the previous session
  • Copy the private ssh key to ~/.ssh/ on code-maven-rex, the management machine.
  • Run the Rex code on the management server to set up the web server on ubu-1


use Rex -feature => [qw( 1.4 exec_autodie)];

desc 'Just printing hostname';
task 'print_hostname', sub {
    say run('hostname');

desc 'Install Rex from Linux distribution';
task install_rex => sub {
    pkg 'rex', ensure => 'present';
    say run('rex -v');

desc 'Configure Rex';
task configure_rex => sub {

    # file is a "resource"  (included in the audit log)
    file '/root/.ssh',
      ensure => 'directory',
      owner  => 'root',
      group  => 'root',
      mode   => '0700';
    file '/root/.ssh/id_rsa',
      source => '/home/gabor/.ssh/rex/rex_id_rsa',
      owner  => 'root',
      group  => 'root',
      mode   => '0600';
    file '/root/.ssh/config', source =>
      'files/config';    # had to edit manually including the IP addresses
    file '/root/infra',         ensure => 'directory';
    file '/root/infra/files',   ensure => 'directory';
    file '/root/infra/Rexfile', source => '../infra/Rexfile';

    # sync_up, sync_down are "commands"
    sync_up '../infra/files', '/root/infra/files';

desc 'Check Rex';
task check_rex => sub {
    #if( not is_installed("tree") ) {
    #    update_package_db;
        pkg 'tree', ensure => 'present';

    #say for run(q{tree -a /root/});
    say scalar run(q{tree -a /root/});

# This did not work well
desc 'update';
task update => sub {

    #run('apt-get dist-upgrade -y');
    say run('uptime');

    #say run('uptime');

desc 'Reboot';
task reboot => sub {
    say run('uptime');
    task '_reboot';
    say run('uptime');

desc 'Reboot';
task _reboot => sub {

use Rex::Commands::SimpleCheck;

sub wait_for_system_to_come_back {
  my ($server) = @_;

  # give some time for the reboot
  Rex::Logger::info("Waiting for system reboot of $server...");
  #sleep 30;

  while ( !is_port_open $server, 22 ) {
    sleep 1;

  Rex::Logger::info("System $server is up and running again...");
  #Rex::Logger::info("Waiting 30 seconds for the services to start up...");
  #sleep 30;

  # reconnect ssh

I had to update the config file manually based on the IP addresses generated by Digital Ocean.


#Host *
#  StrictHostKeyChecking no

Host ubu1

Host ubu2


  • Switch to latest Rex from CPAN.
  • Create droplets using Fedora, Debian, CentOS, and FreeBSD as well in different regions. (Done manually during the meeting.)
  • Deploy the Web server with our page on each one of them. (Managed to do it partially)
  • Introduction to templates - Change the html page so on each distribution it will say "Welcome to DISTRIBUTION by Rex"
  • We discussed a way to version control exactly what we are running? (So list inventory and only allow to run on the macnies in the inventory. host groups?)

Added the following to ~/.bashrc, disconnected and logged in again.

eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)"

Bash history


    1  rex -v
    2  cpanm
    3  adduser rexify
    4  perl -MCPAN -Mlocal::lib -e 'CPAN::install(LWP)'
    5  apt search local-lib
    6  apt search liblocal-lib-perl
    7  apt install liblocal-lib-perl
    8  perl -Mlocal::lib
    9  vim .bashrc
   10  printenv
   11  apt install libcpanminus-lib-perl
   12  apt install cpanminus
   18  apt install build-essential
   19  cpanm Rex
   20  rex -v
   21  ll
   22  cd infra/
   23  ll
   24  rex -T
   25  rex -H 'ubu[1,2]' print_hostname
   26  vim ~/.ssh/config 
   27  rex -H 'ubu[1,2] deb1' print_hostname
   28  rex -H 'ubu[1,2] deb1' -T
   29  rex -H 'deb1' setup_nginx
   30  vim Rexfile 
   31  rex -H 'deb1' setup_nginx -d
   32  rex -H 'deb1' -d setup_nginx
   33  vim Rexfile 
   34  rex -H 'deb1' setup_nginx
   35  cat ~/.ssh/config 
   36  rex -H 'deb1' setup_nginx -T
   37  rex -H 'deb1' -T setup_nginx
   38  rex -H 'deb1' -T
   39  rex -H 'deb1' configure_nginx
   40  vim ../.ssh/config 
   41  #rex -H 'ubu[1,2] deb1 cent1 fed1 free1' print_hostname
   42  cat ~/.ssh/config 
   43  rex -H 'ubu[1,2] deb1 cent1 fed1 free1' print_hostname
   44  fg
   45  vim Rexfile 
   46  fg
   47  rex -T
   48  rex -G all print_hostname
   49  rex -G all -T
   50  rex -G all setup_nginx
   51  rex -h
   52  rex -h | less
   53  rex -t 6 -G all setup_nginx
   54  cat ~/.ssh/config
   55  fg
   56  rex -t 6 -G all setup_nginx
   57  fg
   58  rex -H ubu1 -e 'run(q{get_operating_system})'
   59  rex -H ubu1 -e 'say get_operating_system'
   60  rex -H fed1 -e 'say get_operating_system'
   61  fg
   62  rex -t 6 -G all configure_nginx
   63  rex -H 'fed1' -e 'say run(q{getent passwd})'
   64  rex -H 'fed1' -e 'say scalar run(q{getent passwd})'
   65  rex -H 'cent1' -e 'say scalar run(q{getent passwd})'
   66  rex -H 'free1' -e 'say scalar run(q{getent passwd})'
   67  fg
   68  rex -t 6 -G all configure_nginx
   69  fg
   70  rex -t 6 -G all configure_nginx
   71  fg
   72  rex -H 'fed1' -e 'say scalar run(q{ls -l /etc/nginx})'
   73  rex -H 'fed1' -e 'say scalar run(q{ls -l /etc/nginx/conf.d})'
   74  rex -H 'cent1' -e 'say scalar run(q{ls -l /etc/nginx/conf.d})'
   75  fg
   76  rex -H 'fed1 cent1' -e 'say scalar run(q{ls -l /etc/nginx/sites-enabled})'
   77  rex -H 'cent1' -e 'say scalar run(q{ls -l /etc/nginx/sites-enabled})'
   78  fg
   79  rex -H 'free1' -e 'say scalar run(q{ls -l /etc/})'
   80  fg
   81  rex -t 6 -G all configure_nginx
   83  rex -H 'fed1 cent1' -e 'say scalar run(q{ls -l /tmp/})'
   84  rex -H 'fed1 cent1' -e 'say scalar run(q{ls -l /tmp/rex/})'
   85  rex -H 'fed1 cent1' -e 'say scalar run(q{cat /etc/nginx/nginx.conf})'



use Rex -feature => [qw( 1.4 exec_autodie)];

group all => qw(ubu[1,2] deb1 cent1 fed1 free1);

desc 'Just printing hostname';
task 'print_hostname', sub {
    say run('hostname');

desc 'Setup nginx';
task setup_nginx => sub {
    pkg 'nginx', ensure => 'present';
    service 'nginx', ensure => 'started';

desc 'Configure new Rex website';
task configure_nginx => sub {
    # copy ubu-1.conf to /etc/nginx/sites-enabled/
    #run('rm -f /etc/nginx/sites-enabled/default');
    my $nginx_dir = case operating_system, {
                qr{Debian|Ubuntu}i  => "/etc/nginx/sites-enabled",
                qr{Fedora|Centos}i  => "/etc/nginx/conf.d",
                qr{FreeBSD}i        => 'www',
                default             => "www-data",

    file "$nginx_dir/default", ensure => 'absent';
    file "$nginx_dir/ubu-1.conf",
        source => 'files/ubu-1.conf',
        on_change => sub {
            service 'nginx' => 'reload';

    # copy main.html to /root/rex/index.html
    #file '/root/rex', ensure => 'directory';
    #file '/root/rex/index.html', source => 'files/main.html';

    # copy main.html to /tmp/rex/index.html
    my $owner = case operating_system, {
                qr{Debian|Ubuntu}i  => "www-data",
                qr{Fedora|Centos}i  => "nginx",
                qr{FreeBSD}i        => 'www',
                default             => "www-data",

    file '/tmp/rex', ensure => 'directory', owner => $owner, group => $owner, mode => '0755';
    #file '/tmp/rex/index.html', source => 'files/main.html';
    my $hostname = run('hostname');
    file '/tmp/rex/index.html', content => template('files/main.html', name => $hostname );

    # reload nginx
    #service 'nginx' => 'reload';

# vim: syntax=perl

HTML Template


<h1>Welcome to Rex on <%= $name -%> - <%= Rex::Commands::Gather::get_operating_system %></h1>

Nginx config file


server {
  listen [::]:80;
  listen 80;
  server_name ubu-1;

  root /tmp/rex;
  location / {
    autoindex on;

.ssh/config file


#Host *
#  StrictHostKeyChecking no

Host ubu1

Host ubu2

Host deb1

Host fed1

Host cent1

Host free1