diff --git a/debian/Containerfile b/debian/Containerfile
index 9748cc7..758e9a8 100644
--- a/debian/Containerfile
+++ b/debian/Containerfile
@@ -34,3 +34,9 @@ COPY assets/bash.bashrc /etc/bash.bashrc
# copy custom scripts
COPY assets/bin/ /usr/local/bin/
+
+# Install templating engine
+RUN wget https://raw.githubusercontent.com/jirutka/esh/master/esh && \
+ chmod +x esh && \
+ mv esh /usr/local/bin/ && \
+ mkdir /etc/templates
\ No newline at end of file
diff --git a/gitea/assets/bin/esh b/gitea/assets/bin/esh
deleted file mode 100755
index 71698a3..0000000
--- a/gitea/assets/bin/esh
+++ /dev/null
@@ -1,366 +0,0 @@
-#!/bin/sh
-# vim: set ts=4:
-#---help---
-# USAGE:
-# esh [options] [--] [...]
-# esh <-h | -V>
-#
-# Process and evaluate an ESH template.
-#
-# ARGUMENTS:
-# Path of the template file or "-" to read from STDIN.
-# Variable(s) specified as = to pass into the
-# template (the have higher priority than environment
-# variables).
-#
-# OPTIONS:
-# -d Don't evaluate template, just dump a shell script.
-# -o Output file or "-" for STDOUT. Defaults to "-".
-# -s Command name or path of the shell to use for template
-# evaluation. It must not contain spaces.
-# Defaults to "/bin/sh".
-# -h Show this help message and exit.
-# -V Print version and exit.
-#
-# ENVIRONMENT:
-# ESH_AWK Command name of path of the awk program to use.
-# It must not contain spaces. Defaults to "awk".
-# ESH_MAX_DEPTH Maximum include depth. Defaults to 3.
-# ESH_SHELL Same as -s.
-#
-# EXIT STATUS:
-# 0 Clean exit, no error has encountered.
-# 1 Generic error.
-# 10 Invalid usage.
-# 11 ESH syntax error.
-# 12 Include error: file not found.
-# 13 Include error: exceeded max include depth (ESH_MAX_DEPTH).
-#
-# Please report bugs at .
-#---help---
-set -eu
-
-readonly PROGNAME='esh'
-readonly VERSION='0.3.0'
-readonly SCRIPTPATH="$0"
-
-AWK_CONVERTER=$(cat <<'AWK'
-function fail(code, msg) {
- state = "ERROR"
- # FIXME: /dev/stderr is not portable
- printf("%s: %s\n", line_info(), msg) > "/dev/stderr"
- exit code
-}
-function line_info() {
- return FILENAME ? (filenames[depth] ":" linenos[depth]) : "(init)" # (init) if inside BEGIN
-}
-# IMPORTANT: This is the only function that should print a newline.
-function puts(str) {
- print(line_info()) > MAP_FILE
- print(str)
-}
-function fputs(str) {
- printf("%s", str)
-}
-function trim(str) {
- gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", str)
- return str
-}
-function read(len, _str) {
- if (len == "") {
- _str = buff
- buff = ""
- } else if (len > 0) {
- _str = substr(buff, 1, len)
- buff = substr(buff, len + 1, length(buff))
- }
- return _str
-}
-function skip(len) {
- buff = substr(buff, len + 1, length(buff))
-}
-function flush(len, _str) {
- _str = read(len)
-
- if (state == "TEXT") {
- gsub("'", "'\\''", _str)
- }
- if (state != "COMMENT") {
- fputs(_str)
- }
-}
-function file_exists(filename, _junk) {
- if ((getline _junk < filename) >= 0) {
- close(filename)
- return 1
- }
- return 0
-}
-function dirname(path) {
- return sub(/\/[^\/]+\/*$/, "/", path) ? path : ""
-}
-function include(filename) {
- if (index(filename, "/") != 1) { # if does not start with "/"
- filename = dirname(filenames[depth]) filename
- }
- if (!file_exists(filename)) {
- fail(12, "cannot include " filename ": not a file or not readable")
- }
- if (depth > MAX_DEPTH) {
- fail(13, "cannot include " filename ": exceeded maximum depth of " MAX_DEPTH)
- }
- buffs[depth] = buff
- states[depth] = state
- filenames[depth + 1] = filename
- depth++
-
- init()
- while ((getline buff < filename) > 0) {
- if (print_nl && state != "COMMENT") {
- puts("")
- }
- process_line()
- }
- end_text()
- close(filename)
-
- depth--
- buff = buffs[depth]
- state = states[depth]
-}
-function init() {
- buff = ""
- linenos[depth] = 0
- print_nl = 0
- start_text()
-}
-function start_text() {
- puts("")
- fputs("printf '%s' '")
- state = "TEXT"
-}
-function end_text() {
- if (state != "TEXT") { return }
- puts("' #< " line_info())
- state = "UNDEF"
-}
-function process_line() {
- linenos[depth]++
-
- while (buff != "") {
- print_nl = 1
-
- if (state == "TEXT" && match(buff, /<%/)) {
- flush(RSTART - 1) # print buff before "<%"
- skip(2) # skip "<%"
-
- flag = substr(buff, 1, 1)
- if (flag != "%") {
- end_text()
- }
- if (flag == "%") { # <%%
- skip(1)
- fputs("<%")
- } else if (flag == "=") { # <%=
- skip(1)
- fputs("__print ")
- state = "TAG"
- } else if (flag == "+") { # <%+
- if (!match(buff, /[^%]%>/)) {
- fail(11, "syntax error: <%+ must be closed on the same line")
- }
- filename = trim(substr(buff, 2, match(buff, /.-?%>/) - 1))
- skip(RSTART)
- include(filename)
- state = "TAG"
- } else if (flag == "#") { # <%#
- state = "COMMENT"
- } else {
- state = "TAG"
- }
- } else if (state != "TEXT" && match(buff, /%>/)) {
- flag = RSTART > 1 ? substr(buff, RSTART - 1, 1) : ""
-
- if (flag == "%") { # %%>
- flush(RSTART - 2)
- skip(1)
- flush(2)
- } else if (flag == "-") { # -%>
- flush(RSTART - 2)
- skip(3)
- print_nl = 0
- } else { # %>
- flush(RSTART - 1)
- skip(2)
- }
- if (flag != "%") {
- start_text()
- }
- } else {
- flush()
- }
- }
-}
-BEGIN {
- FS = ""
- depth = 0
-
- puts("#!" (SHELL ~ /\// ? SHELL : "/usr/bin/env " SHELL))
- puts("set -eu")
- puts("if ( set -o pipefail 2>/dev/null ); then set -o pipefail; fi")
- puts("__print() { printf '%s' \"$*\"; }")
-
- split(VARS, _lines, /\n/)
- for (_i in _lines) {
- puts(_lines[_i])
- }
- init()
-}
-{
- if (NR == 1) {
- filenames[0] = FILENAME # this var is not defined in BEGIN so we must do it here
- }
- buff = $0
- process_line()
-
- if (print_nl && state != "COMMENT") {
- puts("")
- }
-}
-END {
- end_text()
-}
-AWK
-)
-AWK_ERR_FILTER=$(cat <<'AWK'
-function line_info(lno, _line, _i) {
- while ((getline _line < MAPFILE) > 0 && _i++ < lno) { }
- close(MAPFILE)
- return _line
-}
-{
- if (match($0, "^" SRCFILE ":( line)? ?[0-9]+:") && match(substr($0, 1, RLENGTH), /[0-9]+:$/)) {
- lno = substr($0, RSTART, RLENGTH - 1) + 0
- msg = substr($0, RSTART + RLENGTH + 1) # v-- some shells duplicate filename
- msg = index(msg, SRCFILE ":") == 1 ? substr(msg, length(SRCFILE) + 3) : msg
- print(line_info(lno) ": " msg)
- } else if ($0 != "") {
- print($0)
- }
-}
-AWK
-)
-readonly AWK_CONVERTER AWK_ERR_FILTER
-
-print_help() {
- sed -En '/^#---help---/,/^#---help---/p' "$SCRIPTPATH" | sed -E 's/^# ?//; 1d;$d;'
-}
-
-filter_shell_stderr() {
- $ESH_AWK \
- -v SRCFILE="$1" \
- -v MAPFILE="$2" \
- -- "$AWK_ERR_FILTER"
-}
-
-evaluate() {
- local srcfile="$1"
- local mapfile="$2"
-
- # This FD redirection magic is for swapping stdout/stderr back and forth.
- exec 3>&1
- { set +e; $ESH_SHELL "$srcfile" 2>&1 1>&3; echo $? >>"$mapfile"; } \
- | filter_shell_stderr "$srcfile" "$mapfile" >&2
- exec 3>&-
-
- return $(tail -n 1 "$mapfile")
-}
-
-convert() {
- local input="$1"
- local vars="$2"
- local map_file="${3:-"/dev/null"}"
-
- $ESH_AWK \
- -v MAX_DEPTH="$ESH_MAX_DEPTH" \
- -v SHELL="$ESH_SHELL" \
- -v MAP_FILE="$map_file" \
- -v VARS="$vars" \
- -- "$AWK_CONVERTER" "$input"
-}
-
-process() {
- local input="$1"
- local vars="$2"
- local evaluate="${3:-yes}"
- local ret=0 tmpfile mapfile
-
- if [ "$evaluate" = yes ]; then
- tmpfile=$(mktemp)
- mapfile=$(mktemp)
-
- convert "$input" "$vars" "$mapfile" > "$tmpfile" || ret=$?
- test $ret -ne 0 || evaluate "$tmpfile" "$mapfile" || ret=$?
-
- rm -f "$tmpfile" "$mapfile"
- else
- convert "$input" "$vars" || ret=$?
- fi
- return $ret
-}
-
-: ${ESH_AWK:="awk"}
-: ${ESH_MAX_DEPTH:=3}
-: ${ESH_SHELL:="/bin/sh"}
-EVALUATE='yes'
-OUTPUT=''
-
-while getopts ':dho:s:V' OPT; do
- case "$OPT" in
- d) EVALUATE=no;;
- h) print_help; exit 0;;
- o) OUTPUT="$OPTARG";;
- s) ESH_SHELL="$OPTARG";;
- V) echo "$PROGNAME $VERSION"; exit 0;;
- '?') echo "$PROGNAME: unknown option: -$OPTARG" >&2; exit 10;;
- esac
-done
-shift $(( OPTIND - 1 ))
-
-if [ $# -eq 0 ]; then
- printf "$PROGNAME: %s\n\n" 'missing argument ' >&2
- print_help >&2
- exit 10
-fi
-
-INPUT="$1"; shift
-[ "$INPUT" != '-' ] || INPUT=''
-if [ "$INPUT" ] && ! [ -f "$INPUT" -a -r "$INPUT" ]; then
- echo "$PROGNAME: can't read $INPUT: not a file or not readable" >&2; exit 10
-fi
-
-# Validate arguments.
-for arg in "$@"; do
- case "$arg" in
- *=*) ;;
- *) echo "$PROGNAME: illegal argument: $arg" >&2; exit 10;;
- esac
-done
-
-# Format variables into shell variable assignments.
-vars=''; for item in "$@"; do
- vars="$vars\n${item%%=*}='$(
- printf %s "${item#*=}" | $ESH_AWK "{ gsub(/'/, \"'\\\\\\\''\"); print }"
- )'"
-done
-
-export ESH="$0"
-
-if [ "${OUTPUT#-}" ]; then
- tmpfile="$(mktemp)"
- trap "rm -f '$tmpfile'" EXIT HUP INT TERM
- process "$INPUT" "$vars" "$EVALUATE" > "$tmpfile"
- mv "$tmpfile" "$OUTPUT"
-else
- process "$INPUT" "$vars" "$EVALUATE"
-fi