test SMTP server credentials using command line

smtp server namesmtp server porte-mailpassword
mydomain.com587myuser@mydomain.commypasswd
credentials example

1 – convert the e-mail to base64

echo -n "myuser@mydoamin.com" | base64

2 – convert the password to base64

echo -n "mypasswd" | base64

3 – connect to the smtp server using openssl

openssl s_client -debug -starttls smtp -crlf -connect mydoamin.com:587

4 – send the commands to the server to validate the credentials

EHLO
AUTH LOGIN
<paste the e-mail converted to base64>
<paste the passwod converted to base64>

If the credentials are correct the output will be: Authentication successful

disable middle mouse button

1 – install xinput package

apt install xinput

2 – get the the mouse id

xinput list

3 – disable the middle muse button ( first param is the id )

xinput set-button-map 17 1 0

get mouse id by name and disable the middle button

xinput list | awk -F= '/Logitech USB Optical Mouse/ { split( $2 ,arr," "); print arr[1] }' | xargs -i xinput set-button-map {} 1 0

delete user with ansble

# delete_user.yml: remove user on target host
# usage example: ansible-playbook delete_user.yml -e target=localhost -e user=testusr
#
# params: target, user

- name: set host
  hosts: "{{ target | lower }}"                                   # target host[1+]

  tasks:

  - name: print usage
    fail:
      msg: "some mandatory param is missing or empty: user. sample usage: ansible-playbook delete_user.yml -e host=localhost -e user=testusr"
    when: (user is undefined) or (user|length == 0)

  - name: delete user
    user:
      name: "{{ user | lower }}"                                # user name[1]
      state: absent
    become: true

links

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html

create user with ansible

# create_user.yml: create user on target host
# execution example: ansible-playbook create_user.yml -e target=localhost -e user=testusr -e passwd=123 -e uid=1007 -e group=users -e additional_groups='sudo,audio,video' -e 'info="support user"' 
#
# params: target, user, passwd, uid, [group], [groups], [info]

- name: set host
  hosts: "{{ target | lower }}"                                 # target host[1+]

  tasks:

  - name: print usage
    fail:
      msg: "some mandatory param is missing or empty: user, passwd, uid. sample usage: ansible-playbook create_user.yml -e host=localhost -e user=testusr -e passwd=123 -e uid=1007 -e group=users -e additional_groups='sudo,audio,video' -e 'info=\"support user\"'"
    when: (user is undefined) or (user|length == 0) or (passwd is undefined) or (passwd|length == 0) or (uid is undefined) or (uid|length == 0)

  - name: create user
    user:
      name: "{{ user | lower }}"                                # user name[1]
      password: "{{ passwd | password_hash('sha512') }}"        # user password[1]
      uid: "{{ uid }}"                                          # uid[1]
      group: "{{ group | default('users') }}"                   # default group[0,1]
      groups: "{{ additional_groups | default('sudo,audio') }}" # additional groups[0+]
      append: yes                                               # append additional groups
      shell: /bin/bash                                          # user shell
      comment: "{{ info | default('created by awx') }}"         # user info[0,1]
      update_password: on_create                                # no update passwd if playbook run twice
      state: present
    become: true

links

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html

change user password with ansible

# change_passwd.yml: change user password on target host
# execution example: ansible-playbook change_passwd.yml -e target=localhost -e user=root -e passwd=123
#
# params: target, user, passwd

- name: set host
  hosts: "{{ target | lower }}"                                 # target host param[1+]

  tasks:

  - name: print usage if some param is missing or empty
    fail:
      msg: "some param is missing or empty: host, user, passwd. sample usage: ansible-playbook change_passwd.yml -e target=localhost -e user=root -e passwd=123"
    when: (user is undefined) or (user|length == 0) or (passwd is undefined) or (passwd|length == 0)

  - name: check if user exist
    getent:
      database: passwd
      key: "{{ user | lower }}"                                 # user name param[1]
      fail_key: yes                                             # quit if user doesn't exist

  - name: change user password
    user:
      name: "{{ user | lower }}"                                # user name param[1]
      password: "{{ passwd | password_hash('sha512') }}"        # user password param[1]
      update_password: always
      state: present
    become: true

links

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/getent_module.htm

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html

execute command after DHCP assign a new IP address

1 – create a file with commands that will be executed (it runs in alphabetical order)

cat > /etc/dhcp/dhclient-exit-hooks.d/z_cmds <<EOF
put the commands here
EOF

2 – change the owner from the created file

chown root. /etc/dhcp/dhclient-exit-hooks.d/z_cmds

3 – change the permission from the created file

chmod 700 /etc/dhcp/dhclient-exit-hooks.d/z_cmds

reference: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_and_managing_networking/assembly_running-dhclient-exit-hooks-using-networkmanager-a-dispatcher-script_configuring-and-managing-networking

curl speed test

#!/bin/bash

test ! -e /tmp/curl.format && cat > /tmp/curl.format <<EOF
   time_namelookup: %{time_namelookup}s\n 
      time_connect: %{time_connect}s\n
   time_appconnect: %{time_appconnect}s\n 
  time_pretransfer: %{time_pretransfer}s\n
     time_redirect: %{time_redirect}s\n 
time_starttransfer: %{time_starttransfer}s\n
 ----------\n 
time_total: %{time_total}s\n
EOF

curl -L -s -w "@/tmp/curl.format" $url_here

setup a local DNS cache server

1 – enable and start systemd-resolved service

systemctl enable systemd-resolved; systemctl start systemd-resolved

2 – replace line starting with DNS= by DNS servers that will be used in /etc/systemd/resolved.conf file

sed -i -E 's/^#DNS=.*|^DNS=.*/DNS=8.8.8.8 8.8.4.4/' /etc/systemd/resolved.conf

3 – replace /etc/resolv.conf to use systemd-resolved configuration settings

cp /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

4 – restart systemd-resolved service

systemctl restart systemd-resolved

5 – check the status of systemd-resolved service

resolvectl status

setup secure DNS queries (optional step)

sed -i -E 's/^#DNSSEC=.*|^DNSSEC=.*/DNSSEC=allow-downgrade/' /etc/systemd/resolved.conf

sed -i -E 's/^#DNSOverTLS=.*|^DNSOverTLS=.*/DNSOverTLS=opportunistic/' /etc/systemd/resolved.conf

update a tar file

delete the current file if it exist

tar --delete -f file.tar etc/passwd

append/update the new file

tar -uvf file.tar /etc/passwd

list tar file content

tar -tvf file.tar

show the file content inside of tar archive

tar xfO file.tar etc/passwd

script to update/add a file to a tar archive

#!/bin/bash
# usage: update_tar_file.sh file.tar file_to_update

test $# -ne 2 && sed -n '/^# usage/ { s/^# //p }' $0 && exit

tar -tvf $1 | grep -q $2 && tar --delete -f $1 $2	# delete file it it already exist in tar archive

tar -uvf $1 $2						# add/update the file in the tar archive

tar -tvf $1 | grep $2		        # list updated/new file in the tar archive

tar xfO $1 $2						# show content of updated/new file in the tar archive

bypass google authenticator to local network

1 – edit /etc/security/access.conf file

cat >> /etc/security/access.conf <EOF
+ : ALL : 192.168.0.0/24
- : ALL : ALL
EOF

2 – edit /etc/pam.d/sshd file

cat >> /etc/pam.d/sshd <EOF
# bypass google authenticator to local network
auth [success=done default=ignore] pam_access.so accessfile=/etc/security/access.conf
auth required pam_google_authenticator.so nullok
EOF

3 – restart ssh service

systemctl restart ssh

format ansible output

colorize only hostname and remove string from hostname line

#!/bin/bash

awk '/rc=0 >>/ ? $0="\033[33;1m" $0 "\033[m" : $0'      | # colorize each host line
sed 's/ | CHANGED | rc=0 >>//'                            # remove string from host line

same as above + colorize error messages

#!/bin/bash

awk '{
  if (/rc=0 >>/) { print "\033[33;1m" $0 "\033[m" }                     # colorize sucessful host line
  else if (/UNREACHABLE! =>/) { print "\033[31;1m" $0 "\033[m" }        # colorize error host line
  else if (/command not found/) { print "\033[41;1m" $0 "\033[m" }      # colorize output error line
  else if (/No such file or dir/) { print "\033[41;1m" $0 "\033[m" }    # colorize output error line
  else { print $0 }                                                     # print other lines
}'                                                                      |
sed 's/ | CHANGED | rc=0 >>//'                                          # remove string from host line

create an ansible module in bash

create the library directory and the ansible module

mkdir library ; cat > library/get_ip_default_gw.sh <<'EOF'
#!/bin/bash
# get ip connected to default gateway

ip=$( ip route | awk '/^default/ { print $5 }' | xargs ip -4 address show | awk '/inet / { print $2 }' | cut -d/ -f1 )

test -s $ip && echo "{ \"failed\": true, \"erro\": \"IP not found! }" || echo "{ \"ip\": \"$ip\" }"
EOF

test module using ansible ad hoc command

ANSIBLE_LIBRARY=./library ansible localhost -m get_ip_default_gw

test module using ansible playbook

ANSIBLE_LIBRARY=./library ansible-playbook -c local /dev/stdin <<EOF
---
- hosts: localhost
  gather_facts: no

  tasks:

  - name: 'get ip connected to default gateway'
    get_ip_default_gw:
    register: result

  - debug: 
      var: result.ip
EOF

print current and previous line only if previous line fulfills a condition

# conditions: same key, num is bigger or equal 2 and num is lower than previous one
 
cat <<EOF | awk 'NR>1 && prev_key==$2 && $3>=2 && prev_num<$3 { print prev_line"\n"$0 } { prev_line=$0; prev_key=$2; prev_num=$3 }' | uniq 
line    key     num
1       A       0 
2       A       1
3       A       0
4       A       1
5       A       2 <= print current line and previous line
6       B       3
7       B       1
8       B       0
9       B       1
10      B       2 <= print current line and previous line
11      B       3 <= print current line and previous line. duplicated removed by uniq command
12      B       1
EOF

check systemctl service status

#!/bin/bash
# check service status
# usage: check_service_status.sh service 

test $# -eq 0 && echo a service need to be passed as param! && sed -n '/^# usage/ { s/^# //p }' $0 && exit  # print usage and quit

systemctl status $1                             |       # check service status
grep -q 'active (running)'                      &&      # if service is running execute next command
systemctl show $1 --property MainPID            |       # get service PID
grep -q =0$                                     &&      # if PID is equal 0 execute next command
echo 'em_result=PIDFAILED|'                     ||      # print to stdout and quit if PID is equal 0 OR execute next command
systemctl status $1                             |       # check service status and print current status
awk '/Active:/ { $2=="active" && $3=="(running)" ? $0=$3 : $0=$2"_"$3; print }'

draw horizontal line in bash

option 1 – line without space

printf '%.s─' $(seq 1 $(tput cols))

option 2 – line with space

printf %"$(tput cols)"s | tr ' ' '-'

option 3 – line with space

seq -s- $COLUMNS| tr -d '[:digit:]'

option 4 – line with yellow color

tput setaf 3 && printf '%.s─' $(seq 1 $(tput cols)) && tput sgr0

option 5 – line with random color

tput setaf $(shuf -i 1-4 -n 1) && printf '%.s─' $(seq 1 $(tput cols)) && tput sgr0

protect ssh server with fail2ban

1 – install fail2ban

apt install fail2ban

2 – create jail configuration file for sshd service

cat > /etc/fail2ban/jail.d/sshd.conf <<EOF 
[sshd]
enabled = true
bantime = 120	# ban time in seconds
maxretry = 3	# number of failed attemps before ban
EOF

3 – restart fail2ban service

systemctl restart fail2ban

to see blocked IPs, failed attemps and other info

fail2ban-client status sshd

to unban an IP

fail2ban-client set sshd unbanip 192.168.0.7

connect on host using ansible credentials

/etc/ansible/hosts file entry example

srv07 ansible_user=root ansible_password=123456

script to connect in a host using ansible hosts file with root password

cat > ansible_connect.sh <<"EOF" | chmod +x ansible_connect.sh
#!/bin/bash -e
# connect on host using ansible credentials
# usage: ansible_connect.sh hostname

test $# -eq 0 && sed -n '/^# usage/ { s/^. //p }' $0 && exit

hosts_file=/path/to/ansible/hosts/file

host=$( tr '[:upper:]' '[:lower:]' <<<$1 ) # convert hostname to lowercase

! grep -q $host $hosts_file && echo host not found in the file: $hosts_file && exit

host $host # quit if host does not exist

function get_root_passwd {
  grep $host $hosts_file                |
  tr ' ' "\n"                           |
  awk -F= '/password/ { print $2 }'
}

sshpass -p "$( get_root_passwd $host )" ssh -o StrictHostKeyChecking=no -l root $host
EOF

get mac address from a single ip

1 – trying to connect to an ip to known your mac address

nc -z 192.168.0.7 22

2 – list all known mac

ip neighbor

– to flush mac table

ip neighbor flush dev wlan0

– some times is necessary try to connect more than one time to the same ip to get the mac address

for i in {1..3}; do test "$( nc -z 192.168.0.7 22 | awk '{print $NF}' )" != "REACHABLE" && nc -z 192.168.0.7 22; done

screenshot from selected screen area

– install necessary packages

apt install imagemagick xclip gmrun

to save screenshot to the chipboard

way 1 – save selected area from terminal to the clipboard

import png:- | xclip -selection clipboard -t image/png

way 2 – save selected area from X11 session to the clipboard

  • press F2 to run Application Finder or execute gmrun command and paste it
bash -c 'import png:- | xclip -selection clipboard -t image/png'

to save screenshot to a file

way 1 – save selected area from terminal to a file

import /tmp/file.png

way 2 – save selected area from X11 session to a file

  • press F2 to run Application Finder or execute gmrun command and paste it
import /tmp/file.png

check free disk space with ansible

cat > free_disk_space.yml <<EOF
---
# ansible-playbook free_disk_space.yml -e free_mb=512 -e percent_full=70 -e target=all

- name: 'set host'
  hosts: "{{ target }}"
  gather_facts: no

  vars:
    - free_mb: 512      # this value or less
    - percent_full: 97  # this value or more

    - cmd: "df -m | 
        awk '$5 ~ /^[0-9]/' |
        awk '{ print $1,$6,substr( $5, 1, length($5)-1 ),$4,$2 }' |
        awk '$3>={{ percent_full }} && $4<={{ free_mb }} { print $1, $2, $3\"%\", $4\"/\"$5 }'"

  tasks:

  - name: 'execute command'
    shell: "{{ cmd }}"
    register: cmd_output
    changed_when: cmd_output.stdout != ""

  - name: "print execution results"
    debug:
      var: cmd_output.stdout
    when: cmd_output.stdout != ""
EOF

To execute the same with ansible ad-hoc command

ansible srv07 -m shell -a "df -m | awk '\$5 ~ /^[0-9]/' | awk '{ print \$1,\$6,substr( \$5, 1, length(\$5)-1 ),\$4,\$2 }' | awk '\$3>=97 && \$4<=512 {print \$1, \$2, \$3\"%\", \$4\"/\"\$5}'"

check if a package is installed with ansible

cat > check_package.yml <<EOF
---
# check if a package is installed
# ansible-playbook check_package.yml -e package=sssd-common -e target=all

- name: 'set host'
  hosts: "{{ target }}"
  gather_facts: yes

  tasks:

  - name: "check if package is installed on Debian family"
    shell: dpkg -l "{{ package }}"
    changed_when: false
    register: package_check
    when: ansible_facts['os_family'] == "Debian"

  - name: "check if package is installed on Red Hat family"
    shell: rpm -q "{{ package }}"
    changed_when: false
    register: package_check
    when: ansible_facts['os_family'] == "RedHat"

  - name: "print execution results"
    debug:
      msg: "package is installed"
    when: package_check is succeeded
EOF

install ssh public key if user exist with ansible

cat > ssh_pub_key_install.yml <<EOF
---
# install ssh public key if user exist
# ansible-playbook ssh_pub_key_install.yml -e target=srv7

- name: 'set host'
  hosts: "{{ target }}"
  gather_facts: no

  tasks:

  - name: 'execute a command'
    command: bash -c "id lancelot"
    changed_when: false
    register: cmd_output

  - name: 'create file'
    lineinfile:
      path: "$HOME/.ssh/authorized_keys"
      line: "ssh-rsa AAB3NzaC1yc2EAADAQABBAQCeeCZw"
      state: present
      create: yes
    when: cmd_output is succeeded
EOF

execute remote command and save output in localhost using ansible

cat > exec.yml <<EOF
---
# run: ansible-playbook exec.yml -e target=srv07 -e out=a.out

- name: 'set host'
  hosts: "{{ target }}"
  gather_facts: no
  become: true
  become_user: root

  vars:
    - cmd: "hostname; date +%F_%R"

  tasks:

  - name: 'execute command'
    shell: "{{ cmd }}"
    ignore_errors: true
    changed_when: false
    register: cmd_output

  - name: 'save output to a file'
    copy:
      dest: "{{ out }}"
      content: |
        "{{ cmd_output.stdout }}"
    delegate_to: localhost
EOF

copy local file or directory to remote host with ansible

cat > copy_from_localhost2remote_host.yml <<EOF
---
# ansible-playbook copy_from_localhost2remote_host.yml -e file=~/x.sh -e target=srv07 [-e dest_dir=/tmp] [-e perm=0744]

- name: 'set host'
  hosts: "{{ target | lower }}"
  gather_facts: no
  become: true
  become_user: root

  tasks:

  - name: 'copy local file or directory to remote host'
    copy:
      src: "{{ file }}"
      dest: "{{ dest_dir | default('/tmp') }}"
      mode: "{{ perm | default('644') }}"
      force: yes
EOF

test command output in ansible

1 – create a playbook file

cat > play.yml <<EOF
---
- name: 'set host'
  hosts: "{{ target }}"
  gather_facts: no

  tasks:

  - name: 'execute a command'
    command: bash -c "ps ax | grep ssh | grep -v grep"
    register: cmd_output

  - name: 'print execution results'
    debug:
      var: cmd_output
    when: cmd_output is succeeded
EOF

2 – execute the playbook

ansible-playbook play.yml -e target=localhost

run an ansible playbook in a host passed as param

1 – create the playbook

cat > play.yml <<EOF
---
- name: 'set host'
  hosts: "{{ target }}"
  gather_facts: false

  tasks:

  - name: 'show running host'
    debug:
      msg: "running on: {{ inventory_hostname }}"
EOF

2 – run the playbook in a specific host

 ansible-playbook play.yml -e target=localhost

to run in multiple hosts

 ansible-playbook play.yml -e target=localhost,192.168.0.7

ssh jump with ansible

1 – create the ssh config file contains the jump host

cat >> ~/.ssh/config <<EOF
PubKeyAuthentication yes
IdentityFile /path/to/your/private/key/id_rsa
StrictHostKeyChecking no

Host firewall
  HostName 200.221.50.3
  Port 2222
  User mickey
EOF

2 – add the host in the ansible inventory file

cat >>/etc/ansible/hosts <<EOF

internalHost ansible_host=192.168.0.7 ansible_user=root ansible_password=123456 ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -q firewall"'
EOF

3 – test connection

ansible internalHost -m ping

enable /etc/rc.local with systemd

1 – create systemd service file

cat > /etc/systemd/system/rc-local.service <<EOF
[Unit]
Description=enable /etc/rc.local compatibility
ConditionPathExists=/etc/rc.local

[Service]
Type=forking
ExecStart=/etc/rc.local
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99

[Install]
WantedBy=multi-user.target
EOF

2 – enable rc-local service

systemctl enable rc-local

3 – create /etc/rc.local file and set execution permission

cat > /etc/rc.local <<EOF | chmod 700 /etc/rc.local
#!/bin/bash
touch /tmp/file_created_to_test_rc.local
EOF

4 – to test do a reboot or start rc.local service and check if the /tmp file was created

systemctl start rc-local && systemctl status rc-local

pass an array to a function in bash

pass an array as argument to a function

#!/bin/bash

array=("one 1" "two 2" "three 3")

function myFunc() {
  for i in "$@"; do # print all elements
    echo "$i"
  done

  echo $1 # print a single element
}

myFunc "${array[@]}" # call function

pass a hash as argument to a function

#!/bin/bash

declare -A age_location=( ['Man']='21 Lisbon' ['Woman']='22 Rio' )

function myFunc() {
  hashmap=("$@")
  for i in "${hashmap[@]}"; do # print all values
    echo "value: $i"
  done

  echo "$1" # get a single value from an element
}

myFunc "${age_location[@]}" # call function

set default application to an extension

1 – create a .desktop file to a portable application

cat > ~/.local/share/applications/libreoffice.desktop <<EOF 
[Desktop Entry]
Name=LibreOffice
Exec=/path/to/libreOffice-still.basic-x86_64.AppImage
Type=Application
Icon=libreoffice
Categories=Office
EOF

2 – get a file mime type

file --mime-type -b file.ods

3 – associate the mime type to a program

echo 'application/vnd.oasis.opendocument.spreadsheet=libreoffice.desktop' >> ~/.config/mimeapps.list

create a secondary disk to a VM in virtualbox

steps to be executes on VirtualBox Host

1 – safely shutdown the VM (shutdown using ssh if you prefer)

vboxmanage controlvm "VmName" poweroff soft

2 – check if VM is down

vboxmanage list runningvms

3 – get VM path files to do the VM backup

vboxmanage showvminfo "VmName"

DO VM BACKUP

4 – create a new disk with size of 500GB

vboxmanage createhd --filename /path/to/new/disk.vdi --size 500000 --format VDI

5 – show SATA storage info to get: SATA name, SATA port and device

vboxmanage showvminfo "VmName" | less

6 – attach the new disk to a SATA Controller on port 1

vboxmanage storageattach "VmName" --storagectl "SATA" --port 1 --device 0 --type hdd --medium /path/to/new/disk.vdi

7 – check if new disk was attached on SATA Controller

vboxmanage showvminfo "VmName" | less

8 – start VM

vboxmanage startvm "VmName" --type headless

9 – connect into VM using SSH

steps to be executes in the VM

10 – check if OS detect the new disk /dev/sdb

lsblk

11 – create a partition table and a partition into the new disk

cfdisk /dev/sdb

12 – format the new created partition

mkfs -t ext4 /dev/sdb1

13 – mount the new created patition

mount /dev/sdb1 /media

14 – sync /var/log data to the new partition

rsync -aAXHv --info=progress2 /var/log/* /media

15 – set new patition to mount on boot

echo "UUID=$( lsblk -l -o NAME,UUID | awk '$1 == "sdb1" { print $NF }' )    /var/log    ext4    defaults    0    2" >> /etc/fstab

optionally you can delete original /var/log data before execute the next step

16 – resync data again and reboot VM

rsync -aAXHv --info=progress2 /var/log/* /media && init 6

resize vm disk on virtualbox

script to resize a disk on virtualbox

#!/bin/bash
# resizing vm disk on virtualbox

name=centos                                             # vm name
hdd_file=/path/to/disk/$name-disk001.vdi                # full path to disk file
new_size_to_disk_in_mb=20480                            # new disk size in MB
rdp_port=7777                                           # rdp port

iso_dir_path=/path/to/iso/dir                           # dir path of gparted ISO
iso_filename=gparted-live-1.1.0-8-amd64.iso             # filename of gparted ISO

# if ISO file doesn't exist download it
test ! -e $iso_dir_path/$iso_filename && wget https://downloads.sourceforge.net/gparted/$iso_filename -P $iso_dir_path

vboxmanage list runningvms | grep "$name" && read -p "VM is running! shutdown it before continue... press any key after shutdown VM"

vboxmanage list runningvms | grep "$name" && vboxmanage controlvm "$name" poweroff soft && read -p "safely shutdown the VM if it not stopped... press any key to continue"

read -p "DO A COPY/BACKUP OF THE VDI FILE and press any key to continue"

# enable RDP on VM if isn't enable
vboxmanage showvminfo "$name" | grep 'VRDE:.*enabled' || vboxmanage modifyvm "$name" --vrdeport $rdp_port --vrde on

echo show storage info:
vboxmanage showvminfo "$name" | egrep 'SATA|IDE'

read -p "press any key to: dettach HDD to storage"
vboxmanage storageattach "$name" --storagectl "SATA" --port 0 --device 0 --type hdd --medium none
vboxmanage showvminfo "$name" | egrep 'SATA|IDE'

read -p "press any key to: show HDD size and info"
vboxmanage list hdds | grep -B 4 -A 3 "$name"

read -p "press any key to resize disk"
vboxmanage modifyhd $hdd_file --resize $new_size_to_disk_in_mb || ( echo ERRO: resizing disk fail... && exit )
# if this step fail execute this command and execute this script again
# vboxmanage internalcommands sethduuid $hdd_file

read -p "press any key to show HDD info"
vboxmanage list hdds | grep -B 4 -A 3 "$name"

read -p "press any key to: attach HDD to storage"
vboxmanage storageattach "$name" --storagectl "SATA" --port 0 --device 0 --type hdd --medium $hdd_file
vboxmanage showvminfo "$name" | egrep 'SATA|IDE'

read -p "press any key to: attach DVD gparted ISO to storage"
vboxmanage storageattach "$name" --storagectl "IDE" --port 0 --device 0 --type dvddrive --medium $iso_dir_path/$iso_filename
vboxmanage showvminfo "$name" | egrep 'SATA|IDE'

read -p "press any key to start VM... you need resize disk using gparted ISO"
vboxmanage startvm "$name" --type headless
echo you need resize disk using gparted through RDP access... VM will boot using gparted ISO
echo -e "\nuse a RDP client like remmina to connect on VM port: $( vboxmanage showvminfo "$name" | awk '/VRDE:.*enabled/ {print $6}' | sed 's/.$//' )\n"

read -p "press any key after resize and poweroff VM"
vboxmanage list runningvms | grep "$name" && vboxmanage controlvm "$name" poweroff soft && read -p "safely shutdown VM it not stopped... press any key to continue"

read -p "press any key to: dettach DVD ISO to storage"
vboxmanage storageattach "$name" --storagectl "IDE" --port 0 --device 0 --type dvddrive --medium none
vboxmanage showvminfo "$name" | egrep 'SATA|IDE'

read -p "press any key to start VM"
vboxmanage startvm "$name" --type headless

if this error appear execute this command:

VBoxManage: error: Cannot register the hard disk ‘/path/to/file.vdi’ {2569f01f-d4f9-4495-ad52-c5a06a18be2c} because a hard disk ‘/path/to/file.vdi’ with UUID {2569f01f-d4f9-4495-ad52-c5a06a18be2c} already exists

vboxmanage internalcommands sethduuid /path/to/file.vdi

convert virtualbox vmdk disk to vdi formart

1 – clone the disk to vdi format

vboxmanage clonehd "disk_file.vmdk" "new_disk_file.vdi" --format vdi

2 – attach the new vdi disk to the machine

vboxmanage storageattach "VmName" --storagectl "SATA" --port 0 --device 0 --type hdd --medium "new_disk_file.vdi"

script to conversion

name=centos                               # vm name
hdd_file=/path/to/disk/$name-disk001.vdi  # full path to vm disk

file_name_without_extension=$( vboxmanage list hdds | grep "$name.*.v" | awk '{ print $2 }' | awk -F. '{ print $1 }' )
file_name_extension=$( vboxmanage list hdds | grep "$name.*.v" | awk '{ print $2 }' | awk -F. '{ print $2 }' )

# check if disk has vmdk extension
if [[ $file_name_extension == vmdk ]]; then

  read -p "press any key to: show HDD info after convert vmdk disk to vdi format"
  vboxmanage list hdds | grep -B 4 -A 3 "$name"

  read -p "press any key to convert vmdk disk to vdi format"
  vboxmanage clonehd "$file_name_without_extension.vmdk" "$hdd_file" --format vdi
  vboxmanage storageattach "$name" --storagectl "SATA" --port 0 --device 0 --type hdd --medium "$hdd_file"

  read -p "press any key to: show HDD info before convert vmdk disk to vdi format"
  vboxmanage list hdds | grep -B 4 -A 3 "$hdd_file"

  read -p 'do you want to delete old vmdk disk and your info? y/n ' y_n && test "$y_n" == "y" -o "$y_n" == "Y" || exit
  vboxmanage list hdds | grep -B 4 -A 3 "$file_name_without_extension.vmdk"

  read -p 'press y key to confirm deletetion of vmdk disk and your info: y/n ' y_n && test "$y_n" == "y" -o "$y_n" == "Y" && echo deleting disk... && rm -f $file_name_without_extension.vmdk || exit
  vboxmanage closemedium disk $( vboxmanage list hdds | grep -B 4 -A 3 $file_name_without_extension.vmdk | grep ^UUID | cut -d: -f2 | xargs ) --delete
fi

manage storage of a virtualbox vm

list attached storage of all VMs

vboxmanage list vms --long | egrep 'SATA|IDE'

list attached storage of running VMs

vboxmanage list runningvms --long | egrep 'SATA|IDE'

show HDD info of a single VM

vboxmanage list hdds | grep -B 4 -A 3 "VmName"

list attached storage of a single VM (device number will appear)

vboxmanage showvminfo "VmName" | egrep 'SATA|IDE'

set or change an ISO image as a IDE storage

vboxmanage storageattach "VmName" --storagectl "IDE" --port 0 --device 0 --type dvddrive --medium /path/to/file.iso

dettach an ISO image from storage

vboxmanage storageattach "VmName" --storagectl "IDE" --port 0 --device 0 --type dvddrive --medium none

list boot order of a VM

vboxmanage showvminfo "VmName" | grep -i -A 4 'boot menu'

enable remote display/rdp in a virtualbox vm

install virtualbox extension pack on VirtualBox Host

1 – check if virtualbox extension pack is installed

vboxmanage list extpacks

2 – get version of virtualbox running

vboxmanage --version

3 – get virtualbox extension pack with same version of virtualbox running if it isn’t installed. https://www.virtualbox.org/wiki/Download_Old_Builds

curl -O https://download.virtualbox.org/virtualbox/6.0.14/Oracle_VM_VirtualBox_Extension_Pack-6.0.14.vbox-extpack

4 – install virtualbox extension pack if it isn’t installed

vboxmanage extpack install Oracle_VM_VirtualBox_Extension_Pack-6.0.14.vbox-extpack

enable Remote Display/RDP in the Virtual Machine

5 – check if RDP is enable in a VM

vboxmanage showvminfo "VmName" | grep VRDE

6 – stop VM if RDP is not enable or if you need change RDP port on VM

vboxmanage controlvm "VmName" poweroff soft

7 – enable remote display/rdp in a VM on port 7777

vboxmanage modifyvm "VmName" --vrdeport 7777 --vrde on

8 – start VM

vboxmanage startvm "VmName" --type headless

9 – check if a process is running on RDP port on VirtualBox Host

netstat -nlp | grep 7777

10 – connect on remote machine using RDP client*

xfreerdp /cert-ignore /u:root /v:192.168.0.7 /port:7777

*if xfreerdp command doesn’t work use remmina RDP client

check ssl certification info

check expiry date of a single ssl certificate

openssl x509 -enddate -subject -noout -in cert.pem

check expiry date of multiple ssl certificates

find -name cert.pem -exec openssl x509 -enddate -subject -noout -in {} \;

get creation and expiry from a ssl certificate

openssl x509 -startdate -enddate -subject -noout -in cert.pem

get all information from a ssl certificate

openssl x509 -text -noout -in cert.pem

test a ssl certificate

openssl s_client -connect www.paypal.com:443
openssl s_client paypal.com:443 2> /dev/null | openssl x509 -noout -dates

check all options about a ssl certificate

man x509

drop email or domains in postfix

1 – create an alias

echo 'devnull: /dev/null' >> /etc/aliases

2 – force postfix to reload changes in /etc/aliases

newaliases

3 – create a regex rule to postfix forward emails to /dev/null

cat >> /etc/postfix/virtual.regexp <<EOF

# delete emails from *sales@gmail.com
/^.*sales@gmail.com/ devnull

4 – test the given email against the rules one file

postmap -q 'john-sales@gmail.com' regexp:/etc/postfix/virtual.regexp

5 – update .db file after edit it (isn’t necessary postfix restart)

postmap /etc/postfix/virtual.regexp

install saltstack minion on qnap nas ts-873

1 – logged as admin user set sudo permission to all users in administrators group

sed -i '/^# %wheel ALL=(ALL) NOPASSWD/a %administrators ALL=(ALL) NOPASSWD: ALL' /usr/etc/sudoers

2 – download package salt-minion inside of QNAP box

wget https://www.qnapclub.eu/en/qpkg/model/download/470819/Saltstack_3001_x86_64.qpkg

3 – install the package manually

sudo qpkg_cli -m Saltstack_3001_x86_64.qpkg --keep

4 – set salt-minion configuration

sudo bash -c "cat > /share/CACHEDEV1_DATA/.qpkg/Saltstack/etc/salt/minion <<EOF
master: 192.168.10.10
id: backup.domain.com
root_dir: /share/CACHEDEV1_DATA/.qpkg/Saltstack
EOF"

don’t start salt-minion manually
it will generate a key and the boot script will generate other key

5 – set salt-minion to start automatically on boot

sudo mount $(getcfg system "system device")6 /tmp/config

sudo bash -c "cat > /tmp/config/autorun.sh <<'EOF'
#!/bin/bash
# This script will run on boot startup
# It was enable on QNAP TS-873 Web App:
# Control Painel => System => Hardware => [x] Run user defined processes during startup (View autorun.sh)

# set sudo permission to all users in administrators group
sed -i '/^# %wheel ALL=(ALL) NOPASSWD/a %administrators ALL=(ALL) NOPASSWD: ALL' /usr/etc/sudoers

# create symbolic link to /opt/Saltstack if it doesn't exist
test ! -e /opt/Saltstack && ln -sf /share/CACHEDEV1_DATA/.qpkg/Saltstack /opt/Saltstack

# execute salt-minion specifying configuration path dir and generate a debug log
/share/CACHEDEV1_DATA/.qpkg/Saltstack/bin/salt-minion -c /share/CACHEDEV1_DATA/.qpkg/Saltstack/etc/salt &> /tmp/salt-minion_debug &
chmod 666 /tmp/salt-minion_debug
EOF"

sudo chmod +x /tmp/config/autorun.sh

6 – Enable QNAP TS-873 to execute autorun.sh script on boot

Control Painel => System => Hardware => [x] Run user defined processes during startup (View autorun.sh)

7 – reboot for salt-minion run automatically on boot

sudo reboot

8 – login into salt master server and accept the minion key

salt-key -A -y

9 – test communication between master«=»minion

netstat -nlap | grep 192.168.10.10:450[56]

execute command with test condition in salt

execute a command if test is true

append a new line to file if it exist

"echo 'newline' >> /tmp/file.txt":
  cmd.run:
    - onlyif: test -e /tmp/file.txt

execute a command if test is false

create a new file if it not exist using onlyif:

"date > /tmp/date.txt":
  cmd.run:
    - onlyif: test ! -e /tmp/date.txt

create a new file if it not exist using unless:

"date > /tmp/date.txt":
  cmd.run:
    - unless: test -e /tmp/date.txt

Reference: https://docs.saltstack.com/en/latest/ref/states/all/salt.states.cmd.html

store/retrieve base64 file in saltstack

1 – create the pillar top file

cat >> /srv/pillar/top.sls <<EOF
base:
  'host1':
    - host1-pillar
EOF

2 – create the pillar file to host1

cat >> /srv/pillar/host1-pillar.sls <<EOF
txt_file: !!binary

jpg_image: !!binary
EOF

3 – encode the files to base64 and put your content on host1.sls file

base64 /etc/passwd | sed 's/^/      /' | sed -i '/^txt/ r /dev/stdin' /srv/pillar/host1-pillar.sls

base64 /usr/share/pixmaps/debian-logo.png | sed 's/^/      /' | sed -i '/^jpg/ r /dev/stdin' /srv/pillar/host1-pillar.sls

4 – list pillar items of host1

salt 'host1' pillar.items

5 – create the state top file

cat >> /srv/salt/top.sls <<EOF
base:
  'host1':
    - host1-state
EOF

6 – create the state file to host1

cat >> /srv/salt/host1-state.sls <<EOF
/tmp/passwd:
  file.managed:
     - contents_pillar: txt_file

/tmp/debian.jpg:
  file.managed:
     - contents_pillar: jpg_image
EOF

7 – test what will be changed before execute state

salt 'host1' state.apply test=true

8 – execute the state of host1 (files will go to /tmp dir)

salt 'host1' state.apply

References:
https://docs.saltstack.com/en/latest/topics/pillar

https://docs.saltstack.com/en/getstarted/config/pillar.html

ssh jump host

to jump a single host

ssh -J user@200.221.50.3:222 user@192.168.0.7

to jump multiple hosts

ssh -J usr@200.11.54.3:222,usr@10.0.1.8 usr@192.168.1.7

to configure jump host in the ssh config file

cat >> ~/.ssh/config <<EOF
PubKeyAuthentication yes
IdentityFile /path/to/your/private/key/id_rsa
 
Host publicIP-server
  HostName 200.221.50.3
  Port 222
  User mickey
 
Host internal-server
  HostName 192.168.0.7
  User donald
  ProxyJump publicIP-server
EOF

to connect on internal-server using ssh config file information

ssh internal-server

to connect in a invalid IP address using jump host from ssh config file

ssh -o ProxyCommand="ssh -W %h:%p -q publicIP-server" usr@10.1.1.3

to copy a file by rsync from a invalid IP using jump host

rsync -rv -e 'ssh -A -J publicIP-server' usr@10.1.1.3:file /tmp

install saltstack agentless

1 – install salt-ssh*

wget -O - https://repo.saltstack.com/py3/debian/10/amd64/latest/SALTSTACK-GPG-KEY.pub | apt-key add -

echo 'deb http://repo.saltstack.com/py3/debian/10/amd64/latest buster main' > /etc/apt/sources.list.d/saltstack.list

apt update && apt install -y salt-ssh && mkdir -p /srv/salt

2 – append host configuration in roster config file

cat >> /etc/salt/roster <<EOF
srv07:
  host: 192.168.0.7
  user: root
  passwd: 123456
EOF
common roster file options**:
port: 22
set_path: /bin:/sbin:/usr/bin:/usr/sbin
user: root
passwd: 123456
priv: /path/to/id_rsa

3 – try to execute a command on remote host. -i “ignore-host-keys”

salt-ssh -i '*' test.ping

4 – install python3 on remote host if the command above fails. -r “execute raw command”

salt-ssh -i -r srv07 'yum -y install python3'

5 – try to execute other command on remote host

salt-ssh 'srv07' network.ip_addrs

*official installation list to all linux distros: https://repo.saltstack.com

**more roster file options: https://docs.saltstack.com/en/latest/topics/ssh/roster.html

to improve speed of ssh connections

keep all ssh connections active for 5 minutes

cat >> ~/.ssh/config <<EOF
ControlMaster auto
ControlPath ~/.ssh/control:%h:%p:%r
ControlPersist 300s
EOF

usage of modules and functions in saltstack

list modules and state modules

salt '*' sys.list_modules
salt '*' sys.list_state_modules

list functions and state functions

salt '*' sys.list_functions
salt '*' sys.list_state_functions

list all functions from a module

salt '*' sys.list_functions grains
salt '*' sys.list_functions user
salt '*' sys.list_state_functions pkg

show all documentation from a module

salt '*' sys.doc grains
salt '*' sys.doc user

show specific documentation of a function in a module

salt '*' sys.doc grains.item
salt '*' sys.doc user.add

execute a function in a module

salt '*' grains.items
salt '*' user.list_users

execute a function in a module passing params

salt '*' grains.item ipv4 cpu_model
salt '*' user.info root
salt '*' cmd.run "ls /tmp"

execute multiple modules passing params (module1,module2 param1,param2)

salt '*' grains.item,sys.list_modules ipv4 ip4_gw,pkg*

run a command locally on the master or minion

salt-call --local test.ping

all state modules: https://docs.saltstack.com/en/latest/ref/states/all/index.html#all-salt-states

all modules: https://docs.saltstack.com/en/latest/py-modindex.html

install and configure saltstack

to execute on SERVER SIDE – Debian 10 (192.168.0.1)

1.1 – install salt-master*

wget -O - https://repo.saltstack.com/py3/debian/10/amd64/latest/SALTSTACK-GPG-KEY.pub | apt-key add -

echo 'deb http://repo.saltstack.com/py3/debian/10/amd64/latest buster main' > /etc/apt/sources.list.d/saltstack.list

apt update && apt install -y salt-master && mkdir -p /srv/salt

1.2 – allow salt-minion to connect in the salt-master ports

iptables -A INPUT -s 192.168.0.7 -p tcp --dport 4505:4506 -m comment --comment "allow salt-minion" -j ACCEPT

1.3 – restart salt-master and check state your state

systemctl restart salt-master; systemctl status salt-master

1.4 – check if salt-master ports are listen

netstat -nlap | egrep ':450[5|6]'

to execute on CLIENT SIDE – CentOS 8 (192.168.0.7)

2.1 – install salt-minion*

yum install https://repo.saltstack.com/py3/redhat/salt-py3-repo-latest.el8.noarch.rpm

yum install -y salt-minion

2.2 – set salt-master IP on minion file

sed -i '/^#master:/a master: 192.168.0.1' /etc/salt/minion

2.3 – set minion ID on minion file and minion_id file

sed -i '/^#id:/a id: srv07' /etc/salt/minion

echo 'srv07' > /etc/salt/minion_id

2.4 – restart salt-minion and check state your state

systemctl restart salt-minion; systemctl status salt-minion

to execute on SERVER SIDE – Debian 10 (192.168.0.1)

1.5 – accept all keys from minions

salt-key -A -y

1.6 – list established connections between minionsmaster

netstat -nlap | grep 4505.*ESTABLISHED

1.7 – get IP from all minions

salt '*' network.ip_addrs

1.8 – get IP and cpu model from a single minion

salt 'srv07' grains.item ipv4 cpu_model

1.9 – get all grains info from a single minion

salt srv07 grains.items

*official installation list to all linux distros: https://repo.saltstack.com

docker report

extract container info in table format

docker ps --format "table {{.Names}}\t{{.State}}\t{{.Status}}\t{{.Size}}\t{{.Networks}}\t{{.Ports}}"

extract hostname and IP from running container

docker ps --format '{{.Names}}' | xargs -i  docker inspect -f '{{.Name}} {{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' {}

manage iptables with ansible

1 – create ansible playbook

cat > firewall-playbook.yml <<'EOF'
---
- hosts: firewall_cloud01
  become: true
  become_user: root

  tasks:
          # ------- filter rules -------

    - name: change default chain policy (used to clean rules)
      iptables:
        chain: INPUT
        policy: ACCEPT

    - name: clean rules on all chains of filter table
      iptables:
        table: filter
        flush: yes

    - name: delete all user-defined chains on filter table
      shell: iptables -t filter -X

    - name: Allow packages to loopback interface
      iptables:
        in_interface: lo
        chain: INPUT
        jump: ACCEPT
        comment: loopback

    - name: Allow established state
      iptables:
        chain: INPUT
        ctstate: ESTABLISHED
        jump: ACCEPT

    - name: Allow ssh connection
      iptables:
        chain: INPUT
        src_range: 192.168.0.1-192.168.0.170
        protocol: tcp
        destination_port: '22'
        jump: ACCEPT
        comment: ssh

    - name: Allow http connection
      iptables:
        chain: INPUT
        source: 192.168.1.0/24
        protocol: tcp
        destination_port: '80'
        jump: ACCEPT
        comment: http

    - name: Allow ftp connection
      iptables:
        chain: INPUT
        protocol: tcp
        source_port: "{{ item }}"
        jump: ACCEPT
        comment: ftp
      with_items: [ '20', '21' ]

    - name: set default chain policy
      iptables:
        chain: INPUT
        policy: DROP

               # ------- nat rules -------

    - name: clean rules on all chains of nat table
      iptables:
        table: nat
        flush: yes

    - name: delete all user-defined chains on nat table
      shell: iptables -t nat -X

    - name: masquerade connection
      shell: iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
EOF

2 – run ansible playbook

ansible-playbook firewall-playbook.yml

iptables module doc: https://docs.ansible.com/ansible/latest/modules/iptables_module.html

install docker on remote host using ansible

STEPS ON REMOTE HOST (WHERE DOCKER WILL BE INTALLED)

1 – do the login by ssh on the remote host

ssh -o StrictHostKeyChecking=no user@192.168.0.7

2 – create an user on remote host to be used by ansible having sudo as additional group

useradd -g users -G sudo user01 -s /bin/bash

echo -e "123456\n123456" | passwd user01

3 – set sudo users to execute commands without password

sed -i '/^%sudo.*ALL:ALL/s/^/#/; //a %sudo   ALL=(ALL) NOPASSWD: ALL' /etc/sudoers

STEPS ON ANSIBLE HOST

1 – Install ansible

apt install -y software-properties-common
apt-add-repository -y --update ppa:ansible/ansible
apt install -y ansible

2 – try to connect to localhost and verify a usable python on it*

ansible localhost, --connection=local -m ping

3 – configure remote host in the ansible hosts file

cat >> /etc/ansible/hosts <<'EOF'
srv01 ansible_host=192.168.0.7 ansible_user=user01 ansible_password=123456
EOF

4 – set config params in /etc/ansible/ansible.cfg file

sed -i '/gathering .*=/a gathering = explicit' /etc/ansible/ansible.cfg
sed -i '/host_key_checking .*=/a host_key_checking = false' /etc/ansible/ansible.cfg
sed -i '/ssh_args.*=/a ssh_args = -C -o ControlMaster=auto -o ControlPersist=300s' /etc/ansible/ansible.cfg
sed -i '/control_path .*=$/a control_path = /tmp/ansible-%%h-%%r' /etc/ansible/ansible.cfg
sed -i '/pipelining .*=/a pipelining = True' /etc/ansible/ansible.cfg
sed -i '/executable .*=/a executable = /bin/bash' /etc/ansible/ansible.cfg

5 – try to connect to remote host and verify a usable python on it

ansible srv01 -m ping

– use the command bellow to install python on remote machine if it not installed

ansible srv01 -b -m raw -a 'apt install -y python3'
ansible options used: -b will execute command as root
-m module name to execute -a arguments passed to module

6 – install docker and others packages on remote host***

cat > srv01-playbook.yml <<'EOF'
---
- hosts: srv01
  become: true
  become_user: root

  tasks:
    - name: install docker and other packages
      apt:
        name:
        - docker.io
        - curl
        state: latest
        update_cache: true
EOF

7 – run ansible-playbook command****

ansible-playbook srv01-playbook.yml

8 – Test if docker was installed*****

ansible srv01 -b -m shell -a 'docker -v'

Optionally you can add a new task to playbook file to get docker version

cat >> srv01-playbook.yml <<'EOF' && ansible-playbook srv01-playbook.yml

    - name: show docker version
      shell: docker -v | cut -d, -f1
      register: result
    - debug:
        msg: "{{ result.stdout }}"
EOF

Documentation of commands or modules used in this post

* ping module: https://docs.ansible.com/ansible/latest/modules/ping_module.html

** ansible.cfg: https://docs.ansible.com/ansible/2.4/intro_configuration.html

*** apt module: https://docs.ansible.com/ansible/latest/modules/apt_module.html

**** ansible-playbook: https://docs.ansible.com/ansible/latest/user_guide/playbooks.html

***** shell module: https://docs.ansible.com/ansible/latest/modules/shell_module.html

put stdin into file

edit file putting pipe content/stdin after line starting with mail string

echo abc | sed '/^mail/ r /dev/stdin' /etc/passwd

edit file putting stdin after line 5

echo abc | sed '5 r /dev/stdin' /etc/passwd

edit a file putting content of first one file inside other after line 5

cat /etc/hostname | sed '7 r /dev/stdin' /etc/passwd

*use -i option on sed to save content to file

comment multiple lines on vim

1 – Put the cursor on the first line that will be commented

2 – Press Crtl + v to vim enter enter in VISUAL BLOCK mode

3 – Move the cursor to down until the line that will be commented or Press j key

4 – Press Shift + i to vim enter in INSERT mode, it will go to the first line

5 – Type # and Press Esc

jump x lines after match

replace next line after line match

sed '/^3/{ n; s/.*/x/ }' <(seq 7)

replace second line after line match

sed '/^3/{ n; n; s/.*/x/ }' <(seq 7)

append/insert a new line after match

sed '/^3/a new_line' <(seq 7)

jump 1 line after match and append a new line

sed '/^3/!{ p; d }; n; a new_line' <(seq 7)

jump 2 lines after match and insert a new line

sed '/^3/!{ p; d }; n; n; a new_line' <(seq 7)

add menu on tint2 taskbar

1 – add the repository that contains jgmenu package for debian 9 stretch

cat >> /etc/apt/sources.list <<EOF
deb http://pkg.bunsenlabs.org/debian stretch-backports main
EOF

2 – install the key of added repository

curl -L https://ddl.bunsenlabs.org/ddl/BunsenLabs-RELEASE.asc | apt-key add -

3 – install jgmenu

apt update && apt install jgmenu

4 – create a .desktop file. * change Icon value

cat > ~/.local/share/applications/jgmenu.desktop <<EOF
[Desktop Entry]
Name=jgmenu
Exec=jgmenu_run &> /dev/null
Type=Application
Icon=/path/to/svg/icon/file.svg
Categories=System
EOF

5 – add launcher entry to jgmenu on tint2rc file

cat >> ~/.config/tint2/tint2rc <<EOF
# Launcher
launcher_icon_size = 22
startup_notifications = 0
launcher_item_app = jgmenu.desktop
EOF

meansure wifi signal strength/power

using /proc file

awk 'END { print int($3*10/7)"%" }' /proc/net/wireless

using iw command

specifying wifi interface

iw wlp2s0 station dump | awk '$1 ~ "signal:" { print int(int($2+100)*1.9) >= 100 ? "100%" : int(int($2+100)*1.9)"%" }'

getting wifi interface automatically

iw $( ip route | awk '/^default.*dev/ { for (x=1; x<NF; x++) if ( $x ~ "dev" ) print $(x+1) }' ) station dump | awk '$1 ~ "signal:" { print int(int($2+100)*1.9) >= 100 ? "100%" : int(int($2+100)*1.9)"%" }'

create/append file using heredoc

use here document to create a file using cat

create a file maintaining interpolation

cat > file1 <<EOF
$HOME
abc
$(hostname)
EOF

suppress interpolation creating a file

cat > file2 <<'EOF'
$HOME
abc
$(hostname)
EOF

append content to a file

cat >> file2 <<FIN
new content
FIN

if the file was created with success execute a command printing a message

cat <<FIN> file3 && echo file created
def
FIN

execute command after append content to a file

cat <<EOF>> file3; wc -l file3
ghi
EOF

create a formatted file inside an if statement(use of TAB is mandatory)

if true; then
        cat > file4 <<-EOF
srv07:
  host: 192.168.0.7
  user: root
        EOF
fi

* if you copy this block of code, delete heredoc lines begin and use TAB

control remotely keyboard and mouse over ssh

1 – install x2x package on the remote machine

apt install x2x

2 – connect from source machine to remote machine and control X display

ssh -X user@192.168.0.7 x2x -north -to :0

* move mouse cursor to up/down borders of screen to alternate between machines

connect on remote machine and change keyboard layout

1 – configure ssh on the client machine to reuse an already established connection

cat >> ~/.ssh/config <<EOF
ControlMaster auto
ControlPath ~/.ssh/control:%h:%p:%r
EOF

2 – connect on the remote machine and execute a command on X11 session to change keyboard layout

sshpass -p "passwdHere" ssh -o StrictHostKeyChecking=no -X user@192.168.0.7 x2x -north -north -to :0 &
sleep 1
ssh -o StrictHostKeyChecking=no -X user@192.168.0.7 DISPLAY=:0 'setxkbmap pt'
reset
echo 'connection ready!'

find maximum/minimum value in a column

awk

get line with maximum value in column 2 using awk

echo -e 'a 3\nb 5\na 7\nb 9' | awk '{print $2, $1}' | sort -k2 -k1nr | awk '$2 != x { print } { x = $2 }'

get line with minimum value in column 2 using awk

echo -e 'a 3\nb 5\na 7\nb 9' | awk '{print $2, $1}' | sort -k2 -k1n | awk '$2 != x { print } { x = $2 }'

datamash

get line with maximum value in column 2 using datamash

echo -e 'a 3\nb 5\na 7\nb 9' | datamash -s -W -g 1 max 2

get line with minimum value in column 2 using datamash

echo -e 'a 3\nb 5\na 7\nb 9' | datamash -s -W -g 1 min 2

most used docker commands

statistics and info commands

show container usage statistics

docker stats

show running process from a container

docker top pc

show the logs from a container

docker logs -f pc

show container log path

docker inspect --format='{{.Name}} {{.LogPath}}' pc

show docker disk usage

docker system df

show all IPs from a container

docker inspect --format='{{.Name}} {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' pc

show mac address from a container

docker inspect --format='{{.Name}} {{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}' pc

show all ports binding from a container

docker inspect --format='{{.Name}} {{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' pc

images commands

search for images on docker hub

docker search debian
docker search -f is-official=true debian

list images

docker images

remove a image

docker rmi debian

container commands

list all container and their status

docker ps -a

create a docker container (it will download the image if it doesn’t exist)

docker create -i --name pc debian

start a container

docker start pc

enter in a container

docker exec -it pc bash

stop a container

docker stop pc
docker stop -t0 pc

remove a single container ( -f will force remotion if it running )

docker rm pc
docker rm -f pc

remove all stopped containers

docker container prune

command options

docker
docker create --help
docker start --help
docker exec --help

terraform with docker

1 – Download terraform cli binary and put it on /usr/local/bin

2 – create the main.tf file

cat > ~/main.tf <<'EOF'
# configure docker provider
provider "docker" {
  version = "~> 2.7"
  host = "tcp://127.0.0.1:2375"
}

# create a image
resource "docker_image" "alpine" {
  name = "alpine"
}

# create a container (it will run for 1 day)
resource "docker_container" "foo" {
  image    = "alpine"
  name     = "foo"
  command = ["sleep", "1d"]

  hostname = "foo"

  volumes {
    host_path = "/path/to/virtual_disk"
    container_path = "/mnt"
    read_only = false
  }
}
EOF

3 – create a working directory “.terraform” and get the docker provider binary

terraform init

4 – show the execution plan (optional)

terraform plan

5 – create or change the infrastructure

terraform apply

6 – see the state of docker container

docker ps -a

7 – execute commands in the container

docker exec foo ip -4 addr
docker exec foo sh -c 'ip -4 addr; hostname'

8 – enter in the container

docker exec -it foo sh

Links:
https://www.terraform.io/docs/providers/docker/index.html
https://www.terraform.io/docs/providers/docker/r/container.html

docker install and dockerd config

1 – install docker

apt install docker.io

2 – modify runtime directory and storage driver

mkdir /etc/docker; cat > /etc/docker/daemon.json <<'EOF'
{
        "data-root": "/mnt",
        "storage-driver": "vfs"
}
EOF

3 – put docker to listen on tcp port changing systemd file

sed '/^ExecStart.*/s/$/ -H tcp:\/\/0.0.0.0:2375/' /lib/systemd/system/docker.service > /etc/systemd/system/docker.service

4 – restart dockerd

systemctl daemon-reload; systemctl restart docker

Links:
https://docs.docker.com/engine/reference/commandline/dockerd
https://docs.docker.com/config/daemon
https://docs.docker.com/config/daemon/systemd
https://docs.docker.com/engine/install/linux-postinstall

create a custom debian live iso

COMMANDS ON HOST SYSTEM

1 – download debian live iso image

2 – install squashfs-tools genisoimage

apt/yum install squashfs-tools genisoimage

3 – mount the iso image

mount -o loop debian-live-10.4.0-amd64-standard.iso /mnt

4 – copy squashfs file system from iso image to local dir

mkdir -p /debian-live-custom/workdir
cp -av /mnt/live/filesystem.squashfs /debian-live-custom
cd /debian-live-custom/workdir

5 – uncompress squashfs

unsquashfs ../filesystem.squashfs

6 – use chroot to set uncompresses squashfs as a current environment

chroot squashfs-root

COMMANDS ON SQUASHFS ENVIRONMENT

modifying the current environment it will be the new custom iso image

7 – set DNS server

echo 'nameserver 8.8.8.8' > /etc/resolv.conf

8 – enable non-free repository

sed -i '/^deb/s/$/ non-free/' /etc/apt/sources.list
apt update

9 – install packages

apt install firmware-iwlwifi net-tools gpm vim ssh gdebi telnet wpasupplicant xserver-xorg-video-vesa xserver-xorg-input-all slim openbox xterm tilda chromium --yes

10 – exit of squashfs environment and back to host system

exit

COMMANDS ON HOST SYSTEM

11 – create a new squashfs file system

mksquashfs squashfs-root/ filesystem.squashfs -comp xz

12 – copy files from original iso image to directory of new iso image

mkdir debian-live-iso-custom
cp -av /mnt/* debian-live-iso-custom
cp -av /mnt/.disk debian-live-iso-custom
cd debian-live-iso-custom

13 – copy custom squashfs to directory of new iso image

unalias cp
cp ../filesystem.squashfs live/filesystem.squashfs

14 – create a new iso

mkisofs -o /tmp/debian-10.4-live-custom.iso -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -J -R -V 'Debian 10.4 Live Custom' .

modify/edit an ISO image

1 – Mount the ISO image

mount -o loop /path/to/file.iso /mnt/

2 – Create new a directory to copy the content of ISO image

mkdir /tmp/content_iso

3 – Copy from mounted iso to the new created directory

rsync -av /mnt/* /tmp/content_iso

4 – Create a new file and turn it executable

echo -e '#!/bin/bash\n echo hello world' > /tmp/content_iso/new_file.sh
chmod +x /tmp/content_iso/new_file.sh

5 – Creating a new ISO file at: /tmp/new.iso

mkisofs -allow-limited-size -udf -o /new.iso -relaxed-filenames -J -R -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -eltorito-alt-boot -eltorito-platform -b boot/grub/efi.img  -no-emul-boot /tmp/content_iso

6 – Remove files and umount the ISO mount point

rm -rf /tmp/content_iso; umount /mnt

7 – Testing… After boot with this new ISO image run

/cdrom/new_file.sh

shortcut keys on x11

create .xbindkeysrc at home user

cat >> ~/.xbindkeysrc <'EOF'
"init 6"
Control + Alt + Delete  # reboot

"gmrun"
Alt + F2        # exec command

"xterm"
Mod4 + t        # Win key + t open xterm
EOF

reload xbindkeys

pkill xbindkeys; xbindkeys

show current configuratiom

xbindkeys --show

execute xbindkeys automaticaly on X11 start

echo 'xbindkeys' >> ~/.bashrc

get keyboard keycodes

xbindkeys -mk

to debug erros don’t start xbindkeys as daemon

pkill xbindkeys; xbindkeys -n

generate an ISO file of your installed linux

It works on Debian based distros

1 – Download Pinguy Builder: https://sourceforge.net/projects/pinguy-os/files/ISO_Builder/pinguybuilder_5.2-1_all.deb

2 – Install Pinguy Builder

apt install pinguybuilder_5.2-1_all.deb

3 – Install other packages used by PinguyBuilder
apt install ubiquity ubiquity-casper ubiquity-frontend-gtk ubiquity-ubuntu-artwork

4 – Run PinguyBuilder-gtk command and configure it to generate a Backup ISO

PinguyBuilder-gtk

5 – Go to Settings tab and change these fields:

Filename => backup_linux.iso

Files to exclude => /cdrom /rofs /media /dev /isodevice

Working directoy => /path/to/target/output/dir/on/hdd_or_usb_drive

6 – Go to Actions tab and click in Backup button

The output file will be generated at: /path/to/target/output/dir/on/hdd_or_usb_drive/PinguyBuilder/backup_linux.iso

Internet connection info can be removed after Installing the Ubiquity GTK frontend step

** Burn ISO file on USB flash drive with mkusb command to make it persistent
OR
*** Add a GRUB entry to boot an ISO direct from HDD

execute script before poweroff/reboot

1 – Create a script and enable the executable flag on it

cat > /usr/local/bin/poweroff_script.sh <<EOF
#!/bin/bash
touch /test     # create a test file
EOF

chmod +x /usr/local/bin/poweroff_script.sh

2 – Create unit file to run script with systemd at shutdown/reboot

cat > /etc/systemd/system/poweroff_script.service <<EOF
[Unit]
Description=Run my custom task at poweroff
DefaultDependencies=no
Before=poweroff.target halt.target shutdown.target
Requires=poweroff.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/poweroff_script.sh
RemainAfterExit=yes

[Install]
WantedBy=shutdown.target
EOF

3 – Refresh the systemd configuration files

systemctl daemon-reload

4 – Enable the script

systemctl enable poweroff_script.service

boot ISO image directly from HD

steps for UEFI BIOS

1 – Add an entry on end on /etc/grub.d/40_custom file

cat >> /etc/grub.d/40_custom <<'EOF'
menuentry "Peppermint Custom ISO MKUSB+PinguyBuilder" {
  set isofile="/path/to/iso/peppermint_linux_customized_with_pinguy_builder.iso"
  loopback loop (hd0,gpt2)$isofile
  linuxefi (loop)/casper/vmlinuz from=${isofile} boot=casper iso-scan/filename=${isofile} quiet splash hostname=pc
  initrdefi (loop)/casper/initrd.gz
}

menuentry "Bodhi Linux Custom ISO MKUSB+PinguyBuilder" {
  set isofile="/path/to/iso/bodhi-5.1.0-64-hwe_custom_mkusb+pinguyBuilder.iso"
  loopback loop (hd0,gpt2)$isofile
  linuxefi (loop)/casper/vmlinuz from=${isofile} boot=casper iso-scan/filename=${isofile} quiet splash hostname=pc
  initrdefi (loop)/casper/initrd.gz
}

menuentry "Debian 10.4 Live ISO" {
  set isofile="/home/nickollas/Downloads/ISO/debian-live-10.4.0-amd64-xfce.iso"
  loopback loop (hd0,gpt2)$isofile
  linuxefi (loop)/live/vmlinuz-4.19.0-9-amd64 boot=live findiso=${isofile} components
  initrdefi (loop)/live/initrd.img-4.19.0-9-amd64
}

menuentry "Kali Linux 2020.1b ISO" {
  set isofile="/path/to/iso/kali-linux-2020.1b-live-amd64.iso"
  loopback loop (hd0,gpt2)$isofile
  linuxefi (loop)/live/vmlinuz-5.4.0-kali2-amd64 findiso=${isofile} boot=live components splash hostname=pc
  initrdefi (loop)/live/initrd.img-5.4.0-kali2-amd64
} 

menuentry "Manjaro Linux 20" {
  set isofile="/path/to/iso/manjaro-xfce-20.0.1-minimal-200511-linux56.iso"
  loopback loop (hd0,gpt2)$isofile
  linuxefi (loop)/boot/vmlinuz-x86_64 img_dev=/dev/disk/by-uuid/${rootuuid} img_loop=${isofile}
  initrdefi (loop)/boot/intel_ucode.img (loop)/boot/amd_ucode.img (loop)/boot/initramfs-x86_64.img
}
EOF

2 – Update GRUB2 for UEFI BIOS

grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg

steps for non-UEFI BIOS

1 – Add an entry on end on /etc/grub.d/40_custom file

cat >> /etc/grub.d/40_custom <<'EOF'
menuentry "Debian 9.2 Install ISO" {
  set isofile="/path/to/iso/debian-9.2.1-amd64-netinst.iso"
  loopback loop (hd0,3)$isofile
  linux (loop)/install.amd/vmlinuz from=${isofile} iso-scan/filename=${isofile} quiet splash hostname=pc
  initrd (loop)/install.amd/initrd.gz
}

menuentry "Porteus ISO" {
  set isofile="/path/to/iso/Porteus-XFCE-v3.1-x86_64.iso"
  loopback loop (hd0,3)$isofile
  linux (loop)/boot/syslinux/vmlinuz from=${isofile} quiet splash hostname=pc
  initrd (loop)/boot/syslinux/initrd.xz
}
EOF

2 – Update GRUB2 for non-UEFI BIOS

update-grub2

Get other configs to grub in the GRUB Live ISO Multiboot page: https://glee.thias.es/GLIM

execute a system command with awk

create a new column with value of command output

awk '{ "date +%F" |& getline $4; print }' <<<'a b c'

creating a file

awk '"touch test_file" |& getline' <<<''

alternating monitor resolution

awk '/*/ { if ( $1 == "1368x768" ) { "xrandr --output eDP1 --mode 1920x1080" |& getline } else { "xrandr --output eDP1 --mode 1368x768" |& getline } }' <(xrandr)

execute command on X11 startup

using X11 startup file – it work with any window manager

  • Create a .desktop file in ~/.config/autostart directory
  • Execute a single command with a parameter when X11 start

    cat > ~/.config/autostart/start_script.desktop <<EOF
    [Desktop Entry]
    Name=start_script
    Type=Application
    Exec=setxkbmap pt
    EOF
    

    Execute multiple commands when X11 start

    cat > ~/.config/autostart/start_script.desktop <<EOF
    [Desktop Entry]
    Name=start_script
    Type=Application
    Exec=sh -c "setxkbmap pt; xterm &"
    EOF
    

    using Openbox startup file – work only with openbox

    All lines in ~/.config/openbox/autostart file will be executed on openbox startup

    echo 'tilda' >> ~/.config/openbox/autostart
    

    create a usb linux live with persistent partition

    It works on Debian based systems

    1 – install the package that contains apt-add-repository command

    apt install software-properties-common
    

    2 – Add in apt the PPA repository of mkusb package

    apt-add-repository ppa:mkusb/ppa
    

    3 – update apt repository list

    apt update
    

    4 – install mkusb and additional packages

    apt install mkusb mkusb-nox usb-pack-efi
    

    5 – run mkusb as a regular user

    mkusb
    

    6 – Follow these steps bellow

    press d => dus, guidus, mkusb-dus -Classic, easy to use
    
    press i => Install (make a boot device)
    
    press p => 'Persistent live - only Debian and Ubuntu'
    
    choose a ISO linux install image
    
    select => upefi usb-pack-efi (default grub from ISO file)
    
    define a percentage of space to the persistent partition
    
    select go => Yes, I want to go ahead
    

    configure notify-send on openbox

    using gdbus command

    it will get icons from /usr/share/icons

    gdbus call --session --dest org.freedesktop.Notifications --object-path /org/freedesktop/Notifications --method org.freedesktop.Notifications.Notify "appName" "7" "system-logo-icon" "text 1" "text 2" "[]" "{}" 5000
    

    using notify-send command

    1 – install packages Debian/CentOS

    apt/yum install xfce4-notifyd
    

    2.1 – show text get icon from /usr/share/icons

    notify-send text1 'text 2' -i system-logo-icon
    

    2.2 – show text specifying icon path

    notify-send abc 'de f' -i /usr/share/pixmaps/openbox.png
    

    2.3 – show text and command output

    notify-send -i system-logo-icon 'boot time' $( systemd-analyze | awk 'NR == 1 {print $NF}' )
    

    – list current configuration

    xfconf-query -c xfce4-notifyd -l -v
    

    – changing some property “expire timeout

    xfconf-query -c xfce4-notifyd -p /expire-timeout -s 7
    

    – graphical configuration

    xfce4-notifyd-config
    

    creating config file manually

    cat > ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-notifyd.xml <<EOF
    <?xml version="1.0" encoding="UTF-8"?>
     
    <channel name="xfce4-notifyd" version="1.0">
      <property name="applications" type="empty">
        <property name="known_applications" type="array">
          <value type="string" value="appName"/>
          <value type="string" value="nm-applet"/>
          <value type="string" value="xfce4-power-manager"/>
          <value type="string" value="xfce4-settings-helper"/>
        </property>
      </property>
      <property name="primary-monitor" type="uint" value="0"/>
      <property name="notify-location" type="uint" value="0"/>
      <property name="log-level" type="uint" value="0"/>
      <property name="log-level-apps" type="uint" value="0"/>
    </channel>
    EOF
    

    configure notify-send at crontab

    0 7 * * * XDG_RUNTIME_DIR=/run/user/$(id -u) notify-send -i pstree32 "$(date +\%R)"
    

    mount remote file system over ssh

    on the client machine install the sshfs package

    apt install sshfs
    

    mount the remote folder “/tmp” on “/mnt” in local machine

    sshfs -o allow_other userHere@192.168.0.1:/tmp /mnt
    

    mount the remote folder in the local machine using private ssh key

    sshfs -o IdentityFile=~/.ssh/id_rsa -o allow_other userHere@192.168.0.1:/tmp /mnt
    

    mounting remote point automatically on boot using /etc/fstab file

    echo 'sshfs#userHehe@192.168.0.1:/tmp /mnt fuse port=2222,IdentityFile=/home/userHere/.ssh/id_rsa,x-systemd.after=network-online.target,allow_other,nonempty 0 2' >> /etc/fstab
    

    manage virtualbox remotely

    steps on VirtualBox Host

    1 – set virtualbox web-service config

    cat >> /etc/default/virtualbox <<EOF 
    VBOXWEB_USER=insertUserHere
    VBOXWEB_PASSWD=insertPasswdHere
    VBOXWEB_HOST=0.0.0.0
    VBOXWEB_TIMEOUT=0
    EOF
    

    2 – restart vboxweb-service

    systemctl restart vboxweb-service
    

    3 – check if vboxweb-service is listen

    netstat -nlp | grep 18083
    

    4 – show virtualbox version

    vboxmanage --version
    

    steps on Desktop

    5 – get remotebox according your virtualbox version in this link: https://remotebox.knobgoblin.org.uk/?page=downloads

    wget https://remotebox.knobgoblin.org.uk/downloads/RemoteBox-2.7.tar.bz2 -P /tmp
    

    6 – unconpress remotebox

    tar -xjvf /tmp/RemoteBox-2.7.tar.bz2 -C /tmp
    

    7 – install dependencies to remotebox

    apt install -y libsoap-lite-perl freerdp-x11
    

    8 – execute remotebox

    cd /tmp/RemoteBox-2.7 && ./remotebox
    

    delete history commands

    See commands history with line number

    cat -n ~/.bash_history
    

    Delete a single history entry number 77

    sed -i '77d' ~/.bash_history
    

    Delete a range of history entry from 12 to 25

    sed -i '12,25d' ~/.bash_history
    

    Delete a range of history entry from 90 until last line

    sed -i '90,$d' ~/.bash_history
    

    replace column by system command in awk

    replace column 2 by external command hostname

    awk '{ "hostname" |& getline $2; print }' <<<'a b c'
    

    replace column 2 by external command date

    awk -F, 'BEGIN{OFS=","} { "date \"+%Y-%m-%d %H:%M:%S\"" |& getline $2 }1'<<<a,b,c
    

    replace column 2 by external sub awk command

    awk '{ "route -n | awk \"/^0/ { print \\$2 }\"" |& getline $2; print }' <<<'a b c'
    

    ssh local port forwarding

    forward remote port 80(httpd) to local port 8080

    ssh -L 8080:localhost:80 user@200.225.2.4
    

    forward remote port 3306(mysql) to local port 7777

    ssh -L 7777:localhost:3306 user@200.225.2.4
    

    forward remote port 80(httpd) to local port 8080 run it in background

    ssh -fNT -L 8080:localhost:80 user@200.225.2.4
    

    to check if process is running in background

    netstat -nlp | less
    

    get all open port of an entire network

    nmap -sS 192.168.1.1-255 | egrep -o '[[:digit:].]{3,}$|^[[:digit:]]*/[[:alpha:]]*' | awk 'BEGIN{ m=0 } { if ( $1 ~ /^[[:digit:].]{3,}$/ ) m++; print m, $0 }' | awk '{ a[$1] = a[$1] FS substr( $0, index( $0,$2 ) ) } END{ for( i in a ) print i a[i] }' | awk 'OFS="," {$1=$1; print substr( $0, index($0,$2) ) }' | sort -V