commit 77ed02f107718d8fef064ced3c8232cf66e12829 Author: Phil Date: Tue Aug 13 20:18:11 2024 -0600 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8c9874c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.python-version +secrets.enc \ No newline at end of file diff --git a/bootstrap.yml b/bootstrap.yml new file mode 100644 index 0000000..c0b085e --- /dev/null +++ b/bootstrap.yml @@ -0,0 +1,13 @@ +--- +- hosts: bootstrap + become: true + vars: + created_username: phil + vars_prompt: + - name: tailscale_key + prompt: Enter the tailscale key + roles: + - bootstrap + - role: artis3n.tailscale + vars: + tailscale_authkey: "{{ tailscale_key }}" \ No newline at end of file diff --git a/hosts.yml b/hosts.yml new file mode 100644 index 0000000..24c4006 --- /dev/null +++ b/hosts.yml @@ -0,0 +1,10 @@ +bootstrap: + hosts: + netcup: + ansible_host: 152.53.36.98 + +docker: + hosts: + docker-01: + ansible_host: 100.70.169.99 + ansible_user: phil \ No newline at end of file diff --git a/requirements.yml b/requirements.yml new file mode 100644 index 0000000..cc7816d --- /dev/null +++ b/requirements.yml @@ -0,0 +1,3 @@ +--- +roles: + - name: artis3n.tailscale \ No newline at end of file diff --git a/roles/bootstrap/tasks/main.yml b/roles/bootstrap/tasks/main.yml new file mode 100644 index 0000000..9e24adc --- /dev/null +++ b/roles/bootstrap/tasks/main.yml @@ -0,0 +1,55 @@ +--- +- name: Install aptitude + apt: + name: aptitude + state: latest + update_cache: true + +- name: Setup passwordless sudo + lineinfile: + path: /etc/sudoers + state: present + regexp: '^%sudo' + line: '%sudo ALL=(ALL) NOPASSWD: ALL' + validate: '/usr/sbin/visudo -cf %s' + +- name: Create a new regular user with sudo privileges + user: + name: "{{ created_username }}" + state: present + groups: sudo + append: true + create_home: true + +- name: Set authorized key for remote user + ansible.posix.authorized_key: + user: "{{ created_username }}" + state: present + key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_ed25519.pub') }}" + +- name: Disable password authentication for root + lineinfile: + path: /etc/ssh/sshd_config + state: present + regexp: '^#?PermitRootLogin' + line: 'PermitRootLogin prohibit-password' + +- name: Update apt and install required system packages + apt: + pkg: + - curl + - vim + - git + - ufw + state: latest + update_cache: true + +- name: UFW - Allow SSH connections + community.general.ufw: + rule: allow + name: OpenSSH + +- name: UFW - Enable and deny by default + community.general.ufw: + state: enabled + default: deny diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml new file mode 100644 index 0000000..4f0448d --- /dev/null +++ b/roles/common/tasks/main.yml @@ -0,0 +1,10 @@ +- name: Install aptitude + apt: + name: aptitude + state: latest + update_cache: true + +- name: UFW - Enable and deny by default + community.general.ufw: + state: enabled + default: deny \ No newline at end of file diff --git a/roles/docker/files/Caddyfile b/roles/docker/files/Caddyfile new file mode 100644 index 0000000..3542a91 --- /dev/null +++ b/roles/docker/files/Caddyfile @@ -0,0 +1,7 @@ +auth.thesatelliteoflove.com { + reverse_proxy authentik-server-1:9000 +} + +git.thesatelliteoflove.com { + reverse_proxy gitea:3000 +} diff --git a/roles/docker/files/caddy-compose.yml b/roles/docker/files/caddy-compose.yml new file mode 100644 index 0000000..b494a56 --- /dev/null +++ b/roles/docker/files/caddy-compose.yml @@ -0,0 +1,22 @@ +services: + caddy: + image: caddy:2.8.4 + restart: unless-stopped + ports: + - "80:80" + - "443:443" + - "443:443/udp" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile + - ./site:/srv + - caddy_data:/data + - caddy_config:/config + +volumes: + caddy_data: + caddy_config: + +networks: + default: + external: true + name: lava \ No newline at end of file diff --git a/roles/docker/files/dockge-compose.yml b/roles/docker/files/dockge-compose.yml new file mode 100644 index 0000000..97a428d --- /dev/null +++ b/roles/docker/files/dockge-compose.yml @@ -0,0 +1,22 @@ +services: + dockge: + image: louislam/dockge:1 + restart: unless-stopped + ports: + # Host Port : Container Port + - 5001:5001 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./data:/app/data + + # If you want to use private registries, you need to share the auth file with Dockge: + # - /root/.docker/:/root/.docker + + # Stacks Directory + # ⚠️ READ IT CAREFULLY. If you did it wrong, your data could end up writing into a WRONG PATH. + # ⚠️ 1. FULL path only. No relative path (MUST) + # ⚠️ 2. Left Stacks Path === Right Stacks Path (MUST) + - /opt/stacks:/opt/stacks + environment: + # Tell Dockge where is your stacks directory + - DOCKGE_STACKS_DIR=/opt/stacks \ No newline at end of file diff --git a/roles/docker/files/gitea-compose.yml b/roles/docker/files/gitea-compose.yml new file mode 100644 index 0000000..fa80811 --- /dev/null +++ b/roles/docker/files/gitea-compose.yml @@ -0,0 +1,26 @@ +version: "3" +services: + server: + image: gitea/gitea:1.22.1 + container_name: gitea + environment: + - USER_UID=1000 + - USER_GID=1000 + restart: unless-stopped + volumes: + - gitea:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - 222:22 + extra_hosts: + - 'auth.thesatelliteoflove.com:172.20.0.6' + +volumes: + gitea: + driver: local + +networks: + default: + external: true + name: lava \ No newline at end of file diff --git a/roles/docker/files/ufw-docker.sh b/roles/docker/files/ufw-docker.sh new file mode 100644 index 0000000..6b92474 --- /dev/null +++ b/roles/docker/files/ufw-docker.sh @@ -0,0 +1,477 @@ +#!/bin/bash +set -euo pipefail +[[ -n "${DEBUG:-}" ]] && set -x + +LANG=en_US.UTF-8 +LANGUAGE=en_US: +LC_ALL=en_US.UTF-8 +PATH="/bin:/usr/bin:/sbin:/usr/sbin:/snap/bin/" + +GREP_REGEXP_INSTANCE_NAME="[-_.[:alnum:]]\\+" +DEFAULT_PROTO=tcp + +ufw_docker_agent=ufw-docker-agent +ufw_docker_agent_image="${UFW_DOCKER_AGENT_IMAGE:-chaifeng/${ufw_docker_agent}:221002-nf_tables}" + +if [[ "${ufw_docker_agent_image}" = *-@(legacy|nf_tables) ]]; then + if iptables --version | grep -F '(legacy)' &>/dev/null; then + ufw_docker_agent_image="${ufw_docker_agent_image%-*}-legacy" + else + ufw_docker_agent_image="${ufw_docker_agent_image%-*}-nf_tables" + fi +fi + +test -n "$ufw_docker_agent_image" + +function ufw-docker--status() { + ufw-docker--list "$GREP_REGEXP_INSTANCE_NAME" +} + +function ufw-docker--list() { + local INSTANCE_NAME="$1" + local INSTANCE_PORT="${2:-}" + local PROTO="${3:-${DEFAULT_PROTO}}" + local NETWORK="${4:-}" + + if [[ -z "$INSTANCE_PORT" ]]; then + INSTANCE_PORT="[[:digit:]]\\+" + PROTO="\\(tcp\\|udp\\)" + fi + + if [[ -z "$NETWORK" ]]; then + NETWORK="[[:graph:]]*" + fi + + ufw status numbered | grep "# allow ${INSTANCE_NAME}\\( ${INSTANCE_PORT}\\/${PROTO}\\)\\( ${NETWORK}\\)\$" || \ + ufw status numbered | grep "# allow ${INSTANCE_NAME}\\( ${INSTANCE_PORT}\\/${PROTO}\\)\$" || \ + ufw status numbered | grep "# allow ${INSTANCE_NAME}\$" +} + +function ufw-docker--list-number() { + ufw-docker--list "$@" | sed -e 's/^\[[[:blank:]]*\([[:digit:]]\+\)\].*/\1/' +} + +function ufw-docker--delete() { + for UFW_NUMBER in $(ufw-docker--list-number "$@" | sort -rn); do + echo "delete \"$UFW_NUMBER\"" + echo y | ufw delete "$UFW_NUMBER" || true + done +} + +function ufw-docker--allow() { + local INSTANCE_NAME="$1" + local INSTANCE_PORT="$2" + local PROTO="$3" + local NETWORK="${4:-}" + + docker inspect "$INSTANCE_NAME" &>/dev/null || + die "Docker instance \"$INSTANCE_NAME\" doesn't exist." + + mapfile -t INSTANCE_IP_ADDRESSES < <(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{"\n"}}{{end}}' "$INSTANCE_NAME" 2>/dev/null | remove_blank_lines) + + [[ -z "${INSTANCE_IP_ADDRESSES:-}" ]] && die "Could not find a running instance \"$INSTANCE_NAME\"." + + mapfile -t INSTANCE_NETWORK_NAMES < <(docker inspect --format='{{range $k, $v := .NetworkSettings.Networks}}{{printf "%s\n" $k}}{{end}}' "$INSTANCE_NAME" 2>/dev/null | remove_blank_lines) + mapfile -t PORT_PROTO_LIST < <(docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}}{{with $conf}}{{$p}}{{"\n"}}{{end}}{{end}}' "$INSTANCE_NAME" | remove_blank_lines) + + if [[ -z "${PORT_PROTO_LIST:-}" ]]; then + err "\"$INSTANCE_NAME\" doesn't have any published ports." + return 1 + fi + + RETVAL=1 + for PORT_PROTO in "${PORT_PROTO_LIST[@]}"; do + if [[ -z "$INSTANCE_PORT" || "$PORT_PROTO" = "${INSTANCE_PORT}/${PROTO}" ]]; then + ITER=0 + for IP in "${INSTANCE_IP_ADDRESSES[@]}"; do + INSTANCE_NETWORK="${INSTANCE_NETWORK_NAMES[$ITER]}" + ITER=$((ITER+1)) + if [[ -n "$NETWORK" ]] && [[ "$NETWORK" != "$INSTANCE_NETWORK" ]]; then + continue + fi + ufw-docker--add-rule "$INSTANCE_NAME" "$IP" "${PORT_PROTO%/*}" "${PORT_PROTO#*/}" "${INSTANCE_NETWORK}" + RETVAL="$?" + done + fi + done + if [[ "$RETVAL" -ne 0 ]]; then + err "Fail to add rule(s), cannot find the published port ${INSTANCE_PORT}/${PROTO} of instance \"${INSTANCE_NAME}\" or cannot update outdated rule(s)." + fi + return "$RETVAL" +} + +function ufw-docker--add-service-rule() { + declare service_id="$1" + declare port="${2%/*}" + declare proto="${2#*/}" + + declare target_ip_port + target_ip_port="$(iptables -t nat -L DOCKER-INGRESS | grep -E "^DNAT\\s+${proto}\\s+.+\\sto:[.0-9]+:${port}\$" | grep -Eo "[.0-9]+:${port}\$")" + + [[ -z "$target_ip_port" ]] && die "Could not find VIP of service ${service_id}." + + ufw-docker--add-rule "$service_id" "${target_ip_port%:*}" "$port" "$proto" +} + +function ufw-docker--add-rule() { + local INSTANCE_NAME="$1" + local INSTANCE_IP_ADDRESS="$2" + local PORT="$3" + local PROTO="$4" + local NETWORK="${5:-}" + + declare comment + + echo "allow ${INSTANCE_NAME} ${PORT}/${PROTO} ${NETWORK}" + typeset -a UFW_OPTS + UFW_OPTS=(route allow proto "${PROTO}" + from any to "$INSTANCE_IP_ADDRESS") + comment="allow ${INSTANCE_NAME}" + [[ -n "$PORT" ]] && { + UFW_OPTS+=(port "${PORT}") + comment="$comment ${PORT}/${PROTO}" + } + [[ -n "$NETWORK" ]] && { + comment="$comment ${NETWORK}" + } + UFW_OPTS+=(comment "$comment") + + if ufw-docker--list "$INSTANCE_NAME" "$PORT" "$PROTO" "$NETWORK" &>/dev/null; then + ufw --dry-run "${UFW_OPTS[@]}" | grep "^Skipping" && return 0 + err "Remove outdated rule." + ufw-docker--delete "$INSTANCE_NAME" "$PORT" "$PROTO" "$NETWORK" + fi + echo ufw "${UFW_OPTS[@]}" + ufw "${UFW_OPTS[@]}" +} + +function ufw-docker--instance-name() { + local INSTANCE_ID="$1" + { + { + docker inspect --format='{{.Name}}' "$INSTANCE_ID" 2>/dev/null | sed -e 's,^/,,' | + grep "^${GREP_REGEXP_INSTANCE_NAME}\$" 2>/dev/null + } || echo -n "$INSTANCE_ID"; + } | remove_blank_lines +} + +function ufw-docker--service() { + declare service_action="${1:-help}" + case "$service_action" in + delete) + shift || true + if [[ "${1:?Invalid 'delete' command syntax.}" != "allow" ]]; then + die "\"delete\" command only support removing allowed rules" + fi + shift || true + declare service_id_or_name="${1:?Missing swarm service name or service ID}" + + "ufw-docker--service-${service_action}" "${service_id_or_name}" + ;; + allow) + shift || true + declare service_id_or_name="${1:?Missing swarm service name or service ID}" + declare service_port="${2:?Missing the port number, such as '80/tcp'.}" + + "ufw-docker--service-${service_action}" "${service_id_or_name}" "${service_port}" + ;; + *) + ufw-docker--help + ;; + esac +} + +function ufw-docker--get-service-id() { + declare service_name="$1" + docker service inspect "${service_name}" --format "{{.ID}}" +} + +function ufw-docker--get-service-name() { + declare service_name="$1" + docker service inspect "${service_name}" --format "{{.Spec.Name}}" +} + +function ufw-docker--service-allow() { + declare service_name="$1" + declare service_port="$2" + declare service_proto=tcp + + if [[ -n "$service_port" ]] && + ! grep -E '^[0-9]+(/(tcp|udp))?$' <<< "$service_port" &>/dev/null; then + die "Invalid port syntax: $service_port" + return 1 + fi + + if [[ "$service_port" = */* ]]; then + service_proto="${service_port#*/}" + service_port="${service_port%/*}" + fi + + declare service_id + service_id="$(ufw-docker--get-service-id "${service_name}")" + [[ -z "${service_id:-}" ]] && die "Could not find service \"$service_name\"" + + service_name="$(ufw-docker--get-service-name "${service_name}")" + + exec 9< <(docker service inspect "$service_name" \ + --format '{{range .Endpoint.Spec.Ports}}{{.PublishedPort}} {{.TargetPort}}/{{.Protocol}}{{"\n"}}{{end}}') + while read -u 9 -r port target_port; do + if [[ "$target_port" = "${service_port}/${service_proto}" ]]; then + declare service_env="ufw_public_${service_id}=${service_name}/${port}/${service_proto}" + break; + fi + done + exec 9<&- + + [[ -z "${service_env:-}" ]] && die "Service $service_name does not publish port $service_port." + + if ! docker service inspect "$ufw_docker_agent" &>/dev/null; then + err "Not found ufw-docker-agent service, creating ..." + docker service create --name "$ufw_docker_agent" --mode global \ + --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ + --mount type=bind,source=/etc/ufw,target=/etc/ufw,readonly=true \ + --env ufw_docker_agent_image="${ufw_docker_agent_image}" \ + --env DEBUG="${DEBUG:-}" \ + --env "${service_env}" \ + "${ufw_docker_agent_image}" + else + declare -a service_env_list + service_env_list+=(--env-add "${service_env}") + + exec 8< <(ufw-docker--get-env-list) + while read -u 8 -r id value; do + [[ "$id" = "$service_id" ]] && continue + [[ "$value" = "${service_name}"/* ]] && service_env_list+=(--env-rm "ufw_public_${id}") + done + exec 8<&- + + docker service update --update-parallelism=0 \ + --env-add ufw_docker_agent_image="${ufw_docker_agent_image}" \ + --env-add DEBUG="${DEBUG:-}" \ + "${service_env_list[@]}" \ + --image "${ufw_docker_agent_image}" \ + "${ufw_docker_agent}" + fi +} + +function ufw-docker--get-env-list() { + docker service inspect "${ufw_docker_agent}" \ + --format '{{range $k,$v := .Spec.TaskTemplate.ContainerSpec.Env}}{{ $v }}{{"\n"}}{{end}}' | + sed -e '/^ufw_public_/!d' \ + -e 's/^ufw_public_//' \ + -e 's/=/ /' +} + +function ufw-docker--service-delete() { + declare service_name="$1" + + exec 8< <(ufw-docker--get-env-list) + while read -u 8 -r id value; do + if [[ "$id" = "$service_name" ]] || [[ "$value" = "${service_name}"/* ]]; then + declare service_id="$id" + service_name="${value%%/*}" + declare service_env="ufw_public_${service_id}=${service_name}/deny" + break; + fi + done + exec 8<&- + + [[ -z "${service_env:-}" ]] && die "Could not find service \"$service_name\"" + + docker service update --update-parallelism=0 \ + --env-add ufw_docker_agent_image="${ufw_docker_agent_image}" \ + --env-add "${service_env}" \ + --image "${ufw_docker_agent_image}" \ + "${ufw_docker_agent}" +} + +function ufw-docker--raw-command() { + ufw "$@" +} + +after_rules="/etc/ufw/after.rules" + +function ufw-docker--check() { + err "\\n########## iptables -n -L DOCKER-USER ##########" + iptables -n -L DOCKER-USER + + err "\\n\\n########## diff $after_rules ##########" + ufw-docker--check-install && err "\\nCheck done." +} + +declare -a files_to_be_deleted + +function rm-on-exit() { + [[ $# -gt 0 ]] && files_to_be_deleted+=("$@") +} + +function on-exit() { + for file in "${files_to_be_deleted[@]:-}"; do + [[ -f "$file" ]] && rm -r "$file" + done + files_to_be_deleted=() +} + +trap on-exit EXIT INT TERM QUIT ABRT ERR + +function ufw-docker--check-install() { + after_rules_tmp="${after_rules_tmp:-$(mktemp)}" + rm-on-exit "$after_rules_tmp" + + sed "/^# BEGIN UFW AND DOCKER/,/^# END UFW AND DOCKER/d" "$after_rules" > "$after_rules_tmp" + >> "${after_rules_tmp}" cat <<-\EOF + # BEGIN UFW AND DOCKER + *filter + :ufw-user-forward - [0:0] + :ufw-docker-logging-deny - [0:0] + :DOCKER-USER - [0:0] + -A DOCKER-USER -j ufw-user-forward + + -A DOCKER-USER -j RETURN -s 10.0.0.0/8 + -A DOCKER-USER -j RETURN -s 172.16.0.0/12 + -A DOCKER-USER -j RETURN -s 192.168.0.0/16 + -A DOCKER-USER -j RETURN -s 100.64.0.0/10 + + -A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN + + -A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16 + -A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8 + -A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12 + -A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 100.64.0.0/10 + -A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16 + -A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8 + -A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12 + -A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 100.64.0.0/10 + + -A DOCKER-USER -j RETURN + + -A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] " + -A ufw-docker-logging-deny -j DROP + + COMMIT + # END UFW AND DOCKER + EOF + + diff -u --color=auto "$after_rules" "$after_rules_tmp" +} + +function ufw-docker--install() { + if ! ufw-docker--check-install; then + local after_rules_bak + after_rules_bak="${after_rules}-ufw-docker~$(date '+%Y-%m-%d-%H%M%S')~" + err "\\nBacking up $after_rules to $after_rules_bak" + cp "$after_rules" "$after_rules_bak" + cat "$after_rules_tmp" > "$after_rules" + err "Please restart UFW service manually by using the following command:" + if type systemctl &>/dev/null; then + err " sudo systemctl restart ufw" + else + err " sudo service ufw restart" + fi + fi +} + +function ufw-docker--help() { + cat <<-EOF >&2 + Usage: + ufw-docker [docker-instance-id-or-name [port[/tcp|/udp]] [network]] + ufw-docker delete allow [docker-instance-id-or-name [port[/tcp|/udp]] [network]] + + ufw-docker service allow >> + ufw-docker service delete allow + + ufw-docker + + Examples: + ufw-docker help + + ufw-docker check # Check the installation of firewall rules + ufw-docker install # Install firewall rules + + ufw-docker status + + ufw-docker list httpd + + + ufw-docker allow httpd + ufw-docker allow httpd 80 + ufw-docker allow httpd 80/tcp + ufw-docker allow httpd 80/tcp default + + ufw-docker delete allow httpd + ufw-docker delete allow httpd 80/tcp + ufw-docker delete allow httpd 80/tcp default + + ufw-docker service allow httpd 80/tcp + + ufw-docker service delete allow httpd + EOF +} + +function remove_blank_lines() { + sed '/^[[:blank:]]*$/d' +} + +function err() { + echo -e "$@" >&2 +} + +function die() { + err "ERROR:" "$@" + exit 1 +} + +# __main__ + +if ! ufw status 2>/dev/null | grep -Fq "Status: active" ; then + die "UFW is disabled or you are not root user, or mismatched iptables legacy/nf_tables, current $(iptables --version)" +fi + +if ! docker -v &> /dev/null; then + die "Docker executable not found." +fi + +ufw_action="${1:-help}" + +case "$ufw_action" in + delete) + shift || true + if [[ "${1:?Invalid 'delete' command syntax.}" != "allow" ]]; then + die "\"delete\" command only support removing allowed rules" + fi + ;& + list|allow) + shift || true + + INSTANCE_ID="${1:?Docker instance name/ID cannot be empty.}" + INSTANCE_NAME="$(ufw-docker--instance-name "$INSTANCE_ID")" + shift || true + + INSTANCE_PORT="${1:-}" + if [[ -n "$INSTANCE_PORT" && ! "$INSTANCE_PORT" =~ [0-9]+(/(tcp|udp))? ]]; then + die "invalid port syntax: \"$INSTANCE_PORT\"." + fi + + PROTO="$DEFAULT_PROTO" + if [[ "$INSTANCE_PORT" = */udp ]]; then + PROTO=udp + fi + shift || true + + NETWORK="${1:-}" + + INSTANCE_PORT="${INSTANCE_PORT%/*}" + + "ufw-docker--$ufw_action" "$INSTANCE_NAME" "$INSTANCE_PORT" "$PROTO" "$NETWORK" + ;; + service|raw-command|add-service-rule) + shift || true + "ufw-docker--$ufw_action" "$@" + ;; + status|install|check) + ufw-docker--"$ufw_action" + ;; + *) + ufw-docker--help + ;; +esac diff --git a/roles/docker/tasks/caddy.yml b/roles/docker/tasks/caddy.yml new file mode 100644 index 0000000..ed14d80 --- /dev/null +++ b/roles/docker/tasks/caddy.yml @@ -0,0 +1,27 @@ +- name: make caddy directories + ansible.builtin.file: + path: "{{ item}}" + state: directory + loop: + - /opt/stacks/caddy + +- name: copy Caddyfile + ansible.builtin.copy: + src: Caddyfile + dest: /opt/stacks/caddy/Caddyfile + owner: root + mode: 644 + +- name: copy caddy compose file + ansible.builtin.copy: + src: caddy-compose.yml + dest: /opt/stacks/caddy/compose.yml + owner: root + mode: 644 + +- name: deploy caddy stack + community.docker.docker_compose_v2: + project_src: /opt/stacks/caddy + recreate: always + files: + - compose.yml \ No newline at end of file diff --git a/roles/docker/tasks/gitea.yml b/roles/docker/tasks/gitea.yml new file mode 100644 index 0000000..6af2f73 --- /dev/null +++ b/roles/docker/tasks/gitea.yml @@ -0,0 +1,19 @@ +- name: make caddy directories + ansible.builtin.file: + path: "{{ item}}" + state: directory + loop: + - /opt/stacks/gitea + +- name: copy gitea compose file + ansible.builtin.copy: + src: gitea-compose.yml + dest: /opt/stacks/gitea/compose.yml + owner: root + mode: 644 + +- name: deploy gitea stack + community.docker.docker_compose_v2: + project_src: /opt/stacks/gitea + files: + - compose.yml \ No newline at end of file diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml new file mode 100644 index 0000000..7634d78 --- /dev/null +++ b/roles/docker/tasks/main.yml @@ -0,0 +1,65 @@ +- name: Install required system packages + apt: + pkg: + - apt-transport-https + - ca-certificates + - curl + - software-properties-common + - python3-pip + - virtualenv + - python3-setuptools + state: latest + update_cache: true + +- name: Add Docker GPG apt Key + apt_key: + url: https://download.docker.com/linux/ubuntu/gpg + state: present + +- name: Add Docker Repository + apt_repository: + repo: deb https://download.docker.com/linux/debian bookworm stable + state: present + +- name: Update apt and install docker-ce + apt: + name: docker-ce + state: latest + update_cache: true + +- name: copy over ufw-docker.sh + ansible.builtin.copy: + src: ufw-docker.sh + dest: /usr/local/bin/ufw-docker.sh + owner: root + mode: 755 + +- name: execute ufw-docker.sh + ansible.builtin.shell: /usr/local/bin/ufw-docker.sh install + +- name: make directories + ansible.builtin.file: + path: "{{ item }}" + state: directory + loop: + - /opt/stacks + - /opt/dockge + +- name: copy dockge compose file + ansible.builtin.copy: + src: dockge-compose.yml + dest: /opt/dockge/dockge.yml + owner: root + mode: 644 + +- name: deploy dockge stack + community.docker.docker_compose_v2: + project_src: /opt/dockge + files: + - dockge.yml + +- name: Install caddy + import_tasks: caddy.yml + +- name: Install gitea + import_tasks: gitea.yml diff --git a/site.yml b/site.yml new file mode 100644 index 0000000..0b38e4b --- /dev/null +++ b/site.yml @@ -0,0 +1,5 @@ +- hosts: docker + become: true + roles: + - common + - docker \ No newline at end of file