diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 00000000..eecbc51a --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,5 @@ +[defaults] +INVENTORY = hosts + +[ssh_connections] +pipelining = true \ No newline at end of file diff --git a/ansible/group_vars/all/vars.yml b/ansible/group_vars/all/vars.yml new file mode 100644 index 00000000..4c77a9f1 --- /dev/null +++ b/ansible/group_vars/all/vars.yml @@ -0,0 +1,15 @@ +packages: + - nano + - exfat-fuse + - exfat-utils + - ca-certificates + - curl + - gnupg + - lsb-release + - nfs-common + - unbound + - dnsutils + +### ZSH Settings +zsh_theme: "powerlevel10k/powerlevel10k" +ohmyzsh_git_url: https://github.com/robbyrussell/oh-my-zsh \ No newline at end of file diff --git a/ansible/tasks/essential.yml b/ansible/tasks/essential.yml new file mode 100644 index 00000000..0856d0db --- /dev/null +++ b/ansible/tasks/essential.yml @@ -0,0 +1,87 @@ +- name: Update packages + apt: + update_cache: yes + upgrade: yes + +- name: Install essential packages + package: + name: "{{ packages }}" + state: latest + +- name: Check if docker is installed + stat: + path: /usr/bin/docker + register: docker_status + +- name: Check if docker pgp key is installed + stat: + path: /usr/share/keyrings/docker-archive-keyring.gpg + register: docker_pgp_key_status + +- name: Download docker + shell: "curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg" + when: not docker_pgp_key_status.stat.exists + +- name: Setup stable docker repository + shell: 'echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null' + when: not docker_status.stat.exists + +- name: Update packages + apt: + update_cache: yes + upgrade: yes + +- name: Install essential packages + package: + name: + - docker-ce + - docker-ce-cli + - containerd.io + state: latest + +- name: Add group docker + group: + name: docker + +- name: Add user to group docker + user: + name: "{{ username }}" + group: docker + +- name: Disable SSH password auth + lineinfile: + dest: /etc/ssh/sshd_config + regexp: "^#PasswordAuthentication yes" + line: "PasswordAuthentication no" + register: sshd_config + +- name: Enable passwordless sudo for "{{ username }}" + lineinfile: + dest: /etc/sudoers + regexp: "^%wheel" + line: "{{ username }} ALL=(ALL) NOPASSWD: ALL" + validate: "/usr/sbin/visudo -cf %s" + +- name: Restart SSH daemon + service: + name: sshd + state: restarted + when: sshd_config.changed + +- name: Allow SSH in UFW + community.general.ufw: + rule: allow + port: 22 + from: 192.168.2.0/24 + proto: tcp + +- name: Allow port 111 for NFS + community.general.ufw: + rule: allow + port: 111 + from: 192.168.2.0/24 + when: nfs_share is defined + +- name: Enable UFW + community.general.ufw: + state: enabled diff --git a/app-data/.gitkeep b/app-data/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apps/pi-hole/data/dnsmasq/.gitkeep b/apps/pi-hole/data/dnsmasq/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apps/pi-hole/data/pihole/.gitkeep b/apps/pi-hole/data/pihole/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apps/pi-hole/docker-compose.yml b/apps/pi-hole/docker-compose.yml new file mode 100644 index 00000000..c2284962 --- /dev/null +++ b/apps/pi-hole/docker-compose.yml @@ -0,0 +1,19 @@ +version: "3.7" + +services: + server: + image: pihole/pihole + restart: on-failure + ports: + - 53:53 + - 53:53/udp + - ${APP_PI_HOLE_PORT}:80 + volumes: + - ${APP_DATA_DIR}/data/pihole:/etc/pihole/ + - ${APP_DATA_DIR}/data/dnsmasq:/etc/dnsmasq.d/ + environment: + - VIRTUAL_HOST=${APP_DOMAIN} + - WEBPASSWORD=${APP_PASSWORD} + networks: + default: + ipv4_address: $APP_PI_HOLE_IP diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..5e517a06 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3.7' + +services: + nginx-proxy: + image: 'jc21/nginx-proxy-manager:latest' + restart: unless-stopped + ports: + - '80:80' + - '81:81' + - '443:443' + volumes: + - ${PWD}/nginx:/data + - ${PWD}/letsencrypt:/etc/letsencrypt \ No newline at end of file diff --git a/letsencrypt/.gitkeep b/letsencrypt/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/nginx/.gitkeep b/nginx/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/scripts/configure.sh b/scripts/configure.sh new file mode 100644 index 00000000..3d0747ad --- /dev/null +++ b/scripts/configure.sh @@ -0,0 +1,76 @@ +# Constants +NETWORK_IP="10.21.21.0" +GATEWAY_IP="10.21.21.1" +NGINX_IP="10.21.21.2" +NGINX_PORT="80" +TIPI_IP="$1" +USERNAME="$(whoami)" + +# Apps +APP_PI_HOLE_PORT="8081" +APP_PI_HOLE_IP="10.21.21.20" + +# Store paths to intermediary config files +ANSIBLE_HOSTS_FILE="./templates/ansible-hosts-sample.cfg" +ENV_FILE="./templates/.env" + +# Remove intermediary config files +[[ -f "$ENV_FILE" ]] && rm -f "$ENV_FILE" +[[ -f "$ANSIBLE_HOSTS_FILE" ]] && rm -f "$ANSIBLE_HOSTS_FILE" + +# Copy template configs to intermediary configs +[[ -f "./templates/.env-sample" ]] && cp "./templates/.env-sample" "$ENV_FILE" +[[ -f "./templates/ansible-hosts-sample.cfg" ]] && cp "./templates/ansible-hosts-sample.cfg" "$ANSIBLE_HOSTS_FILE" + +# Install ansible if not installed +if ! command -v ansible > /dev/null; then + echo "Installing Ansible..." + apt-get update + apt-get install -y software-properties-common + apt-add-repository -y ppa:ansible/ansible + apt-get update + apt-get install -y ansible +fi + +# Install ssh-keygen if not installed +if ! command -v ssh-keygen > /dev/null; then + echo "Installing ssh-keygen..." + apt-get update + apt-get install -y ssh-keygen +fi + +# Generate ssh keys +if [[ ! -f "~/ssh/id_rsa_tipi" ]]; then + echo "Generating ssh keys..." + mkdir -p "~/ssh" + ssh-keygen -t rsa -b 4096 -f "~/ssh/id_rsa_tipi" -N "" +fi + +echo "Generating config files..." +for template in "${ENV_FILE}" "${ANSIBLE_HOSTS_FILE}"; do + # Umbrel + sed -i "s//${NETWORK_IP}/g" "${template}" + sed -i "s//${GATEWAY_IP}/g" "${template}" + sed -i "s//${NGINX_IP}/g" "${template}" + sed -i "s//${NGINX_PORT}/g" "${template}" + # Apps + sed -i "s//${APP_PI_HOLE_PORT}/g" "${template}" + sed -i "s//${APP_PI_HOLE_IP}/g" "${template}" + # Ansible + sed -i "s//${TIPI_IP}/g" "${template}" + sed -i "s//${USERNAME}/g" "${template}" +done + +# Copy SSH keys to ansible host +echo "Copying SSH keys to tipi server..." +ssh-copy-id -i "~/ssh/id_rsa_tipi" "${USERNAME}@${TIPI_IP}" + +mv -f "$ENV_FILE" "./.env" +mv -f "$ANSIBLE_HOSTS_FILE" "./ansible/hosts" + +echo "Configuring permissions..." +find "$UMBREL_ROOT" -path "$UMBREL_ROOT/app-data" -prune -o -exec chown 1000:1000 {} + || true + +# Run ansible playbook +echo "Running Ansible playbook..." +ansible-playbook -i "./ansible/hosts" "./ansible/playbook.yml" \ No newline at end of file diff --git a/scripts/start.sh b/scripts/start.sh new file mode 100644 index 00000000..2856a64a --- /dev/null +++ b/scripts/start.sh @@ -0,0 +1,6 @@ +if [[ $UID != 0 ]]; then + echo "Tipi must be started as root" + echo "Please re-run this script as" + echo " sudo ./scripts/start" + exit 1 +fi \ No newline at end of file diff --git a/templates/.env-sample b/templates/.env-sample new file mode 100644 index 00000000..77f46023 --- /dev/null +++ b/templates/.env-sample @@ -0,0 +1,10 @@ +#Umbrel +NETWORK_IP= +GATEWAY_IP= +NGINX_IP= +NGINX_PORT= +DASHBOARD_IP= + +# Apps +APP_PI_HOLE_PORT= +APP_PI_HOLE_IP= diff --git a/templates/ansible-hosts-sample.cfg b/templates/ansible-hosts-sample.cfg new file mode 100644 index 00000000..017327fb --- /dev/null +++ b/templates/ansible-hosts-sample.cfg @@ -0,0 +1,2 @@ +[home] +homeserver ansible_host= ansible_user= ansible_connection=ssh ansible_ssh_private_key_file= \ No newline at end of file diff --git a/templates/nginx-sample.conf b/templates/nginx-sample.conf new file mode 100644 index 00000000..0cdc7d22 --- /dev/null +++ b/templates/nginx-sample.conf @@ -0,0 +1,31 @@ +# Warning: it's not recommended to modify these files directly. Any +# modifications you make can break the functionality of your umbrel. These files +# are automatically reset with every Umbrel update. + +user nginx; +worker_processes 1; + +error_log /dev/stdout info; + +events { + worker_connections 1024; +} + +http { + access_log /dev/stdout; + + proxy_read_timeout 600; + + default_type application/octet-stream; + + server { + listen 80; + + location / { + proxy_pass http://:3004/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + } +}