Best way to test if a systemd service is running in bash script

systemctl is-active application.service
systemctl is-enabled application.service
systemctl is-active --quiet service

will exit with status zero if service is active, non-zero otherwise, making it ideal for scripts:

systemctl is-active --quiet service && echo Service is running

References
https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
https://unix.stackexchange.com/questions/396630/the-proper-way-to-test-if-a-service-is-running-in-a-script

Check if a File or Directory Exists in Bash

Check if File Exist

FILE=/etc/resolv.conf
if test -f "$FILE"; then
    echo "$FILE exist"
fi
FILE=/etc/resolv.conf
if [ -f "$FILE" ]; then
    echo "$FILE exist"
fi
FILE=/etc/resolv.conf
if [[ -f "$FILE" ]]; then
    echo "$FILE exist"
fi

Check if Directory Exist

FILE=/etc/docker
if [ -d "$FILE" ]; then
    echo "$FILE is a directory"
fi

Check if File does Not Exist

FILE=/etc/docker
if [ ! -f "$FILE" ]; then
    echo "$FILE does not exist"
fi

Check if Multiple Files Exist

FILE=/etc/docker
if [ -f /etc/resolv.conf -a -f /etc/hosts ]; then
    echo "$FILE is a directory"
fi
FILE=/etc/docker
if [ -f /etc/resolv.conf && -f /etc/hosts ]; then
    echo "$FILE is a directory"
fi

File test operators

  • -f FILE – True if the FILE exists and is a regular file (not a directory or device).
  • -G FILE – True if the FILE exists and has the same group as the user running the command.
  • -h FILE – True if the FILE exists and is a symbolic link.
  • -g FILE – True if the FILE exists and has set-group-id (sgid) flag set.
  • -k FILE – True if the FILE exists and has a sticky bit flag set.
  • -L FILE – True if the FILE exists and is a symbolic link.
  • -O FILE – True if the FILE exists and is owned by the user running the command.
  • -p FILE – True if the FILE exists and is a pipe.
  • -r FILE – True if the FILE exists and is readable.
  • -S FILE – True if the FILE exists and is socket.
  • -s FILE – True if the FILE exists and has nonzero size.
  • -u FILE – True if the exists and set-user-id (suid) flag is set.
  • -w FILE – True if the FILE exists and is writable.
  • -x FILE – True if the FILE exists and is executable.

References
https://linuxize.com/post/bash-check-if-file-exists/

Using environment variables in systemd units

Environment directive

Environment="ONE=one" 'TWO=two two'
ExecStart=/bin/echo $ONE $TWO ${TWO}

EnvironmentFile directive

EnvironmentFile similar to Environment directive but reads the environment variables from a text file. The text file should contain new-line-separated variable assignments.This environment file can then be sourced and its variables used
Example file : /run/metadata/coreos

COREOS_DIGITALOCEAN_IPV4_ANCHOR_0=X.X.X.X
COREOS_DIGITALOCEAN_IPV4_PRIVATE_0=X.X.X.X
COREOS_DIGITALOCEAN_HOSTNAME=test.example.com
COREOS_DIGITALOCEAN_IPV4_PUBLIC_0=X.X.X.X
COREOS_DIGITALOCEAN_IPV6_PUBLIC_0=X:X:X:X:X:X:X:X
[Unit]
Requires=coreos-metadata.service
After=coreos-metadata.service

[Service]
EnvironmentFile=/run/metadata/coreos
ExecStart=
ExecStart=/usr/bin/etcd2 \
  --advertise-client-urls=http://${COREOS_DIGITALOCEAN_IPV4_PUBLIC_0}:2379 \
  --initial-advertise-peer-urls=http://${COREOS_DIGITALOCEAN_IPV4_PRIVATE_0}:2380 \
  --listen-client-urls=http://0.0.0.0:2379 \
  --listen-peer-urls=http://${COREOS_DIGITALOCEAN_IPV4_PRIVATE_0}:2380 \
  --initial-cluster=%m=http://${COREOS_DIGITALOCEAN_IPV4_PRIVATE_0}:2380

References
https://stackoverflow.com/questions/37864999/referencing-other-environment-variables-in-systemd
https://coreos.com/os/docs/latest/using-environment-variables-in-systemd-units.html

Configure Multiple Users for Shadowsocks-libev

For example, Cloud and Tifa, two AVALANCHE members, are planning to deploy shadowsocks-libev services on the same VPS to bypass the firewall of Shinra Inc. In this case, they could simply create cloud.json and tifa.json configurations with different ports, passwords and encryption methods in /etc/shadowsocks-libev directory. Then enable and start the systemd services using the following commands:

sudo systemctl enable shadowsocks-libev-server@cloud.service --now
sudo systemctl enable shadowsocks-libev-server@tifa.service --now

The status of shadowsocks-libev instances could be checked with the following commands:

sudo systemctl status shadowsocks-libev-server@cloud.service
sudo systemctl status shadowsocks-libev-server@tifa.service

You can start shadowsocks-libev instances with the following commands:

sudo systemctl start shadowsocks-libev-server@cloud.service
sudo systemctl start shadowsocks-libev-server@tifa.service

References
https://blog.zzhou612.com/2019/02/15/configure-multiple-users-for-shadowsocks-libev/

Apache reverse proxy configuration for socket.io

sudo a2enmod proxy_http
sudo a2enmod proxy_fcgi
sudo a2enmod proxy_wstunnel
# VirtualHost ms.example.net
<VirtualHost *:80>
  ServerName ms.example.net
  ProxyRequests Off
  ProxyPreserveHost On
  RemoteIPHeader X-Forwarded-For
  <Proxy *>
    Order deny,allow
    Allow from all
  </Proxy>
  RewriteEngine On
  RewriteCond %{REQUEST_URI} ^/socket.io          [NC]
  RewriteCond %{QUERY_STRING} transport=websocket [NC]
  RewriteRule /(.*) ws://localhost:14102/$1        [P,L]

  ProxyPass /socket.io http://localhost:14102/socket.io
  ProxyPassReverse /socket.io http://localhost:14102/socket.io
</VirtualHost>

<VirtualHost *:443>
  ServerName ms.example.net
  ProxyRequests Off
  ProxyPreserveHost On
  RemoteIPHeader X-Forwarded-For
  RewriteEngine on
  <Proxy *>
    Order deny,allow
    Allow from all
  </Proxy>
  SSLEngine On
  SSLCertificateFile /etc/letsencrypt/live/example.net/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/example.net/privkey.pem
  
  RewriteEngine On
  RewriteCond %{REQUEST_URI} ^/socket.io          [NC]
  RewriteCond %{QUERY_STRING} transport=websocket [NC]
  RewriteRule /(.*) ws://localhost:14102/$1        [P,L]
  ProxyPass /socket.io http://localhost:14102/socket.io
  ProxyPassReverse /socket.io http://localhost:14102/socket.io
  
</VirtualHost>

Use a secure URL for your initial connection, i.e. instead of “http://” use “https://”. If the WebSocket transport is chosen, then Socket.IO should automatically use “wss://” (SSL) for the WebSocket connection too.

var socket = io.connect('https://localhost', {secure: true});

References
http://xpo6.com/socket-io-via-apache-reverse-proxy/
https://stackoverflow.com/questions/36472920/apache-proxy-configuration-for-socket-io-project-not-in-root
https://gist.github.com/iacchus/954e0787d6893c5ab8e1
https://stackoverflow.com/questions/6599470/node-js-socket-io-with-ssl