diff --git a/.ansible-lint b/.ansible-lint
new file mode 100644
index 0000000000000000000000000000000000000000..9c9323e8df825eddaf10a9188e0fd26583c5dde0
--- /dev/null
+++ b/.ansible-lint
@@ -0,0 +1,89 @@
+---
+# based on documentation available at
+# https://ansible-lint.readthedocs.io/en/latest/configuring/
+
+# exclude_paths included in this file are parsed relative to this file's location
+# and not relative to the CWD of execution. CLI arguments passed to the --exclude
+# option will be parsed relative to the CWD of execution.
+exclude_paths:
+  - .cache/ # implicit unless exclude_paths is defined in config
+  - .git/
+  - .githooks/
+  - backups/
+# parseable: true
+# quiet: true
+# verbosity: 1
+
+# Mock modules or roles in order to pass ansible-playbook --syntax-check
+#mock_modules:
+#  - zuul_return
+#  # note the foo.bar is invalid as being neither a module or a collection
+#  - fake_namespace.fake_collection.fake_module
+#  - fake_namespace.fake_collection.fake_module.fake_submodule
+#mock_roles:
+#  - mocked_role
+#  - author.role_name # old standalone galaxy role
+#  - fake_namespace.fake_collection.fake_role # role within a collection
+
+# Enable checking of loop variable prefixes in roles
+loop_var_prefix: "{role}_"
+
+# Enforce variable names to follow pattern below, in addition to Ansible own
+# requirements, like avoiding python identifiers. To disable add `var-naming`
+# to skip_list.
+var_naming_pattern: "^[a-z_][a-z0-9_]*$"
+
+use_default_rules: true
+# Load custom rules from this specific folder
+# rulesdir:
+#   - ./rule/directory/
+
+# This makes linter to fully ignore rules/tags listed below
+skip_list:
+  - skip_this_tag
+  - git-latest
+
+# Any rule that has the 'opt-in' tag will not be loaded unless its 'id' is
+# mentioned in the enable_list:
+enable_list:
+  - empty-string-compare # opt-in
+  - no-log-password # opt-in
+  - no-same-owner # opt-in
+  # add yaml here if you want to avoid ignoring yaml checks when yamllint
+  # library is missing. Normally its absence just skips using that rule.
+  - yaml
+# Report only a subset of tags and fully ignore any others
+# tags:
+#   - var-spacing
+
+# This makes the linter display but not fail for rules/tags listed below:
+warn_list:
+  - skip_this_tag
+  - git-latest
+  - experimental # experimental is included in the implicit list
+  # - role-name
+
+# Offline mode disables installation of requirements.yml
+offline: false
+
+# Define required Ansible's variables to satisfy syntax check
+#extra_vars:
+#  foo: bar
+#  multiline_string_variable: |
+#    line1
+#    line2
+#  complex_variable: ":{;\t$()"
+
+# Uncomment to enforce action validation with tasks, usually is not
+# needed as Ansible syntax check also covers it.
+# skip_action_validation: false
+
+# List of additional kind:pattern to be added at the top of the default
+# match list, first match determines the file kind.
+kinds:
+  # - playbook: "**/examples/*.{yml,yaml}"
+  # - galaxy: "**/folder/galaxy.yml"
+  # - tasks: "**/tasks/*.yml"
+  # - vars: "**/vars/*.yml"
+  # - meta: "**/meta/main.yml"
+  - yaml: "**/*.yaml-too"
diff --git a/.githooks/pre-commit b/.githooks/pre-commit
index 39148cfc5bc90d6d22f6acbad18f26e6b26771bf..02df4d59f0a37ead68a96a3e70d7428dad7f4270 100755
--- a/.githooks/pre-commit
+++ b/.githooks/pre-commit
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 #
 # An example hook script to verify what is about to be committed.
 # Called by "git commit" with no arguments.  The hook should
@@ -24,12 +24,12 @@ exec 1>&2
 # Cross platform projects tend to avoid non-ASCII filenames; prevent
 # them from being added to the repository. We exploit the fact that the
 # printable range starts at the space character and ends with tilde.
-if [ "$allownonascii" != "true" ] &&
+if [ "${allownonascii}" != "true" ] &&
 	# Note that the use of brackets around a tr range is ok here, (it's
 	# even required, for portability to Solaris 10's /usr/bin/tr), since
 	# the square bracket bytes happen to fall in the designated range.
-	test $(git diff --cached --name-only --diff-filter=A -z $against |
-	  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
+	test "$( git diff --cached --name-only --diff-filter=A -z "${against}" |
+	  LC_ALL=C tr -d '[ -~]\0' | wc -c )" != 0
 then
 	cat <<\EOF
 Error: Attempt to add a non-ASCII file name.
@@ -69,12 +69,16 @@ YAML_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep ".yml$")
 if [[ ${YAML_FILES} != "" ]]; then
 	for file in ${YAML_FILES}; do
 		yamllint "${file}"
-		if [[ ${?} -ne 0 ]]; then
+		if ! yamllint "${file}"; then
 			exit 1
 		fi
 	done
 fi && echo "SUCCESS: Yamllint stage."
 
+### ANSIBLE-LINT stage
+ansible-lint "site.yml" || exit 1
+echo "SUCCESS: Ansible-lint stage."
+
 ### VAULT detection stage
 VAULT_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep ".vault$")
 if [[ ${VAULT_FILES} != "" ]]; then
@@ -88,14 +92,15 @@ fi
 if [[ ${STAGED_FILES} != "" ]]; then
 	for file in ${STAGED_FILES}; do
 		grep -e "\$ANSIBLE_VAULT;[[:digit:]]\.[[:digit:]];AES256" "${file}"
-		[[ ${?} -eq 0 ]] && echo "ERROR: Ansible-Vault in String found in file '${file}'." && exit 1
+		if grep -e "\$ANSIBLE_VAULT;[[:digit:]]\.[[:digit:]];AES256" "${file}"; then
+			echo "ERROR: Ansible-Vault in String found in file '${file}'." && exit 1
+		fi
 	done
 fi
 echo "SUCCESS: Vault detection stage."
 
 ### URL detection stage
-${GREP_CMD} ${GREP_EXCLUDES} -e "http[s]*.*git.*SLUB" -e "http[s]*.*git.*slub" -e "git@" "${REPOPATH}"
-if [[ ${?} -eq 0 ]]; then
+if "${GREP_CMD}" "${GREP_EXCLUDES}" -e "http[s]*.*git.*SLUB" -e "http[s]*.*git.*slub" -e "git@" "${REPOPATH}"; then
 	echo "ERROR: found internal URLs."
 	exit 1;
 fi
@@ -103,22 +108,29 @@ echo "SUCCESS: URL detection stage."
 
 ### IP address detection stage
 # This is pretty basic regex matching, but it's a start.
-IP_REGEX='[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
-${GREP_CMD} ${GREP_EXCLUDES} -e "${IP_REGEX}" "${REPOPATH}" | grep -v "127.0.0"
-if [[ ${?} -eq 0 ]]; then
+IP_REGEX='[^a-zA-ZäöÜÄÖÜß/\\\-][0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
+if "${GREP_CMD}" "${GREP_EXCLUDES}" -e "${IP_REGEX}" "${REPOPATH}" | grep -v "127.0.0"; then
 	echo "ERROR: found IP address."
 	exit 1;
 fi
 echo "SUCCESS: IP address detection stage."
 
 ### SSH-Key detection stage
-${GREP_CMD} ${GREP_EXCLUDES} -e "ssh-[dr]sa " "${REPOPATH}"
-if [[ ${?} -eq 0 ]]; then
+if "${GREP_CMD}" "${GREP_EXCLUDES}" -e "ssh-[dr]sa " "${REPOPATH}"; then
 	echo "ERROR: found SSH key."
 	exit 1;
 fi
 echo "SUCCESS: SSH Key detection stage."
 
+### SHELLSCRIPT CHECK stage
+SH_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep ".sh$")
+if [[ ${SH_FILES} != "" ]]; then
+	for file in ${SH_FILES}; do
+		shellcheck "${file}"
+	done
+fi
+echo "SUCCESS: SHELLSCRIPT CHECK stage."
+