├── .gitignore ├── LICENSE ├── README.md ├── TODO.md ├── ansible ├── Makefile ├── README.md ├── ansible.cfg ├── inventory.hydra ├── inventory.sample ├── playbook.yml └── roles │ ├── bootstrap-node │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ ├── apt.yml │ │ ├── hostname.yml │ │ ├── locale.yml │ │ ├── main.yml │ │ ├── node-exporter.yml │ │ ├── ssh.yml │ │ ├── timezone.yml │ │ └── user.yml │ ├── templates │ │ └── ssh-banner.j2 │ └── vars │ │ └── main.yml │ ├── setup-docker │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ └── daemon.json │ ├── setup-tailscale │ ├── handlers │ │ └── main.yml │ └── tasks │ │ └── main.yml │ └── viasite-ansible.zsh │ ├── .gitignore │ ├── .gitlab-ci.yml │ ├── .travis.yml │ ├── CHANGELOG.md │ ├── README.md │ ├── Vagrantfile │ ├── defaults │ └── main.yml │ ├── install.sh │ ├── meta │ ├── .galaxy_install_info │ └── main.yml │ ├── molecule │ ├── default │ │ ├── molecule.yml │ │ └── tests │ │ │ └── test_default.py │ ├── resources │ │ ├── converge.yml │ │ └── prepare.yml │ ├── shared │ │ └── molecule.yml │ └── user │ │ ├── molecule.yml │ │ └── prepare.yml │ ├── playbook.yml │ ├── scripts │ └── generate-changelog │ ├── tasks │ ├── configure.yml │ ├── install.yml │ ├── main.yml │ └── post-install.yml │ ├── templates │ └── zshrc.j2 │ ├── tests │ └── vagrant.yml │ └── vars │ └── main.yml ├── docs ├── SETUP.md └── calvin.jpg ├── talks ├── foss-united-apr-2021.html ├── foss-united-apr-2021.md └── img │ ├── cycle.jpg │ ├── isp-monitoring-2.png │ └── isp-monitoring.png └── terraform ├── .terraform.lock.hcl ├── Makefile ├── env.sample ├── main.tf ├── modules ├── caddy │ ├── conf │ │ ├── Caddyfile-internal │ │ ├── Caddyfile-public │ │ └── caddy.nomad │ ├── data.tf │ ├── job.tf │ ├── providers.tf │ └── variables.tf ├── cloudflare │ ├── records.tf │ ├── variables.tf │ ├── versions.tf │ └── zones.tf ├── digitalocean │ ├── README.md │ ├── firewalls.tf │ ├── floyd.tf │ ├── output.tf │ ├── project.tf │ ├── ssh.tf │ └── versions.tf ├── doggo │ ├── conf │ │ └── doggo.nomad │ ├── job.tf │ └── providers.tf ├── gitea │ ├── conf │ │ ├── app.ini.tpl │ │ └── gitea.nomad │ ├── data.tf │ ├── job.tf │ ├── providers.tf │ └── variables.tf ├── monitoring │ ├── conf │ │ ├── monitoring.nomad │ │ └── prometheus.yml │ ├── data.tf │ ├── job.tf │ └── providers.tf ├── pihole │ ├── conf │ │ └── pihole.nomad │ ├── job.tf │ └── providers.tf ├── restic │ ├── conf │ │ └── restic.nomad │ ├── job.tf │ ├── providers.tf │ └── variables.tf ├── shynet │ ├── conf │ │ ├── app.nomad │ │ └── db.nomad │ ├── job.tf │ ├── providers.tf │ └── variables.tf └── syncthing │ ├── conf │ └── app.nomad │ ├── job.tf │ └── providers.tf ├── providers.tf ├── variables.tf └── versions.tf /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | packer* 3 | www 4 | inventory 5 | *.tfvars 6 | .terraform.tfstate.lock.info 7 | .terraform 8 | *.tfstate 9 | *.tfstate.backup 10 | *.backup 11 | *.env 12 | AdGuardHome.yaml 13 | .ci-vault-pass 14 | consul-keys.txt 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Karan Sharma 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 |

hydra

5 |

6 | Setup scripts for my homelab 7 |

8 | Calvin and Hobbes 9 |

10 | 11 | --- 12 | 13 | ## Overview 14 | 15 | - Single node [Nomad](https://www.nomadproject.io/) server for running workloads. 16 | - [Consul](https://www.consul.io/) agent co-located for service discovery. 17 | - [Ansible](https://www.ansible.com/) scripts to boostrap the node. 18 | - [Terraform](https://www.terraform.io/) modules for managing the following services: 19 | - Nomad jobs 20 | - Cloudflare DNS 21 | - DigitalOcean Infra 22 | - [Tailscale VPN](https://tailscale.com/) for connectivity to internal services. 23 | - [Caddy](https://caddyserver.com/) as a reverse proxy for all web services. 24 | 25 | ## Services Running 26 | 27 | - [Pihole](https://pi-hole.net/) 28 | - [Gitea](https://gitea.io/) 29 | - [Shynet](https://github.com/milesmcc/shynet) 30 | - [Syncthing](https://syncthing.net/) 31 | 32 | ## Blog Posts 33 | 34 | Here's a collection of posts I've written which shows how Hydra has evolved over the years: 35 | 36 | - **2021-02-14**: [Home Server with Nomad](https://mrkaran.dev/posts/home-server-nomad/) 37 | - **2020-04-23**: [Home Server Updates](https://mrkaran.dev/posts/home-server-updates/) 38 | - **2019-09-22**: [Home Server Setup](https://mrkaran.dev/posts/home-server-setup/) 39 | 40 | ## Setup Instructions 41 | 42 | Visit [SETUP.md](./docs/SETUP.md) for following instructions on setting up Nomad and Consul. 43 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ## Baby Steps 2 | 3 | - [x] Setup Tailscale in Floyd/Gilmour. 4 | - [x] Configure Nomad and Consul to bind on Tailscale Address. 5 | - [x] Deploy Caddy as a Nomad Job which 6 | - [x] binds to 80/443 on host 7 | - [x] mounts the cert directory 8 | - [x] template file (caddy.tpl) 9 | - [x] Configure `nomad.mrkaran.dev` and `consul.mrkaran.dev`. 10 | - [x] Create Terraform module for running workloads as Nomad jobs. 11 | 12 | ## Hands on by deploying more workloads 13 | 14 | - [x] Deploy `shynet.mrkaran.dev` 15 | -------------------------------------------------------------------------------- /ansible/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: run 2 | 3 | run: 4 | ansible-playbook playbook.yml -i inventory --extra-vars "hosts=hydra" 5 | -------------------------------------------------------------------------------- /ansible/README.md: -------------------------------------------------------------------------------- 1 | # Ansible Playbook for setting up Hydra Home Server 2 | 3 | ## Running 4 | 5 | ## Imp things to keep in mind 6 | 7 | 1) `ansible_ssh_user` for the first run should `root` since there is no user in the instance. 8 | You must ensure that `bootstrap-nodes` role is first run before continuing. It disables the `root` SSH login to the instance and only 9 | the `username` supplied in `inventory` has access to SSH. 10 | 11 | **Bootstrap**: `ansible-playbook -i inventory playbook.yml --tag=bootstrap` 12 | 13 | If you fail at this step, you need to debug before proceeding. 14 | 15 | 16 | 2) For Tailscale, it is recommended to generate `Pre Authorisation Keys` and encrypt them in vault: 17 | 18 | - To encrypt the string `ansible-vault encrypt_string '' --name 'tailscale_auth_key` 19 | - To run the playbook: `ansible-playbook -i inventory playbook.yml --tag=tailscale --ask-vault-pass` 20 | -------------------------------------------------------------------------------- /ansible/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | roles_path = ./roles 3 | inventory = ./inventory 4 | # strategy_plugins = /home/karan/.local/lib/python3.8/site-packages/ansible_mitogen/plugins/strategy 5 | # strategy = mitogen_linear 6 | [ssh_connection] 7 | scp_if_ssh = True -------------------------------------------------------------------------------- /ansible/inventory.hydra: -------------------------------------------------------------------------------- 1 | [hydra:children] 2 | floyd 3 | 4 | [floyd] 5 | floyd ansible_ssh_host=floyd ansible_ssh_user=karan ansible_ssh_port=22 remote_ssh_user=karan 6 | 7 | [floyd:vars] 8 | username=karan 9 | github_ssh_key_url=https://github.com/mr-karan.keys -------------------------------------------------------------------------------- /ansible/inventory.sample: -------------------------------------------------------------------------------- 1 | [hydra:children] 2 | srv1 3 | 4 | [srv1] 5 | srv1 ansible_ssh_host=srv1 ansible_ssh_user=username ansible_ssh_port=22 remote_ssh_user=user 6 | 7 | [srv1:vars] 8 | username=username 9 | github_ssh_key_url=https://github.com/username.keys -------------------------------------------------------------------------------- /ansible/playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | roles: 5 | - role: bootstrap-node 6 | tags: 7 | - bootstrap 8 | 9 | - role: setup-docker 10 | become: true 11 | tags: 12 | - docker 13 | 14 | - role: setup-tailscale 15 | become: yes 16 | tags: 17 | - tailscale 18 | 19 | - role: viasite-ansible.zsh 20 | become: yes 21 | tags: 22 | - zsh 23 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: restart sshd 2 | service: 3 | name: ssh 4 | state: restarted 5 | 6 | - name: reboot 7 | reboot: 8 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/tasks/apt.yml: -------------------------------------------------------------------------------- 1 | - name: Update apt cache and upgrade 2 | become: yes 3 | apt: 4 | update_cache: yes 5 | upgrade: "yes" 6 | 7 | - name: Install dependencies 8 | become: yes 9 | apt: 10 | name: "{{ packages }}" 11 | vars: 12 | packages: 13 | - apt-transport-https 14 | - vim 15 | - curl 16 | - jq 17 | - fzf 18 | - python 19 | - python3-pip 20 | - python-apt 21 | - python3-apt 22 | - gnupg2 23 | - gnupg-agent 24 | 25 | - name: install unattended-upgrades 26 | apt: 27 | name: "unattended-upgrades" 28 | state: present 29 | 30 | - name: Remove useless packages from the cache 31 | become: yes 32 | apt: 33 | autoclean: yes 34 | 35 | - name: Remove dependencies that are no longer required 36 | become: yes 37 | apt: 38 | autoremove: yes 39 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/tasks/hostname.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: updating hostname to {{inventory_hostname}} from {{ansible_hostname}} 4 | hostname: 5 | name: "{{inventory_hostname}}" 6 | notify: 7 | - reboot 8 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/tasks/locale.yml: -------------------------------------------------------------------------------- 1 | - name: Ensure US locale exists 2 | locale_gen: 3 | name: en_US.UTF-8 4 | state: present -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - import_tasks: apt.yml 4 | tags: 5 | - apt 6 | 7 | - import_tasks: locale.yml 8 | tags: 9 | - locale 10 | 11 | - import_tasks: user.yml 12 | tags: 13 | - user 14 | 15 | - import_tasks: ssh.yml 16 | tags: 17 | - ssh 18 | 19 | - import_tasks: timezone.yml 20 | tags: 21 | - timezone 22 | 23 | - import_tasks: hostname.yml 24 | tags: 25 | - hostname 26 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/tasks/node-exporter.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mr-karan/homelab/06653f8f276e53b3ef987d80ce65b7d7e190cdce/ansible/roles/bootstrap-node/tasks/node-exporter.yml -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/tasks/ssh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: disable ssh remote root login 4 | lineinfile: 5 | dest: "{{ ssh_sshd_config }}" 6 | regexp: "^#?PermitRootLogin" 7 | line: "PermitRootLogin no" 8 | state: present 9 | notify: 10 | - restart sshd 11 | 12 | - name: enable ssh strict mode 13 | lineinfile: 14 | dest: "{{ ssh_sshd_config }}" 15 | regexp: "^#?StrictModes" 16 | line: "StrictModes yes" 17 | state: present 18 | notify: 19 | - restart sshd 20 | 21 | - name: disable X11 forwarding 22 | lineinfile: 23 | dest: "{{ ssh_sshd_config }}" 24 | regexp: "^#?X11Forwarding" 25 | line: "X11Forwarding no" 26 | state: present 27 | notify: 28 | - restart sshd 29 | 30 | - name: disable ssh password login 31 | lineinfile: 32 | dest: "{{ ssh_sshd_config }}" 33 | regexp: "{{ item.regexp }}" 34 | line: "{{ item.line }}" 35 | state: present 36 | with_items: 37 | - regexp: "^#?PasswordAuthentication" 38 | line: "PasswordAuthentication no" 39 | - regexp: "^#?ChallengeResponseAuthentication" 40 | line: "ChallengeResponseAuthentication no" 41 | - regexp: "^#?PermitEmptyPasswords" 42 | line: "PermitEmptyPasswords no" 43 | notify: 44 | - restart sshd 45 | 46 | - name: set ssh allowed users to {{ username }} 47 | lineinfile: 48 | dest: "{{ ssh_sshd_config }}" 49 | regexp: "^#?AllowUsers" 50 | line: "AllowUsers {{ username }}" 51 | notify: 52 | - restart sshd 53 | when: username != None 54 | 55 | - name: add ssh banner info 56 | lineinfile: 57 | dest: "{{ ssh_sshd_config }}" 58 | regexp: "^#?Banner" 59 | line: "Banner /etc/issue.net" 60 | state: present 61 | notify: 62 | - restart sshd 63 | 64 | - name: update ssh banner 65 | template: 66 | src: ssh-banner.j2 67 | dest: /etc/issue.net 68 | notify: 69 | - restart sshd 70 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/tasks/timezone.yml: -------------------------------------------------------------------------------- 1 | - name: Set timezone to Asia/Kolkata 2 | timezone: 3 | name: Asia/Kolkata 4 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/tasks/user.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Make sure we have a 'wheel' group 4 | group: 5 | name: wheel 6 | state: present 7 | 8 | - name: Allow 'wheel' group to have passwordless sudo 9 | lineinfile: 10 | dest: /etc/sudoers 11 | state: present 12 | regexp: '^%wheel' 13 | line: '%wheel ALL=(ALL) NOPASSWD: ALL' 14 | validate: 'visudo -cf %s' 15 | when: ansible_user == "root" 16 | 17 | - name: Add user to wheel group 18 | user: 19 | name: "{{username}}" 20 | groups: 21 | - wheel 22 | append: yes 23 | state: present 24 | createhome: yes 25 | shell: /bin/bash 26 | when: ansible_user == "root" 27 | 28 | - name: Set authorized key for user 29 | authorized_key: 30 | user: "{{username}}" 31 | state: present 32 | key: "{{github_ssh_key_url}}" 33 | when: github_ssh_key_url != None 34 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/templates/ssh-banner.j2: -------------------------------------------------------------------------------- 1 | ******************************************************************************** 2 | * Welcome to {{ansible_hostname}}! The Hydra HomeLab Server. * 3 | * * 4 | * This system is for the use of authorized users only. Usage of * 5 | * this system may be monitored and recorded by system personnel. * 6 | * * 7 | ******************************************************************************** 8 | 9 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap-node/vars/main.yml: -------------------------------------------------------------------------------- 1 | ssh_sshd_config: "/etc/ssh/sshd_config" 2 | -------------------------------------------------------------------------------- /ansible/roles/setup-docker/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: Start docker on boot 2 | systemd: 3 | name: docker 4 | state: started 5 | enabled: yes 6 | 7 | - name: Restart Docker 8 | systemd: 9 | name: docker 10 | state: restarted 11 | -------------------------------------------------------------------------------- /ansible/roles/setup-docker/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # sudo apt-get install * 2 | - name: Install docker packages 3 | apt: 4 | name: 5 | [ 6 | "apt-transport-https", 7 | "ca-certificates", 8 | "curl", 9 | "gnupg-agent", 10 | "software-properties-common", 11 | ] 12 | state: present 13 | update_cache: yes 14 | tags: 15 | - docker 16 | 17 | # curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 18 | - name: Add Docker s official GPG key 19 | apt_key: 20 | url: https://download.docker.com/linux/ubuntu/gpg 21 | state: present 22 | tags: 23 | - docker 24 | 25 | # sudo apt-key fingerprint 0EBFCD88 26 | - name: Verify that we have the key with the fingerprint 27 | apt_key: 28 | id: 0EBFCD88 29 | state: present 30 | tags: 31 | - docker 32 | 33 | # sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" 34 | - name: Set up the stable repository 35 | apt_repository: 36 | repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable 37 | state: present 38 | update_cache: yes 39 | tags: 40 | - docker 41 | 42 | # sudo apt-get update 43 | - name: Update apt packages 44 | apt: 45 | update_cache: yes 46 | tags: 47 | - docker 48 | 49 | # sudo apt-get install docker-ce 50 | - name: Install docker 51 | apt: 52 | state: present 53 | update_cache: yes 54 | name: ["docker-ce", "docker-ce-cli", "containerd.io"] 55 | notify: Start docker on boot 56 | tags: 57 | - docker 58 | 59 | # sudo groupadd docker 60 | - name: Create "docker" group 61 | group: 62 | name: "docker" 63 | state: present 64 | tags: 65 | - docker 66 | 67 | # sudo usermod -aG docker 68 | - name: Add remote user to "docker" group 69 | user: 70 | name: "{{username}}" 71 | group: "docker" 72 | append: yes 73 | tags: 74 | - docker 75 | 76 | - name: Configure sane defaults for logging (docker daemon) 77 | template: 78 | src: "daemon.json" 79 | dest: "/etc/docker/daemon.json" 80 | owner: "root" 81 | group: "root" 82 | mode: "0644" 83 | notify: Restart Docker 84 | tags: 85 | - docker 86 | 87 | - name: Install Docker-compose 88 | shell: sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 89 | tags: 90 | - docker 91 | 92 | - name: Changing perm of /usr/local/bin/docker-compose 93 | file: dest=/usr/local/bin/docker-compose mode=a+x 94 | tags: 95 | - docker 96 | -------------------------------------------------------------------------------- /ansible/roles/setup-docker/templates/daemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "log-driver": "json-file", 3 | "log-opts": { 4 | "max-size": "10m", 5 | "max-file": "10" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ansible/roles/setup-tailscale/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: enable tailscaled service 2 | service: 3 | name: tailscaled 4 | state: started 5 | enabled: yes 6 | 7 | - name: Tailscale Status 8 | listen: Confirm Tailscale is Connected 9 | command: tailscale status 10 | register: handlers_tailscale_status 11 | 12 | - name: Assert Tailscale is Connected 13 | listen: Confirm Tailscale is Connected 14 | assert: 15 | that: 16 | - handlers_tailscale_status.stdout | length != 0 17 | -------------------------------------------------------------------------------- /ansible/roles/setup-tailscale/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Update apt cache and upgrade 2 | apt: 3 | update_cache: yes 4 | upgrade: "yes" 5 | 6 | - name: Tailscale Signing Key 7 | apt_key: 8 | url: https://pkgs.tailscale.com/stable/{{ ansible_distribution | lower }}/{{ ansible_distribution_release | lower }}.gpg 9 | state: present 10 | 11 | - name: Add Tailscale Deb 12 | apt_repository: 13 | repo: deb https://pkgs.tailscale.com/stable/{{ ansible_distribution | lower }} {{ ansible_distribution_release | lower }} main 14 | state: present 15 | 16 | - name: Install Tailscale 17 | apt: 18 | name: tailscale 19 | state: present 20 | update_cache: yes 21 | notify: enable tailscaled service 22 | 23 | - name: Check if Tailscale is connected 24 | command: tailscale status 25 | changed_when: false 26 | register: tailscale_status 27 | 28 | # - name: Bring Tailscale Up 29 | # become: yes 30 | # command: tailscale up --authkey={{ tailscale_auth_key }} 31 | # register: tailscale_start 32 | # when: tailscale_status.stdout | length == 0 33 | # notify: Confirm Tailscale is Connected 34 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/.gitignore: -------------------------------------------------------------------------------- 1 | .molecule 2 | 00aptproxy 3 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test: 3 | script: 4 | - molecule test --all 5 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: python 3 | python: "2.7" 4 | sudo: required 5 | services: 6 | - docker 7 | 8 | before_install: 9 | - docker --version 10 | install: 11 | - pip install molecule docker 12 | script: 13 | - molecule test --all 14 | 15 | notifications: 16 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [master](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.2.6...v) (2020-05-01) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * configurable zsh_fzf_path variable and change $HOME/.bin to $HOME/bin ([5b9ab7a](https://github.com/viasite-ansible/ansible-role-zsh/commit/5b9ab7a)) 7 | * extending of PATH not just rewrite ([6c2fdd7](https://github.com/viasite-ansible/ansible-role-zsh/commit/6c2fdd7)), closes [#14](https://github.com/viasite-ansible/ansible-role-zsh/issues/14) 8 | 9 | 10 | ### Features 11 | 12 | * fzf path should be /usr/local/bin only in shared scenarios, otherwise it should be installed in local user home ([e3ada98](https://github.com/viasite-ansible/ansible-role-zsh/commit/e3ada98)) 13 | 14 | 15 | 16 | ## [3.2.5](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.2.4...v3.2.5) (2019-03-14) 17 | 18 | 19 | ### Bug Fixes 20 | 21 | * check commands in in check mode ([030bc1f](https://github.com/viasite-ansible/ansible-role-zsh/commit/030bc1f)), closes [#31](https://github.com/viasite-ansible/ansible-role-zsh/issues/31) 22 | 23 | 24 | 25 | ## [3.2.4](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.2.3...v3.2.4) (2019-03-14) 26 | 27 | 28 | ### Bug Fixes 29 | 30 | * correct run in check mode ([9f6d88b](https://github.com/viasite-ansible/ansible-role-zsh/commit/9f6d88b)), closes [#31](https://github.com/viasite-ansible/ansible-role-zsh/issues/31) 31 | 32 | 33 | 34 | ## [3.2.3](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.2.2...v3.2.3) (2018-11-21) 35 | 36 | 37 | ### Bug Fixes 38 | 39 | * add POWERLEVEL9K_CONTEXT_REMOTE colors same as POWERLEVEL9K_CONTEXT_DEFAULT ([6794785](https://github.com/viasite-ansible/ansible-role-zsh/commit/6794785)) 40 | * don't use paths like ~user in config ([40150ec](https://github.com/viasite-ansible/ansible-role-zsh/commit/40150ec)) 41 | * freeze zdharma/fast-syntax-highlighting at v1.2 ([1765bff](https://github.com/viasite-ansible/ansible-role-zsh/commit/1765bff)) 42 | * unquote path ([3677d78](https://github.com/viasite-ansible/ansible-role-zsh/commit/3677d78)) 43 | 44 | 45 | ### Features 46 | 47 | * shared installation for many users, zsh_shared ([0bdba8e](https://github.com/viasite-ansible/ansible-role-zsh/commit/0bdba8e)) 48 | * zsh_aliases ([2770ec3](https://github.com/viasite-ansible/ansible-role-zsh/commit/2770ec3)) 49 | 50 | 51 | 52 | ## [3.2.2](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.2.1...v3.2.2) (2018-06-13) 53 | 54 | 55 | ### Bug Fixes 56 | 57 | * upgrade fzf 0.17.3 -> 0.17.4 ([98a0569](https://github.com/viasite-ansible/ansible-role-zsh/commit/98a0569)) 58 | 59 | 60 | 61 | ## [3.2.1](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.2.0...v3.2.1) (2018-05-01) 62 | 63 | 64 | ### Features 65 | 66 | * Midnight Commander Solarized Dark skin ([0017e34](https://github.com/viasite-ansible/ansible-role-zsh/commit/0017e34)) 67 | 68 | 69 | 70 | # [3.2.0](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.1.2...v3.2.0) (2018-01-11) 71 | 72 | 73 | ### Bug Fixes 74 | 75 | * alias 'suser' ([ba34e57](https://github.com/viasite-ansible/ansible-role-zsh/commit/ba34e57)) 76 | * update fzf to 0.6.11 ([385dc9d](https://github.com/viasite-ansible/ansible-role-zsh/commit/385dc9d)) 77 | * upgrade fzf 0.16.11 -> 0.17.3 ([1a08ef2](https://github.com/viasite-ansible/ansible-role-zsh/commit/1a08ef2)) 78 | 79 | 80 | ### Features 81 | 82 | * install.sh for current user ([a7c998e](https://github.com/viasite-ansible/ansible-role-zsh/commit/a7c998e)) 83 | 84 | 85 | 86 | ## [3.1.2](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.1.1...v3.1.2) (2017-06-21) 87 | 88 | 89 | ### Features 90 | 91 | * add viasite-ansible/zsh-ansible-server bundle ([3c990b2](https://github.com/viasite-ansible/ansible-role-zsh/commit/3c990b2)) 92 | 93 | 94 | 95 | ## [3.1.1](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.1.0...v3.1.1) (2017-06-14) 96 | 97 | 98 | ### Bug Fixes 99 | 100 | * update fzf to 0.16.8 ([0e7b913](https://github.com/viasite-ansible/ansible-role-zsh/commit/0e7b913)) 101 | 102 | 103 | ### Features 104 | 105 | * add systemd bundle ([40c34d0](https://github.com/viasite-ansible/ansible-role-zsh/commit/40c34d0)) 106 | 107 | 108 | 109 | # [3.1.0](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.0.3...v3.1.0) (2017-05-27) 110 | 111 | 112 | ### Features 113 | 114 | * add github-*, fzf-insert-* widgets (ytet5uy4/fzf-widgets update) ([23a7e9c](https://github.com/viasite-ansible/ansible-role-zsh/commit/23a7e9c)) 115 | 116 | 117 | 118 | ## [3.0.3](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.0.2...v3.0.3) (2017-05-27) 119 | 120 | 121 | ### Bug Fixes 122 | 123 | * update ytet5uy4/fzf-widgets@3f6b9cf ([58965f1](https://github.com/viasite-ansible/ansible-role-zsh/commit/58965f1)) 124 | 125 | 126 | 127 | ## [3.0.2](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.0.1...v3.0.2) (2017-05-26) 128 | 129 | 130 | ### Bug Fixes 131 | 132 | * switch antigen branch from develop to master ([6141a02](https://github.com/viasite-ansible/ansible-role-zsh/commit/6141a02)) 133 | 134 | 135 | ### Features 136 | 137 | * disable zsh share history (unsetopt share_history) ([de0b5ae](https://github.com/viasite-ansible/ansible-role-zsh/commit/de0b5ae)), closes [#16](https://github.com/viasite-ansible/ansible-role-zsh/issues/16) 138 | 139 | 140 | 141 | ## [3.0.1](https://github.com/viasite-ansible/ansible-role-zsh/compare/v3.0.0...v3.0.1) (2017-05-14) 142 | 143 | 144 | ### Bug Fixes 145 | 146 | * idempotence and correct `antigen reset` ([44bd345](https://github.com/viasite-ansible/ansible-role-zsh/commit/44bd345)) 147 | 148 | 149 | ### Features 150 | 151 | * upgrade to antigen v2 ([a85cc77](https://github.com/viasite-ansible/ansible-role-zsh/commit/a85cc77)), closes [#12](https://github.com/viasite-ansible/ansible-role-zsh/issues/12) 152 | 153 | 154 | 155 | ## [2.1.8](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.1.7...v2.1.8) (2017-05-13) 156 | 157 | 158 | ### Bug Fixes 159 | 160 | * make working command conditions on clean centos ([71399b8](https://github.com/viasite-ansible/ansible-role-zsh/commit/71399b8)), closes [#8](https://github.com/viasite-ansible/ansible-role-zsh/issues/8) 161 | 162 | 163 | 164 | ## [2.1.7](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.1.6...v2.1.7) (2017-05-13) 165 | 166 | 167 | ### Bug Fixes 168 | 169 | * replace popstas/zsh-command-time to native powerlevel9k segment ([24e3480](https://github.com/viasite-ansible/ansible-role-zsh/commit/24e3480)), closes [#13](https://github.com/viasite-ansible/ansible-role-zsh/issues/13) 170 | 171 | 172 | ### Features 173 | 174 | * hide host and/or user on local machine (powerlevel9k 0.6 feature) ([12630d4](https://github.com/viasite-ansible/ansible-role-zsh/commit/12630d4)), closes [#15](https://github.com/viasite-ansible/ansible-role-zsh/issues/15) 175 | 176 | 177 | 178 | ## [2.1.6](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.1.5...v2.1.6) (2017-04-26) 179 | 180 | 181 | ### Bug Fixes 182 | 183 | * skip early compinit execute on Ubuntu ([f581c7b](https://github.com/viasite-ansible/ansible-role-zsh/commit/f581c7b)), closes [#9](https://github.com/viasite-ansible/ansible-role-zsh/issues/9) 184 | 185 | 186 | ### Features 187 | 188 | * add docker widgets from updated ytet5uy4/fzf-widgets ([ee84bf3](https://github.com/viasite-ansible/ansible-role-zsh/commit/ee84bf3)) 189 | 190 | 191 | 192 | ## [2.1.5](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.1.4...v2.1.5) (2017-04-25) 193 | 194 | 195 | ### Bug Fixes 196 | 197 | * make condition for disable command-not-found for macOS ([d789633](https://github.com/viasite-ansible/ansible-role-zsh/commit/d789633)), closes [#7](https://github.com/viasite-ansible/ansible-role-zsh/issues/7) 198 | 199 | 200 | 201 | ## [2.1.4](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.1.3...v2.1.4) (2017-04-23) 202 | 203 | 204 | ### Bug Fixes 205 | 206 | * support check `command` exists for zsh_antigen_bundles_extras ([b6e4284](https://github.com/viasite-ansible/ansible-role-zsh/commit/b6e4284)) 207 | 208 | 209 | ### Features 210 | 211 | * add fzf-kill-process to ytet5uy4/fzf-widgets ([8bc9e93](https://github.com/viasite-ansible/ansible-role-zsh/commit/8bc9e93)) 212 | * add viasite/drall, viasite/server-scripts bundles ([74d3451](https://github.com/viasite-ansible/ansible-role-zsh/commit/74d3451)) 213 | 214 | 215 | 216 | ## [2.1.3](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.1.2...v2.1.3) (2017-04-21) 217 | 218 | 219 | ### Features 220 | 221 | * add viasite/drupal-scripts bundle for drs ([7371bde](https://github.com/viasite-ansible/ansible-role-zsh/commit/7371bde)) 222 | 223 | 224 | 225 | ## [2.1.2](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.1.1...v2.1.2) (2017-04-19) 226 | 227 | 228 | ### Bug Fixes 229 | 230 | * removed debian plugin from zsh_antigen_bundles ([ddb600e](https://github.com/viasite-ansible/ansible-role-zsh/commit/ddb600e)), closes [#6](https://github.com/viasite-ansible/ansible-role-zsh/issues/6) 231 | 232 | 233 | 234 | ## [2.1.1](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.1.0...v2.1.1) (2017-04-16) 235 | 236 | 237 | ### Bug Fixes 238 | 239 | * HIST_STAMPS, COMPLETION_WAITING_DOTS don't work if it before antigen apply ([4093191](https://github.com/viasite-ansible/ansible-role-zsh/commit/4093191)) 240 | * provision role for root on macOS ([2d1f939](https://github.com/viasite-ansible/ansible-role-zsh/commit/2d1f939)) 241 | 242 | 243 | ### Features 244 | 245 | * zsh-users/zsh-syntax-highlighting -> zdharma/fast-syntax-highlighting ([ff3542f](https://github.com/viasite-ansible/ansible-role-zsh/commit/ff3542f)) 246 | 247 | 248 | 249 | # [2.1.0](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.0.4...v2.1.0) (2017-04-08) 250 | 251 | 252 | ### Bug Fixes 253 | 254 | * role broken on 'Check commands exists' when skipped ([0676934](https://github.com/viasite-ansible/ansible-role-zsh/commit/0676934)) 255 | 256 | 257 | ### Features 258 | 259 | * new widget: fzf-git-delete-branches, add --exact to insert-history ([15d22a4](https://github.com/viasite-ansible/ansible-role-zsh/commit/15d22a4)), closes [ytet5uy4/fzf-widgets#2](https://github.com/ytet5uy4/fzf-widgets/issues/2) 260 | 261 | 262 | 263 | ## [2.0.4](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.0.3...v2.0.4) (2017-04-03) 264 | 265 | 266 | ### Bug Fixes 267 | 268 | * hotkeys with bundle dependency don't enabled if bundle was dict ([4187981](https://github.com/viasite-ansible/ansible-role-zsh/commit/4187981)) 269 | 270 | 271 | ### Features 272 | 273 | * add copy-earlier-word to widgets ([ec4382b](https://github.com/viasite-ansible/ansible-role-zsh/commit/ec4382b)) 274 | * zsh_hotkeys_extras variable for custom hotkeys ([e7e8b25](https://github.com/viasite-ansible/ansible-role-zsh/commit/e7e8b25)) 275 | 276 | 277 | 278 | ## [2.0.3](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.0.2...v2.0.3) (2017-04-03) 279 | 280 | 281 | ### Bug Fixes 282 | 283 | * add debian jessie to platforms ([995c601](https://github.com/viasite-ansible/ansible-role-zsh/commit/995c601)) 284 | * move TERM var above theme, for zsh 4.3 ([7030837](https://github.com/viasite-ansible/ansible-role-zsh/commit/7030837)) 285 | * zsh, disable autosuggestions for zsh 4.3 ([76521c9](https://github.com/viasite-ansible/ansible-role-zsh/commit/76521c9)) 286 | 287 | 288 | 289 | ## [2.0.2](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.0.1...v2.0.2) (2017-04-02) 290 | 291 | 292 | ### Bug Fixes 293 | 294 | * fzf install for macOS ([ce924e6](https://github.com/viasite-ansible/ansible-role-zsh/commit/ce924e6)) 295 | * remove composer plugin from defaults ([7dd8aa3](https://github.com/viasite-ansible/ansible-role-zsh/commit/7dd8aa3)) 296 | * zsh-syntax-highlighting loaded on zsh 4.3.10 ([6062c8d](https://github.com/viasite-ansible/ansible-role-zsh/commit/6062c8d)) 297 | 298 | 299 | 300 | ## [2.0.1](https://github.com/viasite-ansible/ansible-role-zsh/compare/v2.0.0...v2.0.1) (2017-04-02) 301 | 302 | 303 | ### Bug Fixes 304 | 305 | * remove zsh_check_commands, now it calculates dynamically ([84c36ca](https://github.com/viasite-ansible/ansible-role-zsh/commit/84c36ca)) 306 | 307 | 308 | ### Features 309 | 310 | * zsh_antigen_bundles_extras for custom bundles ([0e2ac6a](https://github.com/viasite-ansible/ansible-role-zsh/commit/0e2ac6a)), closes [#5](https://github.com/viasite-ansible/ansible-role-zsh/issues/5) 311 | 312 | 313 | 314 | # [2.0.0](https://github.com/viasite-ansible/ansible-role-zsh/compare/v1.1.6...v2.0.0) (2017-04-02) 315 | 316 | 317 | ### Bug Fixes 318 | 319 | * change antigen version to `master` for idempotency ([dee73e8](https://github.com/viasite-ansible/ansible-role-zsh/commit/dee73e8)) 320 | * check for fzf installed any way ([d5f8aae](https://github.com/viasite-ansible/ansible-role-zsh/commit/d5f8aae)) 321 | * don't install tmux if plugin enabled, but enable plugin if tmux installed ([640ab24](https://github.com/viasite-ansible/ansible-role-zsh/commit/640ab24)) 322 | * install.sh tested on ubuntu and debian ([bcb9112](https://github.com/viasite-ansible/ansible-role-zsh/commit/bcb9112)) 323 | * merge install-* files, use `package` module ([a2f89b9](https://github.com/viasite-ansible/ansible-role-zsh/commit/a2f89b9)) 324 | * powerlevel9k correct load on zsh 4.3 ([ce2f629](https://github.com/viasite-ansible/ansible-role-zsh/commit/ce2f629)) 325 | * white color in phpstorm solarized dark terminal ([422f99c](https://github.com/viasite-ansible/ansible-role-zsh/commit/422f99c)) 326 | 327 | 328 | ### Features 329 | 330 | * add naive RedHat support ([102080b](https://github.com/viasite-ansible/ansible-role-zsh/commit/102080b)) 331 | * antigen plugin manager ([80f4eab](https://github.com/viasite-ansible/ansible-role-zsh/commit/80f4eab)) 332 | * junegunn/fzf replaced with more functional ytet5uy4/fzf-widgets ([ffd2d6e](https://github.com/viasite-ansible/ansible-role-zsh/commit/ffd2d6e)) 333 | * load plugin only if command exists in system or if custom `when` is true ([e9288c2](https://github.com/viasite-ansible/ansible-role-zsh/commit/e9288c2)), closes [#2](https://github.com/viasite-ansible/ansible-role-zsh/issues/2) 334 | * zero-knowledge install.sh, docs ([d145b59](https://github.com/viasite-ansible/ansible-role-zsh/commit/d145b59)) 335 | * zsh_hotkeys with bundle dependency ([cbacc3d](https://github.com/viasite-ansible/ansible-role-zsh/commit/cbacc3d)), closes [#4](https://github.com/viasite-ansible/ansible-role-zsh/issues/4) 336 | 337 | 338 | 339 | ## [1.1.5](https://github.com/viasite-ansible/ansible-role-zsh/compare/v1.1.4...v1.1.5) (2017-03-09) 340 | 341 | 342 | ### Bug Fixes 343 | 344 | * backup .zshrc ([81e5650](https://github.com/viasite-ansible/ansible-role-zsh/commit/81e5650)) 345 | 346 | 347 | 348 | ## [1.1.4](https://github.com/viasite-ansible/ansible-role-zsh/compare/v1.1.3...v1.1.4) (2017-03-08) 349 | 350 | 351 | ### Features 352 | 353 | * zsh_autosuggestions_bind_key_2 ([368fb68](https://github.com/viasite-ansible/ansible-role-zsh/commit/368fb68)) 354 | 355 | 356 | 357 | ## [1.1.3](https://github.com/viasite-ansible/ansible-role-zsh/compare/v1.1.2...v1.1.3) (2017-03-08) 358 | 359 | 360 | ### Bug Fixes 361 | 362 | * vcs color foreground black on any color scheme ([2d0d102](https://github.com/viasite-ansible/ansible-role-zsh/commit/2d0d102)) 363 | 364 | 365 | 366 | ## [1.1.2](https://github.com/viasite-ansible/ansible-role-zsh/compare/v1.1.1...v1.1.2) (2017-03-06) 367 | 368 | 369 | ### Bug Fixes 370 | 371 | * cannot bind to an empty key sequence for 'zsh_autosuggestions_bind_key' ([94074fa](https://github.com/viasite-ansible/ansible-role-zsh/commit/94074fa)) 372 | * idempotence when update git from root to user ([092dbcc](https://github.com/viasite-ansible/ansible-role-zsh/commit/092dbcc)) 373 | * macos permissions ([232c0a9](https://github.com/viasite-ansible/ansible-role-zsh/commit/232c0a9)) 374 | * remove zsh-highlighting on --tags configure ([802fcba](https://github.com/viasite-ansible/ansible-role-zsh/commit/802fcba)) 375 | 376 | 377 | 378 | ## [1.1.1](https://github.com/viasite-ansible/ansible-role-zsh/compare/v1.1.0...v1.1.1) (2017-03-05) 379 | 380 | 381 | ### Bug Fixes 382 | 383 | * workaround for zsh-users/zsh-syntax-highlighting[#286](https://github.com/viasite-ansible/ansible-role-zsh/issues/286) ([372633b](https://github.com/viasite-ansible/ansible-role-zsh/commit/372633b)) 384 | 385 | 386 | 387 | # [1.1.0](https://github.com/viasite-ansible/ansible-role-zsh/compare/v1.0.0...v1.1.0) (2017-03-05) 388 | 389 | 390 | ### Bug Fixes 391 | 392 | * transfer ownership from popstas to viasite ([b898fe0](https://github.com/viasite-ansible/ansible-role-zsh/commit/b898fe0)) 393 | 394 | 395 | ### Features 396 | 397 | * rewrite: switch to powerlevel9k and per user files ([9ef2300](https://github.com/viasite-ansible/ansible-role-zsh/commit/9ef2300)) 398 | * rewrite: switch to powerlevel9k and per user files ([69ddc67](https://github.com/viasite-ansible/ansible-role-zsh/commit/69ddc67)) 399 | * rewrite: switch to powerlevel9k and per user files ([fa99913](https://github.com/viasite-ansible/ansible-role-zsh/commit/fa99913)) 400 | 401 | 402 | 403 | # [1.0.0](https://github.com/viasite-ansible/ansible-role-zsh/compare/1c12b96...v1.0.0) (2017-02-23) 404 | 405 | 406 | ### Bug Fixes 407 | 408 | * setup other user than ansible_remote_user ([1c12b96](https://github.com/viasite-ansible/ansible-role-zsh/commit/1c12b96)) 409 | 410 | 411 | 412 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/viasite-ansible/ansible-role-zsh.svg?branch=master)](https://travis-ci.org/viasite-ansible/ansible-role-zsh) 2 | 3 | Tested on Debian 10, Ubuntu 16.04, Ubuntu 18.04, Ubuntu 20.04, macOS 10.12, CentOS 8. 4 | 5 | **For upgrade from viasite-ansible.zsh 1.x, 2.x to 3.0 see [below](#upgrade).** 6 | 7 | 8 | 9 | ## Zero-knowledge install: 10 | If you using Ubuntu or Debian and not familiar with Ansible, you can just execute [install.sh](install.sh) on target machine: 11 | ``` 12 | curl https://raw.githubusercontent.com/viasite-ansible/ansible-role-zsh/master/install.sh | bash 13 | ``` 14 | It will install pip3, ansible and setup zsh for root and current user. 15 | 16 | Then [configure terminal application](#configure-terminal-application). 17 | 18 | 19 | ## Includes: 20 | - zsh 21 | - [antigen](https://github.com/zsh-users/antigen) 22 | - [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh) 23 | - [powerlevel9k theme](https://github.com/bhilburn/powerlevel9k) 24 | - [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) 25 | - [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting) 26 | - [unixorn/autoupdate-antigen.zshplugin](https://github.com/unixorn/autoupdate-antigen.zshplugin) 27 | - [ytet5uy4/fzf-widgets](https://github.com/ytet5uy4/fzf-widgets) 28 | - [urbainvaes/fzf-marks](https://github.com/popstas/urbainvaes/fzf-marks) 29 | 30 | ## Features 31 | - customize powerlevel9k theme prompt segments and colors 32 | - default colors tested with solarized dark and default grey terminal in putty 33 | - add custom prompt elements from yml 34 | - custom zsh config with `~/.zshrc.local` or `/etc/zshrc.local` 35 | - load `/etc/profile.d` scripts 36 | - install only plugins that useful for your machine. For example, plugin `docker` will not install if you have not Docker 37 | 38 | ## 1.5 mins demo 39 | ![1.5 mins demo](https://github.com/popstas/popstas.github.io/blob/master/images/2017-03/ansible-role-zsh-demo.gif?raw=true) 40 | 41 | ## Color schemes 42 | ![colors demo](https://github.com/popstas/popstas.github.io/blob/master/images/2017-03/ansible-role-zsh-colors.gif?raw=true) 43 | 44 | ## Midnight Commander Solarized Dark skin 45 | If you using Solarized Dark scheme and `mc`, you should want to install skin, then set `zsh_mc_solarized_skin: yes` 46 | 47 | 48 | ## Demo install in Vagrant 49 | You can test work of role before install in real machine. 50 | Just execute `vagrant up`, then `vagrant ssh` for enter in virtual machine. 51 | 52 | Note: you cannot install vagrant on VPS like Digital Ocean or in Docker. Use local machine for it. 53 | [Download](https://www.vagrantup.com/downloads.html) and install vagrant for your operating system. 54 | 55 | 56 | 57 | ## Install for real machine 58 | Zero-knowledge install: see [above](#zero-knowledge-install). 59 | 60 | ### Manual install 61 | 62 | 0. [Install Ansible](http://docs.ansible.com/ansible/intro_installation.html). 63 | For Ubuntu: 64 | ``` bash 65 | sudo apt update 66 | sudo apt install python3-pip -y 67 | sudo pip3 install ansible 68 | ``` 69 | 70 | 1. Download role: 71 | ``` 72 | ansible-galaxy install viasite-ansible.zsh --force 73 | ``` 74 | 75 | 2. Write playbook or use [playbook.yml](playbook.yml): 76 | ``` 77 | - hosts: all 78 | vars: 79 | zsh_antigen_bundles_extras: 80 | - nvm 81 | - joel-porquet/zsh-dircolors-solarized 82 | zsh_autosuggestions_bind_key: "^U" 83 | roles: 84 | - viasite-ansible.zsh 85 | ``` 86 | 87 | 3. Provision playbook: 88 | ``` 89 | ansible-playbook -i "localhost," -c local -K playbook.yml 90 | ``` 91 | 92 | If you want to provision role for root user on macOS, you should install packages manually: 93 | ``` 94 | brew install zsh git wget 95 | ``` 96 | 97 | It will install zsh environment for ansible remote user. If you want to setup zsh for other users, 98 | you should define variable `zsh_user`: 99 | 100 | Via playbook: 101 | ``` 102 | - hosts: all 103 | roles: 104 | - { role: viasite-ansible.zsh, zsh_user: otheruser } 105 | - { role: viasite-ansible.zsh, zsh_user: thirduser } 106 | ``` 107 | 108 | Or via command: 109 | ``` 110 | ansible-playbook -i hosts zsh.yml -e zsh_user=otheruser 111 | ``` 112 | 113 | 4. Install fzf **without shell extensions**, [download binary](https://github.com/junegunn/fzf-bin/releases) 114 | or `brew install fzf` for macOS. 115 | 116 | Note: I don't use `tmux-fzf` and don't tested work of it. 117 | 118 | 119 | 120 | ## Multiuser shared install 121 | If you have 10+ users on host, probably you don't want manage tens of configurations and thousands of files. 122 | 123 | In this case you can deploy single zsh config and include it to all users. 124 | 125 | It causes some limitations: 126 | 127 | - Users have read only access to zsh config 128 | - Users cannot disable global enabled bundles 129 | - Possible bugs such cache write permission denied 130 | - Possible bugs with oh-my-zsh themes 131 | 132 | For install shared configuration you should set `zsh_shared: yes`. 133 | Configuration will install to `/usr/share/zsh-config`, then you just can include to user config: 134 | 135 | ``` bash 136 | source /usr/share/zsh-config/.zshrc 137 | ``` 138 | 139 | You can still provision custom configs for several users. 140 | 141 | 142 | 143 | ## Configure 144 | You should not edit `~/.zshrc`! 145 | Add your custom config to `~/.zshrc.local` (per user) or `/etc/zshrc.local` (global). 146 | `.zshrc.local` will never touched by ansible. 147 | 148 | 149 | ### Configure terminal application 150 | 1. Download [powerline fonts](https://github.com/powerline/fonts), install font that you prefer. 151 | You can see screenshots [here](https://github.com/powerline/fonts/blob/master/samples/All.md). 152 | 153 | 2. Set color scheme. 154 | 155 | Personaly, I prefer Solarized Dark color sceme, Droid Sans Mono for Powerline in iTerm and DejaVu Sans Mono in Putty. 156 | 157 | #### iTerm 158 | Profiles - Text - Change Font - select font "for Powerline" 159 | 160 | Profiles - Colors - Color Presets... - select Solarized Dark 161 | 162 | #### Putty 163 | Settings - Window - Appearance - Font settings 164 | 165 | You can download [Solarized Dark for Putty](https://github.com/altercation/solarized/tree/master/putty-colors-solarized). 166 | 167 | #### Gnome Terminal 168 | gnome-terminal have built-in Solarized Dark, note that you should select both background color scheme and palette scheme. 169 | 170 | 171 | 172 | ### Hotkeys 173 | You can view hotkeys in [defaults/main.yml](defaults/main.yml), `zsh_hotkeys`. 174 | 175 | Sample hotkey definitions: 176 | ``` yaml 177 | - { hotkey: '^r', action: 'fzf-history' } 178 | # with dependency of bundle 179 | - { hotkey: '`', action: autosuggest-accept, bundle: zsh-users/zsh-autosuggestions } 180 | ``` 181 | 182 | Useful to set `autosuggest-accept` to ` hotkey, but it conflicts with Midnight Commander (break Ctrl+O subshell). 183 | 184 | You can add your custom hotkeys without replace default hotkeys with `zsh_hotkeys_extras` variable: 185 | ``` yaml 186 | zsh_hotkeys_extras: 187 | - { hotkey: '^[^[[D', action: backward-word } # alt+left 188 | - { hotkey: '^[^[[C', action: forward-word } # alt+right 189 | # Example inserts 2nd argument from end of prev. cmd 190 | - { hotkey: '^[,', action: copy-earlier-word } # ctrl+, 191 | ``` 192 | 193 | ### Aliases 194 | You can use aliases for your command with easy deploy. 195 | Aliases config mostly same as hotkeys config: 196 | 197 | ``` yaml 198 | zsh_aliases: 199 | - { alias: 'dfh', action: 'df -h | grep -v docker' } 200 | # with dependency of bundle and without replace default asiases 201 | - zsh_aliases_extra 202 | - { alias: 'dfh', action: 'df -h | grep -v docker', bundle: } 203 | ``` 204 | 205 | #### Default hotkeys from plugins: 206 | - - accept autosuggestion 207 | - Ctrl+Z - move current application to background, press again for return to foreground 208 | - Ctrl+G - jump to bookmarked directory. Use `mark` in directory for add to bookmarks 209 | - Ctrl+R - show command history 210 | - Ctrl+@ - show all fzf-widgets 211 | - Ctrl+@,C - fzf-change-dir, press fast! 212 | - Ctrl+\\ - fzf-change-recent-dir 213 | - Ctrl+@,G - fzf-change-repository 214 | - Ctrl+@,F - fzf-edit-files 215 | - Ctrl+@,. - fzf-edit-dotfiles 216 | - Ctrl+@,S - fzf-exec-ssh (using your ~/.ssh/config) 217 | - Ctrl+@,G,A - fzf-git-add-file 218 | - Ctrl+@,G,B - fzf-git-checkout-branch 219 | - Ctrl+@,G,D - fzf-git-delete-branches 220 | 221 | 222 | 223 | ## Configure bundles 224 | You can check default bundles in [defaults/main.yml](defaults/main.yml#L37). 225 | If you like default bundles, but you want to add your bundles, use `zsh_antigen_bundles_extras` variable (see example playbook above). 226 | If you want to remove some default bundles, you should use `zsh_antigen_bundles` variable. 227 | 228 | Format of list matches [antigen](https://github.com/zsh-users/antigen#antigen-bundle). All bellow variants valid: 229 | ``` yaml 230 | - docker # oh-my-zsh plugin 231 | - zsh-users/zsh-autosuggestions # plugin from github 232 | - zsh-users/zsh-autosuggestions@v0.3.3 # plugin from github with fixed version 233 | - ~/projects/zsh/my-plugin --no-local-clone # plugin from local directory 234 | ``` 235 | 236 | Note that bundles can use conditions for load. There are two types of conditions: 237 | 238 | 1. Command conditions. Just add `command` to bundle: 239 | ``` yaml 240 | - { name: docker, command: docker } 241 | - name: docker-compose 242 | command: docker-compose 243 | ``` 244 | Bundles `docker` and `docker-compose` will be added to config only if commands exists on target system. 245 | 246 | 2. When conditions. You can define any ansible conditions as you define in `when` in tasks: 247 | ``` yaml 248 | # load only for zsh >= 4.3.17 249 | - name: zsh-users/zsh-syntax-highlighting 250 | when: "{{ zsh_version is version_compare('4.3.17', '>=') }}" 251 | # load only for macOS 252 | - { name: brew, when: "{{ ansible_os_family != 'Darwin' }}" } 253 | ``` 254 | Note: you should wrap condition in `"{{ }}"` 255 | 256 | 257 | 258 | ## Upgrade 259 | viasite-ansible.zsh v3.0 introduces antigen v2.0, it don't have backward compatibility to antigen 1.x. 260 | 261 | I don't spent much time for smooth upgrade, therefore you probably should do some manual actions: 262 | if powerlevel9k prompt don't loaded after provision role, you should execute `antigen reset`. 263 | 264 | After reopen shell all should be done. 265 | 266 | ### Downgrade to antigen v1 267 | Antigen v2 much faster (up to 2x more faster startup), but if something went wrong, you can downgrade to antigen v1, 268 | see note for zsh 4.3 users below. 269 | 270 | ### For users with zsh 4.x 271 | Antigen v2 not work on zsh < 5.0, if you use zsh 4.x, please add to you playbook: 272 | ``` yaml 273 | zsh_antigen_version: v1.4.1 274 | ``` 275 | 276 | 277 | ## Known bugs 278 | ### `su username` caused errors 279 | See [antigen issue](https://github.com/zsh-users/antigen/issues/136). 280 | If both root and su user using antigen, you should use `su - username` in place of `su username`. 281 | 282 | Or you can use bundled alias `suser`. 283 | 284 | Also, you can try to fix it, add to `~/.zshrc.local`: 285 | ``` 286 | alias su='su -' 287 | ``` 288 | But this alias can break you scripts, that using `su`. 289 | 290 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/Vagrantfile: -------------------------------------------------------------------------------- 1 | $VM_BOX = 'bento/ubuntu-16.04' 2 | 3 | Vagrant.configure('2') do |config| 4 | config.vm.box = $VM_BOX 5 | 6 | config.vm.provision "ansible" do |ansible| 7 | ansible.extra_vars = { ansible_ssh_user: 'vagrant', vagrant: true, zsh_user: 'vagrant' } 8 | ansible.sudo = true 9 | ansible.playbook = 'tests/vagrant.yml' 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | zsh_user: "{{ ansible_user_id }}" 4 | 5 | # .zshrc config 6 | zsh_hist_stamps: yyyy-mm-dd 7 | zsh_share_history: no 8 | zsh_update_interval: 30 # set 0 for disable autoupdates 9 | zsh_editor: vim 10 | zsh_term: xterm-256color 11 | zsh_mc_solarized_skin: no 12 | 13 | zsh_path: 14 | - "{{ zsh_fzf_path }}" 15 | - /usr/local/sbin 16 | - /usr/local/bin 17 | - /usr/sbin 18 | - /usr/bin 19 | - /sbin 20 | - /bin 21 | - /usr/games 22 | - /usr/local/games 23 | 24 | zsh_load_etc_profile: yes 25 | 26 | fzf_widgets: ytet5uy4/fzf-widgets 27 | 28 | zsh_antigen_version: master 29 | zsh_fzf_version: 0.17.4 30 | 31 | zsh_antigen_bundles: 32 | - { name: command-not-found, when: "{{ ansible_os_family != 'Darwin' }}" } # too slow on OSX 33 | - { name: brew, command: brew } 34 | - { name: docker, command: docker } 35 | - { name: docker-compose, command: docker-compose } 36 | - fancy-ctrl-z 37 | - git-extras 38 | - gnu-utils 39 | - { name: httpie, command: http } 40 | - { name: golang, command: go } 41 | - { name: gulp, command: gulp } 42 | - { name: helm, command: helm } 43 | - { name: kubectl, command: kubectl } 44 | - { name: pip, command: pip } 45 | - { name: rake, command: rake } 46 | - { name: symfony2, command: symfony } 47 | - { name: systemd, command: systemctl } 48 | - python 49 | - { name: tmux, command: tmux } 50 | - { name: vagrant, command: vagrant } 51 | - { name: viasite/drall, command: drall } 52 | - { name: viasite/drupal-scripts, command: drs } 53 | - { name: viasite/server-scripts, command: dbdump } 54 | - { name: viasite-ansible/zsh-ansible-server, command: ansible-deploy } 55 | - zsh_reload 56 | 57 | # on zsh 4.3.10 autosuggestions breaks multiline commands with \ 58 | - { name: zsh-users/zsh-autosuggestions, when: "{{ zsh_version is version_compare('5.0', '>=') }}" } 59 | - popstas/zsh-command-time 60 | - { name: unixorn/autoupdate-antigen.zshplugin, when: "{{ zsh_update_interval > 0 }}" } 61 | - urbainvaes/fzf-marks # replaces jump plugin, mark, jump and Ctrl+G 62 | - "{{ fzf_widgets }}" 63 | # must be last, don't work on zsh < 4.3.17 64 | #- { name: zsh-users/zsh-syntax-highlighting, when: "{{ zsh_version | default(false) is version_compare('4.3.17', '>=') }}" } 65 | # bug with text paste in fast-syntax-highlighting v1.21, see https://github.com/zdharma/fast-syntax-highlighting/issues/30 66 | - { name: zdharma/fast-syntax-highlighting@v1.2, when: "{{ zsh_version is version_compare('4.3.17', '>=') }}" } 67 | 68 | zsh_antigen_bundles_extras: [] 69 | 70 | # useful for deploy many zsh users at host, without duplicate and without write access 71 | zsh_shared: no 72 | zsh_change_user_shell: yes 73 | 74 | zsh_antigen_theme: "bhilburn/powerlevel9k powerlevel9k" 75 | 76 | zsh_hotkeys: 77 | # home & end keys work 78 | - { hotkey: '\e[1~', action: beginning-of-line } 79 | - { hotkey: '\e[4~', action: end-of-line } 80 | 81 | # fzf-widgets 82 | - { hotkey: '^@' , action: fzf-select-widget, bundle: "{{ fzf_widgets }}" } 83 | - { hotkey: '^@.' , action: fzf-edit-dotfiles, bundle: "{{ fzf_widgets }}" } 84 | - { hotkey: '^@c', action: fzf-change-directory, bundle: "{{ fzf_widgets }}" } 85 | - { hotkey: '^@f', action: fzf-edit-files, bundle: "{{ fzf_widgets }}" } 86 | - { hotkey: '^@k', action: fzf-kill-processes, bundle: "{{ fzf_widgets }}" } 87 | - { hotkey: '^@s', action: fzf-exec-ssh, bundle: "{{ fzf_widgets }}" } 88 | - { hotkey: '^\' , action: fzf-change-recent-directory, bundle: "{{ fzf_widgets }}" } 89 | - { hotkey: '^r', action: fzf-insert-history, bundle: "{{ fzf_widgets }}" } 90 | - { hotkey: '^xf', action: fzf-insert-files, bundle: "{{ fzf_widgets }}" } 91 | - { hotkey: '^xd', action: fzf-insert-directory, bundle: "{{ fzf_widgets }}" } 92 | 93 | # fzf-widgets: Git 94 | - { hotkey: '^@g', action: fzf-select-git-widget, bundle: "{{ fzf_widgets }}" } 95 | - { hotkey: '^@ga', action: fzf-git-add-files, bundle: "{{ fzf_widgets }}" } 96 | - { hotkey: '^@gc', action: fzf-git-change-repository, bundle: "{{ fzf_widgets }}" } 97 | - { hotkey: '^@gco', action: fzf-git-checkout-branch, bundle: "{{ fzf_widgets }}" } 98 | - { hotkey: '^@gd', action: fzf-git-delete-branches, bundle: "{{ fzf_widgets }}" } 99 | 100 | # fzf-widgets: GitHub 101 | - { hotkey: '^@gh', action: fzf-select-github-widget, bundle: "{{ fzf_widgets }}" } 102 | - { hotkey: '^@ghi', action: fzf-github-show-issue, bundle: "{{ fzf_widgets }}" } 103 | - { hotkey: '^@ghe', action: fzf-github-edit-issue, bundle: "{{ fzf_widgets }}" } 104 | - { hotkey: '^@gho', action: fzf-github-open-issue, bundle: "{{ fzf_widgets }}" } 105 | - { hotkey: '^@ghc', action: fzf-github-close-issue, bundle: "{{ fzf_widgets }}" } 106 | - { hotkey: '^@ghco', action: fzf-github-comment-issue, bundle: "{{ fzf_widgets }}" } 107 | 108 | # fzf-widgets: Docker 109 | - { hotkey: '^@d', action: fzf-select-docker-widget, bundle: "{{ fzf_widgets }}" } 110 | - { hotkey: '^@dk', action: fzf-docker-kill-containers, bundle: "{{ fzf_widgets }}" } 111 | - { hotkey: '^@dl', action: fzf-docker-logs-container, bundle: "{{ fzf_widgets }}" } 112 | - { hotkey: '^@dr', action: fzf-docker-remove-containers, bundle: "{{ fzf_widgets }}" } 113 | - { hotkey: '^@dri', action: fzf-docker-remove-images, bundle: "{{ fzf_widgets }}" } 114 | - { hotkey: '^@drv', action: fzf-docker-remove-volumes, bundle: "{{ fzf_widgets }}" } 115 | - { hotkey: '^@dsa', action: fzf-docker-start-containers, bundle: "{{ fzf_widgets }}" } 116 | - { hotkey: '^@dso', action: fzf-docker-stop-containers, bundle: "{{ fzf_widgets }}" } 117 | 118 | # autosuggestions 119 | - { hotkey: '{{ zsh_autosuggestions_bind_key }}', action: autosuggest-accept, bundle: zsh-users/zsh-autosuggestions } 120 | - { hotkey: '{{ zsh_autosuggestions_bind_key_2 }}', action: autosuggest-accept, bundle: zsh-users/zsh-autosuggestions } 121 | 122 | zsh_hotkeys_extras: [] 123 | 124 | # only single quotes allowed in action 125 | zsh_aliases: 126 | - { alias: 'apt-update-list-upgrade', action: 'apt update && apt upgrade --dry-run | grep Inst | sort | fzf && apt upgrade' } 127 | - { alias: 'dfh', action: 'df -h | grep -v docker' } 128 | - { alias: 'ubuntu-release', action: 'lsb_release -a' } 129 | - { alias: '', action: '' } 130 | 131 | 132 | # zsh-autosuggestions 133 | zsh_autosuggestions_max_length: 15 134 | zsh_autosuggestions_bind_key: "" 135 | zsh_autosuggestions_bind_key_2: "" 136 | 137 | # fzf 138 | zsh_fzf_path: "$HOME/bin" 139 | zsh_fzf_height: "100%" 140 | zsh_fzf_reverse: yes 141 | zsh_fzf_border: no 142 | zsh_fzf_ctrl_r_opts: '--exact' 143 | 144 | # command-time 145 | zsh_command_time_min_seconds: 3 146 | zsh_command_time_echo: "" 147 | 148 | # powerlevel9k 149 | zsh_powerlevel9k_left_prompt: 150 | - context 151 | - dir 152 | 153 | zsh_powerlevel9k_right_prompt: 154 | - status 155 | - background_jobs 156 | - vcs 157 | - command_execution_time 158 | - time 159 | 160 | zsh_powerlevel_custom_elements: 161 | - name: command_time 162 | command: "zsh_command_time" 163 | background: "248" 164 | foreground: "000" 165 | 166 | zsh_powerlevel9k_hide_host_on_local: yes 167 | zsh_powerlevel9k_always_show_context: no # hide hostname and username from prompt on local machine 168 | zsh_powerlevel9k_always_show_user: no # hide username from prompt on local machine 169 | zsh_powerlevel9k_prompt_on_newline: no 170 | zsh_powerlevel9k_shorten_dir_length: 3 171 | zsh_powerlevel9k_status_verbose: 0 172 | 173 | # dir (context) colors 174 | zsh_powerlevel9k_context_default_foreground: "255" # white 175 | zsh_powerlevel9k_context_default_background: "024" # blue 176 | zsh_powerlevel9k_context_root_foreground: "255" # white 177 | zsh_powerlevel9k_context_root_background: "124" # red 178 | zsh_powerlevel9k_dir_foreground: "255" # white 179 | zsh_powerlevel9k_dir_background: "240" # gray 180 | zsh_powerlevel9k_dir_etc_foreground: "{{ zsh_powerlevel9k_dir_foreground }}" 181 | zsh_powerlevel9k_dir_etc_background: "{{ zsh_powerlevel9k_dir_background }}" 182 | zsh_powerlevel9k_dir_path_highlight_foreground: "{{ zsh_powerlevel9k_dir_foreground }}" 183 | zsh_powerlevel9k_dir_path_highlight_background: "{{ zsh_powerlevel9k_dir_background }}" 184 | 185 | # vcs colors 186 | zsh_powerlevel9k_vcs_foreground: "232" # about black on any palette 187 | zsh_powerlevel9k_vcs_clean_background: "100" # dirty green 188 | zsh_powerlevel9k_vcs_modified_background: "094" # orange 189 | zsh_powerlevel9k_vcs_untracked_background: "094" # orange 190 | 191 | # command execution time 192 | zsh_powerlevel9k_command_execution_time_foreground: "000" 193 | zsh_powerlevel9k_command_execution_time_background: "248" 194 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | title() { 5 | local color='\033[1;37m' 6 | local nc='\033[0m' 7 | printf "\n${color}$1${nc}\n" 8 | } 9 | 10 | title "Install pip and Ansible" 11 | sudo apt update 12 | sudo apt install python3-pip -y 13 | sudo pip3 install ansible 14 | 15 | title "Install viasite-ansible.zsh" 16 | ansible-galaxy install viasite-ansible.zsh --force 17 | 18 | title "Download playbook to /tmp/zsh.yml" 19 | curl https://raw.githubusercontent.com/viasite-ansible/ansible-role-zsh/master/playbook.yml > /tmp/zsh.yml 20 | 21 | title "Provision playbook for root" 22 | ansible-playbook -i "localhost," -c local -b /tmp/zsh.yml 23 | 24 | title "Provision playbook for $(whoami)" 25 | ansible-playbook -i "localhost," -c local -b /tmp/zsh.yml --extra-vars="zsh_user=$(whoami)" 26 | 27 | title "Finished! Please, restart your shell." 28 | echo "" 29 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/meta/.galaxy_install_info: -------------------------------------------------------------------------------- 1 | install_date: Mon Feb 8 11:41:50 2021 2 | version: v3.3.2 3 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Stanislav Popov 4 | company: Viasite 5 | description: oh-my-zsh with powerlevel9k theme, fzf and other plugins 6 | license: MIT 7 | min_ansible_version: 2.0 8 | platforms: 9 | - name: Ubuntu 10 | versions: 11 | - trusty 12 | - xenial 13 | - name: Debian 14 | versions: 15 | - squeeze 16 | - wheezy 17 | - jessie 18 | - name: EL 19 | versions: 20 | - 7 21 | - name: MacOSX 22 | versions: 23 | - 10.12 24 | galaxy_tags: 25 | - system 26 | - shell 27 | - user 28 | - zsh 29 | dependencies: [] -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: docker 4 | platforms: 5 | - name: ansible-role-zsh-debian-10 6 | image: geerlingguy/docker-debian10-ansible 7 | pre_build_image: true 8 | 9 | - name: ansible-role-zsh-1604 10 | image: geerlingguy/docker-ubuntu1604-ansible 11 | pre_build_image: true 12 | 13 | - name: ansible-role-zsh-1804 14 | image: geerlingguy/docker-ubuntu1804-ansible 15 | pre_build_image: true 16 | 17 | - name: ansible-role-zsh-2004 18 | image: geerlingguy/docker-ubuntu2004-ansible 19 | pre_build_image: true 20 | 21 | - name: ansible-role-zsh-centos-8 22 | image: geerlingguy/docker-centos8-ansible 23 | 24 | #driver: 25 | # name: vagrant 26 | # provider: 27 | # name: virtualbox 28 | #platforms: 29 | # - name: xenial64 30 | # box: bento/ubuntu-16.04 31 | 32 | #verifier: 33 | # name: testinfra 34 | 35 | provisioner: 36 | name: ansible 37 | playbooks: 38 | prepare: ../resources/prepare.yml 39 | converge: ../resources/converge.yml 40 | inventory: 41 | group_vars: 42 | all: 43 | zsh_user: root 44 | zsh_mc_solarized_skin: yes 45 | zsh_antigen_bundles_extras: 46 | - { name: test/in-list, when: true } 47 | - { name: test/not-in-list, when: false } 48 | - { name: test/command-exists, command: zsh } 49 | - { name: test/command-not-exists, command: not-exists-commanddd } 50 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/molecule/default/tests/test_default.py: -------------------------------------------------------------------------------- 1 | import os 2 | import testinfra.utils.ansible_runner 3 | 4 | testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( 5 | os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') 6 | 7 | 8 | def test_bundles_when(host): 9 | c = host.file('/root/.zshrc').content 10 | assert 'test/in-list' in c 11 | assert 'test/not-in-list' not in c 12 | 13 | 14 | def test_bundles_command(host): 15 | c = host.file('/root/.zshrc').content 16 | assert 'test/command-exists' in c 17 | assert 'test/command-not-exists' not in c 18 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/molecule/resources/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | roles: 4 | - ansible-role-zsh 5 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/molecule/resources/prepare.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Prepare 3 | hosts: all 4 | gather_facts: False 5 | tasks: 6 | - name: apt-proxy 7 | copy: 8 | content: "Acquire::http::Proxy \"{{ lookup('env', 'APT_PROXY') }}\"; Acquire::https::Proxy \"false\";" 9 | dest: /etc/apt/apt.conf.d/01proxy 10 | failed_when: False 11 | - name: Update apt cache 12 | package: 13 | update_cache: yes 14 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/molecule/shared/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | scenario: 3 | name: shared 4 | driver: 5 | name: docker 6 | platforms: 7 | - name: ansible-role-zsh-debian-10 8 | image: geerlingguy/docker-debian10-ansible 9 | pre_build_image: true 10 | 11 | - name: ansible-role-zsh-1604 12 | image: geerlingguy/docker-ubuntu1604-ansible 13 | pre_build_image: true 14 | 15 | - name: ansible-role-zsh-1804 16 | image: geerlingguy/docker-ubuntu1804-ansible 17 | pre_build_image: true 18 | 19 | - name: ansible-role-zsh-2004 20 | image: geerlingguy/docker-ubuntu2004-ansible 21 | pre_build_image: true 22 | 23 | - name: ansible-role-zsh-centos-8 24 | image: geerlingguy/docker-centos8-ansible 25 | 26 | provisioner: 27 | name: ansible 28 | playbooks: 29 | prepare: ../resources/prepare.yml 30 | converge: ../resources/converge.yml 31 | inventory: 32 | group_vars: 33 | all: 34 | zsh_shared: yes 35 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/molecule/user/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | scenario: 3 | name: user 4 | driver: 5 | name: docker 6 | platforms: 7 | - name: ansible-role-zsh-debian-10 8 | image: geerlingguy/docker-debian10-ansible 9 | pre_build_image: true 10 | 11 | - name: ansible-role-zsh-1604 12 | image: geerlingguy/docker-ubuntu1604-ansible 13 | pre_build_image: true 14 | 15 | - name: ansible-role-zsh-1804 16 | image: geerlingguy/docker-ubuntu1804-ansible 17 | pre_build_image: true 18 | 19 | - name: ansible-role-zsh-2004 20 | image: geerlingguy/docker-ubuntu2004-ansible 21 | pre_build_image: true 22 | 23 | - name: ansible-role-zsh-centos-8 24 | image: geerlingguy/docker-centos8-ansible 25 | 26 | provisioner: 27 | name: ansible 28 | playbooks: 29 | prepare: prepare.yml 30 | converge: ../resources/converge.yml 31 | inventory: 32 | group_vars: 33 | all: 34 | zsh_user: testuser 35 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/molecule/user/prepare.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Prepare 3 | hosts: all 4 | gather_facts: False 5 | tasks: 6 | - name: apt-proxy 7 | copy: 8 | content: "Acquire::http::Proxy \"{{ lookup('env', 'APT_PROXY') }}\"; Acquire::https::Proxy \"false\";" 9 | dest: /etc/apt/apt.conf.d/01proxy 10 | failed_when: False 11 | 12 | - name: create testuser 13 | user: 14 | name: testuser 15 | home: /home/testuser 16 | shell: /bin/bash 17 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | vars: 4 | # your extra bundles here 5 | zsh_antigen_bundles_extras: [] 6 | # your variables here 7 | zsh_autosuggestions_bind_key: "^U" 8 | roles: 9 | - viasite-ansible.zsh 10 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/scripts/generate-changelog: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HELP=" 4 | 1. If github branch exists, 5 | rename origin to origin_origin, 6 | rename copy github to origin. 7 | 8 | 2. Generate CHANGELOG.md 9 | 10 | 3. Reverts all branch operations at step 1 11 | " 12 | 13 | IS_BRANCH_RENAME=$(git remote | grep -c github) 14 | 15 | # 1. 16 | if [ "$IS_BRANCH_RENAME" = "1" ]; then 17 | git remote rename origin origin_origin 18 | git remote rename github origin 19 | fi 20 | 21 | # 2. 22 | conventional-changelog -p angular -o CHANGELOG.md -r 0 23 | sed -i.bak 's/# \[\]/# [master]/g' CHANGELOG.md 24 | rm CHANGELOG.md.bak 25 | git add CHANGELOG.md 26 | 27 | # 3. 28 | if [ "$IS_BRANCH_RENAME" = "1" ]; then 29 | git remote rename origin github 30 | git remote rename origin_origin origin 31 | fi 32 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/tasks/configure.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Check zsh version 4 | shell: "set -o pipefail; zsh --version | cut -d ' ' -f2" 5 | args: 6 | executable: /bin/bash 7 | register: zsh_register_version 8 | check_mode: no 9 | changed_when: false 10 | tags: configure 11 | 12 | - name: Set zsh_version variable 13 | set_fact: 14 | zsh_version: "{{ zsh_register_version.stdout }}" 15 | 16 | - name: Merge bundles lists 17 | set_fact: 18 | zsh_antigen_bundles: "{{ zsh_antigen_bundles }} + {{ zsh_antigen_bundles_extras }}" 19 | 20 | - name: Disable autoupdate if zsh_shared install 21 | set_fact: 22 | zsh_update_interval: 0 23 | when: zsh_shared 24 | 25 | - name: Check commands exists 26 | shell: "command -v {{ item.command }} || which {{ item.command }}" 27 | with_items: "{{ zsh_antigen_bundles }}" 28 | failed_when: false 29 | changed_when: false 30 | check_mode: no 31 | when: item.command is defined 32 | register: zsh_register_commands_exists 33 | 34 | - name: Merge hotkeys lists 35 | set_fact: 36 | zsh_hotkeys: "{{ zsh_hotkeys }} + {{ zsh_hotkeys_extras }}" 37 | 38 | - name: Check antigen version 39 | shell: | 40 | set -o pipefail 41 | cat "{{ zsh_antigen_path }}/antigen/VERSION" | tr -d 'v' 42 | args: 43 | executable: /bin/bash 44 | register: zsh_register_antigen_version 45 | changed_when: false 46 | failed_when: false 47 | check_mode: no 48 | tags: configure 49 | 50 | - name: Set zsh_antigen_installed_version variable 51 | set_fact: 52 | zsh_antigen_installed_version: "{{ zsh_register_antigen_version.stdout }}" 53 | 54 | - name: Write .zshrc config 55 | template: 56 | src: zshrc.j2 57 | dest: "{{ zsh_config }}" 58 | owner: "{{ zsh_user }}" 59 | group: "{{ zsh_user_group }}" 60 | backup: yes 61 | 62 | - name: Set zsh as default shell 63 | user: 64 | name: "{{ zsh_user }}" 65 | shell: /bin/zsh 66 | become: true 67 | when: not zsh_shared and zsh_change_user_shell 68 | 69 | - name: Add skip_global_compinit for disable early compinit call in Ubuntu 70 | lineinfile: 71 | regexp: "skip_global_compinit=1" 72 | line: "skip_global_compinit=1" 73 | dest: /etc/zsh/zshenv 74 | state: present 75 | when: ansible_distribution == 'Ubuntu' 76 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/tasks/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Update package cache 4 | package: 5 | update_cache: yes 6 | when: ansible_os_family != 'Darwin' 7 | 8 | - name: Install zsh, git, wget 9 | package: 10 | name: 11 | - zsh 12 | - git 13 | - wget 14 | state: present 15 | # brew don't work from root user on macOS 16 | when: not (zsh_user == 'root' and ansible_os_family == 'Darwin') 17 | 18 | - name: Clone antigen {{ zsh_antigen_version }} 19 | git: 20 | repo: https://github.com/zsh-users/antigen.git 21 | dest: "{{ zsh_antigen_path }}/antigen" 22 | version: "{{ zsh_antigen_version }}" 23 | force: yes 24 | become: yes 25 | become_user: "{{ zsh_user }}" 26 | register: zsh_register_antigen_clone 27 | 28 | - name: Clone iwfmp/mc-solarized-skin 29 | git: 30 | repo: https://github.com/iwfmp/mc-solarized-skin.git 31 | version: master 32 | dest: "~{{ zsh_user }}/.mc/lib/mc-solarized" 33 | force: yes 34 | become: yes 35 | become_user: "{{ zsh_user }}" 36 | when: zsh_mc_solarized_skin and not zsh_shared 37 | 38 | - name: Check fzf installed 39 | command: which fzf 40 | changed_when: false 41 | failed_when: false 42 | check_mode: no 43 | register: zsh_register_fzf_command 44 | 45 | - name: Set zsh_fzf_path to /usr/local/bin 46 | set_fact: 47 | zsh_fzf_path: /usr/local/bin 48 | changed_when: false 49 | when: zsh_shared 50 | 51 | - name: Set zsh_fzf_path_absolute 52 | set_fact: 53 | zsh_fzf_path_absolute: "{{ zsh_fzf_path | replace('$HOME', '~' + zsh_user) }}" 54 | changed_when: false 55 | 56 | - name: Ensure users home binary folder is present 57 | file: 58 | path: "{{ zsh_fzf_path_absolute }}" 59 | owner: "{{ zsh_user }}" 60 | group: "{{ zsh_user_group }}" 61 | mode: u=rwx,g=rwx,o=rx 62 | state: directory 63 | when: not zsh_shared 64 | 65 | - name: "Download fzf to {{ zsh_fzf_path_absolute }}" 66 | unarchive: 67 | src: "{{ zsh_fzf_url }}" 68 | dest: "{{ zsh_fzf_path_absolute }}" 69 | remote_src: yes 70 | creates: "{{ zsh_fzf_path_absolute }}/fzf" 71 | when: zsh_register_fzf_command.rc == 1 72 | 73 | - name: Set directory permissions 74 | file: 75 | name: "{{ zsh_antigen_path }}" 76 | owner: "{{ zsh_user }}" 77 | group: "{{ zsh_user_group }}" 78 | recurse: yes 79 | changed_when: false 80 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - include: install.yml 4 | tags: [ zsh, install ] 5 | 6 | - include: configure.yml 7 | tags: [ zsh, configure ] 8 | 9 | - include: post-install.yml 10 | tags: [ zsh, install, post_install ] 11 | 12 | - name: Reset antigen cache 13 | command: "/bin/zsh -c 'source {{ zsh_config }}; antigen reset'" 14 | become: yes 15 | become_user: "{{ zsh_user }}" 16 | changed_when: false 17 | failed_when: false 18 | tags: always 19 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/tasks/post-install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Reset antigen cache 3 | command: "/bin/zsh -c 'source {{ zsh_config }}; antigen reset'" 4 | become: yes 5 | become_user: "{{ zsh_user }}" 6 | changed_when: false 7 | failed_when: false 8 | 9 | # it will fail, but it install all bundles for user 10 | - name: Update antigen bundles 11 | command: "/bin/zsh -c 'source {{ zsh_config }}; antigen update'" 12 | become: yes 13 | become_user: "{{ zsh_user }}" 14 | changed_when: false 15 | failed_when: false 16 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/templates/zshrc.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # zsh version: {{ zsh_version }} 3 | # antigen version: {{ zsh_antigen_installed_version }} 4 | 5 | export TERM="{{ zsh_term }}" 6 | export EDITOR="{{ zsh_editor }}" 7 | export PATH="$PATH:{{ zsh_path | join(":") }}" 8 | 9 | HIST_STAMPS="{{ zsh_hist_stamps }}" 10 | UPDATE_ZSH_DAYS="{{ zsh_update_interval }}" 11 | COMPLETION_WAITING_DOTS="true" 12 | 13 | # ADOTDIR="{{ zsh_antigen_path_compat }}" 14 | {% if zsh_shared %} 15 | ANTIGEN_AUTO_CONFIG=false # disable updates 16 | _ANTIGEN_THEME_COMPAT=false # disable theme cache 17 | {% endif %} 18 | 19 | ANTIGEN_BUNDLES="{{ zsh_antigen_path_compat }}/bundles" 20 | ANTIGEN_PLUGIN_UPDATE_DAYS="{{ zsh_update_interval }}" 21 | ANTIGEN_SYSTEM_UPDATE_DAYS="{{ zsh_update_interval }}" 22 | 23 | {% if zsh_mc_solarized_skin %}export MC_SKIN="$HOME/.mc/lib/mc-solarized/solarized.ini"{% endif %} 24 | 25 | source "{{ zsh_antigen_path_compat }}/antigen/antigen.zsh" 26 | 27 | antigen use oh-my-zsh 28 | 29 | {% set bundles_enabled = [] %} 30 | 31 | {% for bundle in zsh_antigen_bundles -%} 32 | {%- if bundle is mapping -%} 33 | {% set valid = true -%} 34 | {% set command_not_exists = [] -%} 35 | 36 | {%- if bundle.when is defined and not bundle.when -%} 37 | {% set valid = false -%} 38 | {% endif -%} 39 | 40 | {% if bundle.command is defined -%} 41 | {% for cmd in zsh_register_commands_exists.results -%} 42 | {% if cmd.cmd is defined and cmd.rc != 0 and cmd.item.command == bundle.command -%} 43 | {% if command_not_exists.append(1) %}{% endif -%} 44 | {% endif -%} 45 | {% endfor -%} 46 | {% endif -%} 47 | 48 | {% if valid and not command_not_exists %} 49 | {%- if 'zsh-syntax-highlighting' in bundle.name or 'fast-syntax-highlighting' in bundle.name -%} 50 | # will fixed in zsh-autosuggestion v0.4 - https://github.com/zsh-users/zsh-autosuggestions/pull/218 51 | if (( ZSHRC_LOAD_ONCE++ == 0 )); then 52 | antigen bundle {{ bundle.name }} 53 | fi 54 | {% else -%} 55 | {% if bundles_enabled.append(bundle.name) %}{% endif -%} 56 | antigen bundle {{ bundle.name }} 57 | {% endif -%} 58 | {% endif -%} 59 | {%- else -%} 60 | {% if bundles_enabled.append(bundle) %}{% endif -%} 61 | antigen bundle {{ bundle }} 62 | {% endif %} 63 | {% endfor %} 64 | 65 | POWERLEVEL9K_INSTALLATION_PATH=$ANTIGEN_BUNDLES/bhilburn/powerlevel9k/powerlevel9k.zsh-theme 66 | 67 | antigen theme {{ zsh_antigen_theme }} 68 | 69 | antigen apply 70 | 71 | ### 72 | 73 | {% if not zsh_share_history %} 74 | unsetopt share_history 75 | {% endif %} 76 | 77 | 78 | autoload -Uz copy-earlier-word 79 | zle -N copy-earlier-word 80 | 81 | # hotkeys 82 | {% for hotkey in zsh_hotkeys %} 83 | {% if hotkey.hotkey != '' and (hotkey.bundle is not defined or hotkey.bundle in bundles_enabled) %} 84 | bindkey '{{ hotkey.hotkey }}' {{ hotkey.action }} 85 | {% endif %} 86 | {% endfor %} 87 | 88 | # aliases 89 | {% for alias in zsh_aliases %} 90 | {% if alias.alias != '' and (alias.bundle is not defined or alias.bundle in bundles_enabled) %} 91 | alias '{{ alias.alias }}'="{{ alias.action }}" 92 | {% endif %} 93 | {% endfor %} 94 | 95 | # fzf 96 | export FZF_TMUX=0 97 | export FZF_DEFAULT_OPTS="{{ zsh_fzf_default_opts }}" 98 | 99 | # fzf-widgets: fzf-change-reset-dir 100 | {% if zsh_version is version_compare('5.0', '>=') -%} 101 | autoload -Uz chpwd_recent_dirs cdr add-zsh-hook 102 | add-zsh-hook chpwd chpwd_recent_dirs 103 | {% endif %} 104 | declare -p FZF_WIDGETS_OPTS > /dev/null 2>&1 && FZF_WIDGETS_OPTS[insert-history]="{{ zsh_fzf_ctrl_r_opts }}" 105 | declare -p FZF_WIDGET_OPTS > /dev/null 2>&1 && FZF_WIDGET_OPTS[insert-history]="{{ zsh_fzf_ctrl_r_opts }}" 106 | 107 | # zsh-autosuggestions 108 | ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE={{ zsh_autosuggestions_max_length }} 109 | ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=240" # gray highlight 110 | 111 | # powerlevel9k 112 | POWERLEVEL9K_SHORTEN_DIR_LENGTH={{ zsh_powerlevel9k_shorten_dir_length }} 113 | POWERLEVEL9K_STATUS_VERBOSE={{ zsh_powerlevel9k_status_verbose }} 114 | 115 | POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=({{ zsh_powerlevel9k_left_prompt | join(" ") }}) 116 | POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=({{ zsh_powerlevel9k_right_prompt | join(" ") }}) 117 | {% if zsh_powerlevel9k_hide_host_on_local and zsh_user != 'root' %}DEFAULT_USER=$USER{% endif %} 118 | 119 | POWERLEVEL9K_ALWAYS_SHOW_CONTEXT={{ zsh_powerlevel9k_always_show_context_bool }} 120 | POWERLEVEL9K_ALWAYS_SHOW_USER={{ zsh_powerlevel9k_always_show_user_bool }} 121 | 122 | {% if zsh_powerlevel_custom_elements is defined and zsh_powerlevel_custom_elements %} 123 | {% for element in zsh_powerlevel_custom_elements %} 124 | {% set prefix = "POWERLEVEL9K_CUSTOM_" + element.name | upper %} 125 | {{ prefix }}="{{ element.command }}" 126 | {{ prefix }}_BACKGROUND="{{ element.background }}" 127 | {{ prefix }}_FOREGROUND="{{ element.foreground }}" 128 | {% endfor %} 129 | {% endif %} 130 | 131 | # https://github.com/bhilburn/powerlevel9k#command_execution_time 132 | POWERLEVEL9K_COMMAND_EXECUTION_TIME_THRESHOLD="{{ zsh_command_time_min_seconds }}" 133 | 134 | POWERLEVEL9K_PROMPT_ON_NEWLINE={{ zsh_powerlevel9k_prompt_on_newline_bool }} 135 | POWERLEVEL9K_RPROMPT_ON_NEWLINE=false 136 | POWERLEVEL9K_PROMPT_ADD_NEWLINE=true 137 | 138 | POWERLEVEL9K_CONTEXT_DEFAULT_FOREGROUND="{{ zsh_powerlevel9k_context_default_foreground }}" 139 | POWERLEVEL9K_CONTEXT_DEFAULT_BACKGROUND="{{ zsh_powerlevel9k_context_default_background }}" 140 | POWERLEVEL9K_CONTEXT_REMOTE_FOREGROUND="{{ zsh_powerlevel9k_context_default_foreground }}" 141 | POWERLEVEL9K_CONTEXT_REMOTE_BACKGROUND="{{ zsh_powerlevel9k_context_default_background }}" 142 | POWERLEVEL9K_CONTEXT_ROOT_FOREGROUND="{{ zsh_powerlevel9k_context_root_foreground }}" 143 | POWERLEVEL9K_CONTEXT_ROOT_BACKGROUND="{{ zsh_powerlevel9k_context_root_background }}" 144 | 145 | POWERLEVEL9K_DIR_DEFAULT_FOREGROUND="{{ zsh_powerlevel9k_dir_foreground }}" 146 | POWERLEVEL9K_DIR_DEFAULT_BACKGROUND="{{ zsh_powerlevel9k_dir_background }}" 147 | POWERLEVEL9K_DIR_HOME_FOREGROUND="{{ zsh_powerlevel9k_dir_foreground }}" 148 | POWERLEVEL9K_DIR_HOME_BACKGROUND="{{ zsh_powerlevel9k_dir_background }}" 149 | POWERLEVEL9K_DIR_HOME_SUBFOLDER_FOREGROUND="{{ zsh_powerlevel9k_dir_foreground }}" 150 | POWERLEVEL9K_DIR_HOME_SUBFOLDER_BACKGROUND="{{ zsh_powerlevel9k_dir_background }}" 151 | POWERLEVEL9K_DIR_ETC_FOREGROUND="{{ zsh_powerlevel9k_dir_etc_foreground }}" 152 | POWERLEVEL9K_DIR_ETC_BACKGROUND="{{ zsh_powerlevel9k_dir_etc_background }}" 153 | POWERLEVEL9K_DIR_PATH_HIGHLIGHT_FOREGROUND="{{ zsh_powerlevel9k_dir_path_highlight_foreground }}" 154 | POWERLEVEL9K_DIR_PATH_HIGHLIGHT_BACKGROUND="{{ zsh_powerlevel9k_dir_path_highlight_background }}" 155 | 156 | POWERLEVEL9K_VCS_CLEAN_BACKGROUND="{{ zsh_powerlevel9k_vcs_clean_background }}" 157 | POWERLEVEL9K_VCS_MODIFIED_BACKGROUND="{{ zsh_powerlevel9k_vcs_modified_background }}" 158 | POWERLEVEL9K_VCS_UNTRACKED_BACKGROUND="{{ zsh_powerlevel9k_vcs_untracked_background }}" 159 | POWERLEVEL9K_VCS_CLEAN_FOREGROUND="{{ zsh_powerlevel9k_vcs_foreground }}" 160 | POWERLEVEL9K_VCS_MODIFIED_FOREGROUND="{{ zsh_powerlevel9k_vcs_foreground }}" 161 | POWERLEVEL9K_VCS_UNTRACKED_FOREGROUND="{{ zsh_powerlevel9k_vcs_foreground }}" 162 | 163 | POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND="{{ zsh_powerlevel9k_command_execution_time_foreground }}" 164 | POWERLEVEL9K_COMMAND_EXECUTION_TIME_BACKGROUND="{{ zsh_powerlevel9k_command_execution_time_background }}" 165 | 166 | # Aliases 167 | alias suser='su -' 168 | 169 | {% if zsh_load_etc_profile %}source /etc/profile{% endif %} 170 | 171 | # user configs 172 | [[ -r /etc/zsh/zshrc.local ]] && source /etc/zsh/zshrc.local 173 | [[ -r "$HOME/.zshrc.local" ]] && source "$HOME/.zshrc.local" 174 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/tests/vagrant.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | roles: 4 | - ../.. 5 | -------------------------------------------------------------------------------- /ansible/roles/viasite-ansible.zsh/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | zsh_user_group: "{% if ansible_os_family == 'Darwin' %}staff{% else %}{{ zsh_user }}{% endif %}" 3 | zsh_antigen_path: "{% if zsh_shared %}/usr/share/zsh-config{% else %}~{{ zsh_user }}/.antigen{% endif %}" 4 | zsh_config: "{% if zsh_shared %}/usr/share/zsh-config/.zshrc{% else %}~{{ zsh_user }}/.zshrc{% endif %}" 5 | zsh_antigen_path_compat: "{{ zsh_antigen_path | replace('~' + zsh_user, '$HOME') }}" 6 | 7 | zsh_fzf_os: linux 8 | zsh_fzf_arch: "{% if '64' in ansible_architecture %}amd64{% else %}386{% endif %}" 9 | zsh_fzf_url: "https://github.com/junegunn/fzf-bin/releases/download/{{ zsh_fzf_version }}/fzf-{{ zsh_fzf_version }}-{{ zsh_fzf_os }}_{{ zsh_fzf_arch }}.tgz" 10 | zsh_antigen_fzf_path: "{{ zsh_antigen_path }}/repos/https-COLON--SLASH--SLASH-github.com-SLASH-junegunn-SLASH-fzf.git" 11 | zsh_fzf_default_opts: "--height {{ zsh_fzf_height }}{% if zsh_fzf_reverse %} --reverse{% endif %}{% if zsh_fzf_border %} --border{% endif %}" 12 | 13 | zsh_powerlevel9k_prompt_on_newline_bool: "{% if zsh_powerlevel9k_prompt_on_newline %}true{% else %}false{% endif %}" 14 | zsh_powerlevel9k_always_show_context_bool: "{% if zsh_powerlevel9k_always_show_context %}true{% else %}false{% endif %}" 15 | zsh_powerlevel9k_always_show_user_bool: "{% if zsh_powerlevel9k_always_show_user %}true{% else %}false{% endif %}" 16 | -------------------------------------------------------------------------------- /docs/SETUP.md: -------------------------------------------------------------------------------- 1 | # Nomad Cluster Setup 2 | 3 | ## Prerequisite 4 | 5 | Before continuing with the setup for Nomad and Consul: 6 | 7 | - Provision DO infra with Terraform. 8 | - Run Ansible Playbook to boostrap the node. 9 | 10 | ### Setup Tailscale 11 | 12 | Tailscale acts as a mesh layer between the server and worker nodes. Since the user's laptop/mobile also has a Tailscale agent running it makes it easy to deploy and browse Nomad/Consul Admin UIs as well. 13 | 14 | ``` 15 | sudo tailscale up 16 | ``` 17 | 18 | ## Install Nomad 19 | 20 | Follow the instructions from the [docs](https://www.nomadproject.io/docs/install). 21 | 22 | ```sh 23 | curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - 24 | sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" 25 | sudo apt-get update && sudo apt-get install nomad 26 | nomad -autocomplete-install 27 | complete -C /usr/bin/nomad nomad 28 | sudo mkdir --parents /opt/nomad 29 | ``` 30 | 31 | ### Setup Nomad 32 | 33 | Follow the instructions from the [docs](https://learn.hashicorp.com/tutorials/nomad/production-deployment-guide-vm-with-consul). 34 | 35 | #### Systemd unit 36 | 37 | ``` 38 | # /etc/systemd/system/nomad.service 39 | [Unit] 40 | Description=Nomad 41 | Documentation=https://www.nomadproject.io/docs 42 | Wants=network-online.target 43 | After=network-online.target 44 | 45 | [Service] 46 | ExecReload=/bin/kill -HUP $MAINPID 47 | ExecStart=/usr/bin/nomad agent -config /etc/nomad.d 48 | KillMode=process 49 | KillSignal=SIGINT 50 | LimitNOFILE=infinity 51 | LimitNPROC=infinity 52 | Restart=on-failure 53 | RestartSec=2 54 | StartLimitBurst=3 55 | StartLimitIntervalSec=10 56 | TasksMax=infinity 57 | 58 | [Install] 59 | WantedBy=multi-user.target 60 | ``` 61 | 62 | #### Configurations 63 | 64 | All the config files are stored in `/etc/nomad.d`. 65 | 66 | ```hcl 67 | data_dir = "/opt/nomad/data" 68 | bind_addr = "{{ GetInterfaceIP \"tailscale0\" }}" 69 | datacenter = "hydra" 70 | 71 | server { 72 | enabled = true 73 | bootstrap_expect = 1 74 | } 75 | 76 | client { 77 | enabled = true 78 | host_network "tailscale" { 79 | cidr = "100.119.138.27/32" 80 | reserved_ports = "22" 81 | } 82 | } 83 | 84 | plugin "docker" { 85 | config { 86 | volumes { 87 | enabled = true 88 | } 89 | extra_labels = ["job_name", "job_id", "task_group_name", "task_name", "namespace", "node_name", "node_id"] 90 | } 91 | } 92 | 93 | plugin "raw_exec" { 94 | config { 95 | enabled = true 96 | } 97 | } 98 | 99 | telemetry { 100 | collection_interval = "15s" 101 | disable_hostname = true 102 | prometheus_metrics = true 103 | publish_allocation_metrics = true 104 | publish_node_metrics = true 105 | } 106 | 107 | consul { 108 | address = "100.119.138.27:8500" 109 | } 110 | ``` 111 | 112 | ### Verification 113 | 114 | Since we changed the `bind_addr` from `0.0.0.0`(default) to Tailscale IP we need to 115 | configure `NOMAD_ADDRESS` env variable for CLI to configure the remote endpoint: 116 | 117 | [Docs](https://www.nomadproject.io/docs/commands#remote-usage) 118 | 119 | ```sh 120 | export NOMAD_ADDR=http://100.119.138.27:4646 121 | ``` 122 | 123 | Before proceeding ahead, make sure `nomad` is running: 124 | 125 | ```sh 126 | $ nomad server members 127 | Name Address Port Status Leader Protocol Build Datacenter Region 128 | floyd.global 10.47.0.6 4648 alive true 2 1.0.3 hydra global 129 | ``` 130 | 131 | ## Install Consul 132 | 133 | ```sh 134 | sudo apt-get update && sudo apt-get install consul 135 | consul -autocomplete-install 136 | complete -C /usr/bin/consul consul 137 | sudo mkdir --parents /opt/consul 138 | ``` 139 | 140 | ## Setup Consul 141 | 142 | ### Generate Keys 143 | 144 | ``` 145 | consul keygen 146 | ``` 147 | 148 | The output of the above command is used in the config file. 149 | 150 | ### Configuration 151 | 152 | All the config is stored in `/etc/consul.d` 153 | 154 | ```hcl 155 | datacenter = "hydra" 156 | data_dir = "/opt/consul/data" 157 | encrypt = "" 158 | server = true 159 | bootstrap_expect = 1 160 | client_addr = "100.119.138.27" 161 | bind_addr = "127.0.0.1" 162 | ui = true 163 | connect { 164 | enabled = true 165 | } 166 | ``` 167 | 168 | ### Systemd Unit 169 | 170 | ``` 171 | [Unit] 172 | Description="HashiCorp Consul - A service mesh solution" 173 | Documentation=https://www.consul.io/ 174 | Requires=network-online.target 175 | After=network-online.target 176 | ConditionFileNotEmpty=/etc/consul.d/consul.hcl 177 | 178 | [Service] 179 | User=consul 180 | Group=consul 181 | ExecStart=/usr/bin/consul agent -config-dir=/etc/consul.d/ 182 | ExecReload=/bin/kill --signal HUP $MAINPID 183 | KillMode=process 184 | KillSignal=SIGTERM 185 | Restart=on-failure 186 | LimitNOFILE=65536 187 | 188 | [Install] 189 | WantedBy=multi-user.target 190 | ``` 191 | 192 | ## Vault 193 | 194 | **WIP** 195 | 196 | Currently using `TF_VARS` to load env variables from the host and run `tf apply`. Terraform then templates out the Nomad `jobspec` and submits the job to the server. This is okay in this context because: 197 | 198 | - Nomad API server is listening only to Tailscale IP. Which means only trusted, authenticated agents have access to the API. This is very important because Nomad shows the plain text version of the `jobspec` in UI and CLI. So all the secret keys can be exposed if a malicious actor has access to the API server (even if read only). 199 | 200 | - The env keys are mostly just one time API tokens or DB Passwords. They don't need to be "watched" and reloaded often, running an entire Vault server just for passing these keys seems a bit _extra complexity_. 201 | 202 | **However**, to just _experiment_ with things and make the setup a bit more secure, we can consider running a single node Vault server: 203 | 204 | - [ ] Setup Vault to store secrets 205 | - [ ] Vault init/unseal steps. 206 | - [ ] Add Policies and Role in Vault for a namespace 207 | - [ ] Configure Nomad to use Vault 208 | - [ ] Add an API token in Vault 209 | - [ ] Pass CF token to Caddyfile and retrieve from Vault with Consul Template 210 | -------------------------------------------------------------------------------- /docs/calvin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mr-karan/homelab/06653f8f276e53b3ef987d80ce65b7d7e190cdce/docs/calvin.jpg -------------------------------------------------------------------------------- /talks/foss-united-apr-2021.html: -------------------------------------------------------------------------------- 1 |
30 |

Self Hosting 101

31 |

FOSS United - April 2021

32 |

@mrkaran

33 | 34 |
35 |
36 |

whoami

37 |

👨‍💻 Writes YAML at Zerodha

38 |

📈 Interested in Monitoring and Observability systems

39 |

📓 Blogs about things I find interesting

40 |

🧩 Self hosted enthusiast

41 | 42 |
43 |
44 |

Why (I) Self Host

45 |
    46 |
  • Break from the Big Tech Co
  • 47 |
48 | 49 |
50 |
51 |

Why (I) Self Host

52 |
    53 |
  • Break from the Big Tech Co
  • 54 |
  • Own your data
  • 55 |
56 | 57 |
58 |
59 |

Why (I) Self Host

60 |
    61 |
  • Break from the Big Tech Co
  • 62 |
  • Own your data
  • 63 |
  • No lock ins for data which is critical
  • 64 |
65 | 66 |
67 |
68 |

Why (I) Self Host

69 |
    70 |
  • Break from the Big Tech Co
  • 71 |
  • Own your data
  • 72 |
  • No lock ins for data which is critical
  • 73 |
  • Chance to contribute to OSS
  • 74 |
75 | 76 |
77 |
78 |

Why (I) Self Host

79 |
    80 |
  • Break from the Big Tech Co
  • 81 |
  • Own your data
  • 82 |
  • No lock ins for data which is critical
  • 83 |
  • Chance to contribute to OSS
  • 84 |
  • Experiment and learn
  • 85 |
86 | 87 |
88 |
89 |

My Setup

90 |

Servers

91 |
    92 |
  • DigitalOcean Droplet (2vCPU, 4GB RAM, blr1 Region)
  • 93 |
  • 1 * RPi 4 Node (4GB RAM)
  • 94 |
  • 1 * RPi 4 Node (2GB RAM)
  • 95 |
96 | 97 |
98 |
99 |

Infra and Deployments

100 |
    101 |
  • Ansible
  • 102 |
  • Terraform
  • 103 |
  • Nomad + Consul
  • 104 |
105 | 106 |
107 |
108 |

Ansible

109 |
    110 |
  • Boostrap the server 111 |
      112 |
    • Harden SSH. User, Shell setups.
    • 113 |
    • Install node-exporter, docker, tailscale.
    • 114 |
    115 |
  • 116 |
117 | 118 |
119 |
120 |

Terraform

121 |
    122 |
  • 123 |

    DigitalOcean infra

    124 |
      125 |
    • Droplet
    • 126 |
    • Firewalls
    • 127 |
    • SSH Keys, Volumes, Floating IPs etc.
    • 128 |
    129 |
  • 130 |
  • 131 |

    Cloudflare DNS

    132 |
      133 |
    • mrkaran.dev hosted zone
    • 134 |
    • DNS Records in ^ the zone.
    • 135 |
    136 |
  • 137 |
138 | 139 |
140 |
141 |

Nomad + Consul

142 |
    143 |
  • Single node cluster.
  • 144 |
  • Runs every workload (mostly) as a docker container.
  • 145 |
146 | 147 |
148 |
149 |

Services I run

150 |
    151 |
  • Pi-hole
  • 152 |
  • Gitea
  • 153 |
  • Joplin Sync Server
  • 154 |
  • Shynet
  • 155 |
  • Firefly III
  • 156 |
  • Nextcloud
  • 157 |
  • doggo (Shameless self plug)
  • 158 |
159 | 160 |
161 |
162 |

Monitoring

163 |
    164 |
  • Grafana
  • 165 |
  • Prometheus
  • 166 |
  • Telegraf to collect home ISP stats 167 |
      168 |
    • Ping Input plugin
    • 169 |
    • DNS Input Plugin
    • 170 |
    171 |
  • 172 |
173 | 174 |
175 |
176 |
177 |
178 |
179 |
180 |

Networking

181 |
    182 |
  • Tailscale for Mesh Network 183 |
      184 |
    • Based on Wireguard VPN.
    • 185 |
    • Authenticated sessions only.
    • 186 |
    • Expose services on RPi easily without any static IP.
    • 187 |
    188 |
  • 189 |
190 | 191 |
192 |
193 |

Networking

194 |
    195 |
  • Caddy as a proxy for all services. 196 |
      197 |
    • 198 |

      Running 2 instances of Caddy.

      199 |
        200 |
      • Private: Listens on Tailscale Interface.
      • 201 |
      • Public: Listens on DO's public IPv4 Interface.
      • 202 |
      203 |
    • 204 |
    • 205 |

      Automatic SSL with ACME DNS challenge

      206 | 209 |
    • 210 |
    211 |
  • 212 |
213 | 214 |
215 |
216 |

Storage

217 |
    218 |
  • 219 |

    DONT use RPi for storage.

    220 |
      221 |
    • Atleast not with SD cards.
    • 222 |
    • Newer RPis can boot off SSDs.
    • 223 |
    224 |
  • 225 |
  • 226 |

    Enable snapshots for volumes provided by cloud provider.

    227 |
  • 228 |
  • 229 |

    Use separate DB instances for different applications.

    230 |
  • 231 |
232 | 233 |
234 |
235 |

Backups

236 |
    237 |
  • Restic 238 |
      239 |
    • Periodic Job in Nomad.
    • 240 |
    • Single vault with everything inside /data.
    • 241 |
    • All applications mount inside /data folder.
    • 242 |
    • Upload to Backblaze B2.
    • 243 |
    244 |
  • 245 |
246 | 247 |
248 |
249 |

Security

250 |
    251 |
  • 252 |

    If it should not be public facing, don't expose to WWW.

    253 |
      254 |
    • Prefer to use a VPN or mesh network instead of IP whitelists.
    • 255 |
    • Tighter Firewall rules otherwise.
    • 256 |
    257 |
  • 258 |
  • 259 |

    Pi-Hole, Gitea, etc Admin interfaces must always be protected with strong passwords.

    260 |
      261 |
    • Wonder how many admin/admin Grafana instances are out in open.
    • 262 |
    • Or worse, no auth. Looking at you Elasticsearch.
    • 263 |
    264 |
  • 265 |
  • 266 |

    Periodic updates to App and OS.

    267 |
  • 268 |
269 | 270 |
271 |
272 |

Takeaways

273 |
    274 |
  • 275 |

    Don't overthink. Pick something really simple (like Pi-hole) and host it.

    276 |
      277 |
    • You'll feel pretty happy about it.
    • 278 |
    279 |
  • 280 |
  • 281 |

    Don't blindly copy/paste this stack.

    282 |
      283 |
    • Took me 2 years of constant iteration and experimentation.
    • 284 |
    • KISS.
    • 285 |
    286 |
  • 287 |
288 | 289 |
290 |
291 |

Resources

292 |

r/selfhosted
293 | - Incredible, beginner friendly wiki: https://wiki.r-selfhosted.com/
294 | github.com/awesome-selfhosted

295 | 296 |
297 |
298 |

Thank You

299 |

Questions?

300 | 301 |
302 |
-------------------------------------------------------------------------------- /talks/foss-united-apr-2021.md: -------------------------------------------------------------------------------- 1 | --- 2 | theme: dracula 3 | paginate: true 4 | marp: true 5 | size: 4K 6 | footer: Hydra Repo: [git.mrkaran.dev/karan/hydra](https://git.mrkaran.dev/karan/hydra) 7 | --- 8 | 9 | 10 | 11 | # Self Hosting 101 12 | 13 | FOSS United - April 2021 14 | 15 | *@mrkaran* 16 | 17 | --- 18 | 19 | # `whoami` 20 | 21 | 👨‍💻 Writes YAML at Zerodha 22 | 23 | 📈 Interested in Monitoring and Observability systems 24 | 25 | 📓 Blogs about things I find interesting 26 | 27 | 🧩 **Self hosted enthusiast** 28 | 29 | ![bg right 66%](./img/cycle.jpg) 30 | 31 | --- 32 | 33 | # Why (I) Self Host 34 | 35 | - Break from the Big Tech Co 36 | 37 | --- 38 | 39 | # Why (I) Self Host 40 | 41 | - Break from the Big Tech Co 42 | - Own your data 43 | 44 | --- 45 | 46 | # Why (I) Self Host 47 | 48 | - Break from the Big Tech Co 49 | - Own your data 50 | - No lock ins for data which is critical 51 | 52 | --- 53 | 54 | # Why (I) Self Host 55 | 56 | - Break from the Big Tech Co 57 | - Own your data 58 | - No lock ins for data which is critical 59 | - Chance to contribute to OSS 60 | 61 | --- 62 | 63 | # Why (I) Self Host 64 | 65 | - Break from the Big Tech Co 66 | - Own your data 67 | - No lock ins for data which is critical 68 | - Chance to contribute to OSS 69 | - Experiment and learn 70 | 71 | --- 72 | 73 | # My Setup 74 | 75 | ## Servers 76 | 77 | - DigitalOcean Droplet (2vCPU, 4GB RAM, blr1 Region) 78 | - 1 * RPi 4 Node (4GB RAM) 79 | - 1 * RPi 4 Node (2GB RAM) 80 | 81 | --- 82 | 83 | # Infra and Deployments 84 | 85 | - Ansible 86 | - Terraform 87 | - Nomad + Consul 88 | 89 | --- 90 | 91 | ## Ansible 92 | 93 | - Boostrap the server 94 | - Harden SSH. User, Shell setups. 95 | - Install `node-exporter`, `docker`, `tailscale`. 96 | 97 | --- 98 | 99 | ## Terraform 100 | 101 | - DigitalOcean infra 102 | - Droplet 103 | - Firewalls 104 | - SSH Keys, Volumes, Floating IPs etc. 105 | 106 | - Cloudflare DNS 107 | - `mrkaran.dev` hosted zone 108 | - DNS Records in ^ the zone. 109 | 110 | --- 111 | 112 | ## Nomad + Consul 113 | 114 | - Single node cluster. 115 | - Runs every workload (mostly) as a docker container. 116 | 117 | --- 118 | 119 | # Services I run 120 | 121 | - Pi-hole 122 | - Gitea 123 | - Joplin Sync Server 124 | - Shynet 125 | - Firefly III 126 | - Nextcloud 127 | - `doggo` (Shameless self plug) 128 | 129 | --- 130 | 131 | # Monitoring 132 | 133 | - Grafana 134 | - Prometheus 135 | - Telegraf to collect home ISP stats 136 | - Ping Input plugin 137 | - DNS Input Plugin 138 | 139 | --- 140 | 141 | ![bg 90%](./img/isp-monitoring.png) 142 | 143 | --- 144 | 145 | ![bg 90%](./img/isp-monitoring-2.png) 146 | 147 | --- 148 | 149 | # Networking 150 | 151 | - Tailscale for Mesh Network 152 | - Based on Wireguard VPN. 153 | - Authenticated sessions only. 154 | - Expose services on RPi easily without any static IP. 155 | 156 | --- 157 | 158 | # Networking 159 | 160 | - Caddy as a proxy for all services. 161 | - Running 2 instances of Caddy. 162 | - Private: Listens on Tailscale Interface. 163 | - Public: Listens on DO's public IPv4 Interface. 164 | 165 | - Automatic SSL with ACME DNS challenge 166 | - Built my own image: https://github.com/mr-karan/caddy-plugins-docker 167 | 168 | --- 169 | 170 | # Storage 171 | 172 | - DONT use RPi for storage. 173 | - Atleast not with SD cards. 174 | - Newer RPis can boot off SSDs. 175 | 176 | - Enable snapshots for volumes provided by cloud provider. 177 | 178 | - Use separate DB instances for different applications. 179 | 180 | --- 181 | 182 | # Backups 183 | 184 | - Restic 185 | - Periodic Job in Nomad. 186 | - Single vault with everything inside `/data`. 187 | - All applications mount inside `/data` folder. 188 | - Upload to Backblaze B2. 189 | 190 | --- 191 | 192 | # Security 193 | 194 | - If it should not be public facing, don't expose to WWW. 195 | - Prefer to use a VPN or mesh network instead of IP whitelists. 196 | - Tighter Firewall rules otherwise. 197 | 198 | - Pi-Hole, Gitea, etc Admin interfaces must always be protected with strong passwords. 199 | - Wonder how many `admin/admin` Grafana instances are out in open. 200 | - Or worse, no auth. Looking at you Elasticsearch. 201 | 202 | - Periodic **updates** to App and OS. 203 | 204 | --- 205 | 206 | # Takeaways 207 | 208 | - Don't overthink. Pick something really simple (like Pi-hole) and host it. 209 | - You'll feel pretty happy about it. 210 | 211 | - Don't blindly copy/paste this stack. 212 | - Took me 2 years of constant iteration and experimentation. 213 | - KISS. 214 | 215 | --- 216 | 217 | # Resources 218 | 219 | [r/selfhosted](https://www.reddit.com/r/selfhosted) 220 | - Incredible, beginner friendly wiki: https://wiki.r-selfhosted.com/ 221 | [github.com/awesome-selfhosted](https://github.com/awesome-selfhosted/awesome-selfhosted) 222 | 223 | --- 224 | 225 | 226 | 227 | 228 | # Thank You 229 | 230 | ## Questions? 231 | -------------------------------------------------------------------------------- /talks/img/cycle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mr-karan/homelab/06653f8f276e53b3ef987d80ce65b7d7e190cdce/talks/img/cycle.jpg -------------------------------------------------------------------------------- /talks/img/isp-monitoring-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mr-karan/homelab/06653f8f276e53b3ef987d80ce65b7d7e190cdce/talks/img/isp-monitoring-2.png -------------------------------------------------------------------------------- /talks/img/isp-monitoring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mr-karan/homelab/06653f8f276e53b3ef987d80ce65b7d7e190cdce/talks/img/isp-monitoring.png -------------------------------------------------------------------------------- /terraform/.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "terraform init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.terraform.io/cloudflare/cloudflare" { 5 | version = "2.20.0" 6 | hashes = [ 7 | "h1:hq912gbF5V9qU6O6TpIjDecKCOpZ3s/o0HIZAIESlw8=", 8 | "zh:1cc439dcf2bb64fbc4b701e0345d47e32c488ebf3c5149c4b2a5da5b1f9b8dc5", 9 | "zh:2b244c594bf674d7f3d939f75daae6bc68732f62603c179d63c8c16b4cd5c248", 10 | "zh:3210c5e6bae1595f231f5e0a479c305b97192d5393b7e6650c6d3647f382041f", 11 | "zh:332f9ac6aa5c18e2df20f177f59cd68ec4c4a46b30e46d7a0af37fffeaed90ca", 12 | "zh:3e304aca15904cde3cf60e23de3422d4dbd84f1b527f587b7d6009f722d8645e", 13 | "zh:5a4ff4512ed12fde14d27ff8ac2e76d3bbea2e39ccc12f0720292c0ebe4a3bf8", 14 | "zh:71dd3268b5e9cb50831254451a6c2b4a3da4383c852b9e37b19ba94b63555532", 15 | "zh:841dfe03377d38667541359c7b5857ff48df4d1cee12f63daadc5837e4ca1974", 16 | "zh:8fa108c7d8b9e1edcdc2aa8be18a054d5e00c67137e29f27c16dc5e2fdcf76b7", 17 | "zh:a38823be68ed1d0aed2e0051d459d150372edff396d3d108725bc889b91cd41f", 18 | "zh:a6c4f12bb0ab72f381eff0172790b00ab35fd6f7f14c60f56a1d67a0bb3225ea", 19 | "zh:bcc00547d0c6ccefe277aa16f5764d4621b0fe76579ab683bb88df192f107c12", 20 | "zh:ca3922155eb365402b8b661c32fb7f9324fecfab7d627810fb9a425fa44ec534", 21 | ] 22 | } 23 | 24 | provider "registry.terraform.io/digitalocean/digitalocean" { 25 | version = "2.5.1" 26 | constraints = "2.5.1" 27 | hashes = [ 28 | "h1:k9itTwJzUpMBTYsXYPoEW/fyoDOcteQc4+OMRmFErbc=", 29 | "zh:057b8fa0f95213e7d856208d456175335fb673cfef14abf41193f0a2d76e1210", 30 | "zh:0daee13dd46de95ce2550459942c1433290798bfb5faac12781f81799dd6b05c", 31 | "zh:13778c00db5c43b2ed5781e2de32d73f34b391c865a52ad3380714bf86251785", 32 | "zh:2b2bbb1b057c8bf15804a9fd47c30f30b39bcd7ed478bfcad11e221c654f5d02", 33 | "zh:43284d2b1a356f541723a46219812590d24742558ef4111eda545212fd60f011", 34 | "zh:6a6e13b55f9aa889e3162d75cb3e585116e8a0d12084629af38f68cdac6aa777", 35 | "zh:6fa3dbbad99a075768e9449fc6082769da1b76ae31a8e296ae50899835e859a1", 36 | "zh:79336598d190f511cf3d3323b49081474669d0daa9c1c0d3b21475110ad97bd9", 37 | "zh:84c4c8d29820229bd94f7d3c5310f1f7208b97e7d4efca2c8e24ae0c0e032267", 38 | "zh:86926853140d9072986d2cb8ff4693784abd5f5d241b8cec402dfad77d8060ed", 39 | "zh:95a896f51656b51519b10edf38f11eb766de60297b8551dc0d14a4041dd16d6f", 40 | "zh:d163da24466cd60eed4749fef56c6593cc6e33be2e210e1b57edfd1c968aa742", 41 | "zh:e830649afac9e505603002f8a76b2441a0a41c96c6516609e2c07ce0c45f9dc3", 42 | ] 43 | } 44 | 45 | provider "registry.terraform.io/hashicorp/http" { 46 | version = "2.1.0" 47 | hashes = [ 48 | "h1:HmUcHqc59VeHReHD2SEhnLVQPUKHKTipJ8Jxq67GiDU=", 49 | "zh:03d82dc0887d755b8406697b1d27506bc9f86f93b3e9b4d26e0679d96b802826", 50 | "zh:0704d02926393ddc0cfad0b87c3d51eafeeae5f9e27cc71e193c141079244a22", 51 | "zh:095ea350ea94973e043dad2394f10bca4a4bf41be775ba59d19961d39141d150", 52 | "zh:0b71ac44e87d6964ace82979fc3cbb09eb876ed8f954449481bcaa969ba29cb7", 53 | "zh:0e255a170db598bd1142c396cefc59712ad6d4e1b0e08a840356a371e7b73bc4", 54 | "zh:67c8091cfad226218c472c04881edf236db8f2dc149dc5ada878a1cd3c1de171", 55 | "zh:75df05e25d14b5101d4bc6624ac4a01bb17af0263c9e8a740e739f8938b86ee3", 56 | "zh:b4e36b2c4f33fdc44bf55fa1c9bb6864b5b77822f444bd56f0be7e9476674d0e", 57 | "zh:b9b36b01d2ec4771838743517bc5f24ea27976634987c6d5529ac4223e44365d", 58 | "zh:ca264a916e42e221fddb98d640148b12e42116046454b39ede99a77fc52f59f4", 59 | "zh:fe373b2fb2cc94777a91ecd7ac5372e699748c455f44f6ea27e494de9e5e6f92", 60 | ] 61 | } 62 | 63 | provider "registry.terraform.io/hashicorp/nomad" { 64 | version = "1.4.14" 65 | constraints = "1.4.14" 66 | hashes = [ 67 | "h1:GxsjoJKg/PWeXYzpzoONBQiaGnY+bPEDDD+BsEDgc8Q=", 68 | "zh:036cc8e0c1c6c2f91573149910eca29a7107b3415536eabeb2581861525da64a", 69 | "zh:1414e2deb87af66a47e44ab5472b4606294cf511722beae2c0a3680041d66635", 70 | "zh:623184a22b347fa5b696d3fbee35f5bff9ed30fbc8b067715c52b6300d655789", 71 | "zh:7a026a57148a7c2e8a08a83c3641898911a7d9998c38eb2c6ca634107ccf49f9", 72 | "zh:87d34e879284453b2ac825f8bb9c88c85027d404b1b9fa445ec97b519dfa59cb", 73 | "zh:90591119307c2f3dd15a6a78964731689444fb1ce3d393eddf83e05a2f187b80", 74 | "zh:b2cbf5e4d4f2d500804e7f1968b3fd2cebd4b164ccf76d7cb2c99ed1eb23957e", 75 | "zh:d5f19ab3d0d172be8af098bb62b47667c632af736c60d1acab0fc1c31dbbcb99", 76 | "zh:ee5f7f75a642eed607d4824b5888e4aacfc4dd435d54d9523d8f8165695d52a1", 77 | "zh:f6300309339221a5f0863bec32d96b38a8e545c5a87b43c5bb8c65d2ff0492ed", 78 | ] 79 | } 80 | 81 | provider "registry.terraform.io/hashicorp/template" { 82 | version = "2.2.0" 83 | hashes = [ 84 | "h1:94qn780bi1qjrbC3uQtjJh3Wkfwd5+tTtJHOb7KTg9w=", 85 | "zh:01702196f0a0492ec07917db7aaa595843d8f171dc195f4c988d2ffca2a06386", 86 | "zh:09aae3da826ba3d7df69efeb25d146a1de0d03e951d35019a0f80e4f58c89b53", 87 | "zh:09ba83c0625b6fe0a954da6fbd0c355ac0b7f07f86c91a2a97849140fea49603", 88 | "zh:0e3a6c8e16f17f19010accd0844187d524580d9fdb0731f675ffcf4afba03d16", 89 | "zh:45f2c594b6f2f34ea663704cc72048b212fe7d16fb4cfd959365fa997228a776", 90 | "zh:77ea3e5a0446784d77114b5e851c970a3dde1e08fa6de38210b8385d7605d451", 91 | "zh:8a154388f3708e3df5a69122a23bdfaf760a523788a5081976b3d5616f7d30ae", 92 | "zh:992843002f2db5a11e626b3fc23dc0c87ad3729b3b3cff08e32ffb3df97edbde", 93 | "zh:ad906f4cebd3ec5e43d5cd6dc8f4c5c9cc3b33d2243c89c5fc18f97f7277b51d", 94 | "zh:c979425ddb256511137ecd093e23283234da0154b7fa8b21c2687182d9aea8b2", 95 | ] 96 | } 97 | 98 | provider "registry.terraform.io/kreuzwerker/docker" { 99 | version = "2.11.0" 100 | hashes = [ 101 | "h1:2BuPcSQY9DSRhPufzrbiGyMW2NX1qqXkH1KfzrMUQmU=", 102 | "zh:1b9d93385cc0329467725ce90affc76a361bc23384a7358431e6ee281ae323de", 103 | "zh:21a327746cdad2abfc22df3d72eb9b36134bb7daeb72b2a52112adfd3a39555a", 104 | "zh:31ed477f429686015271188b03e89bfc400b74eea9e83956ea4cc16018b561f3", 105 | "zh:4302d65b5cbedbe42cf35094748058aea44f75dd7ec2b257330b5f60a2521def", 106 | "zh:43f53e3e29070dfec0621915d0a5266c386f7416f6a719531b7c55924cefd280", 107 | "zh:4bf7704bf46868edd834991f350aa6204c72397be1e1a784278391bb911e29f5", 108 | "zh:503434ddf9c801aa9a9e47e76b6b5758dd4583a49f7ac373066430b37b3efcaf", 109 | "zh:67410f9ed6503692121519b81e13cf5274ceadb5566bf2ec2dc0a6e43c700621", 110 | "zh:c0fd724ed8da52375976c3595a2a6748bf28c07ec881ad7154e657ab5c38f25b", 111 | "zh:cbe762d96c4ae61c42d8c02c047954b52a6567b214a0263345135baf249accd7", 112 | "zh:d3a23b086199d4a2a63707f28c0da8b392d8d11281c6881d85a959e76626fb7e", 113 | ] 114 | } 115 | -------------------------------------------------------------------------------- /terraform/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: init plan apply lint 2 | 3 | plan: 4 | - terraform plan 5 | 6 | init: 7 | - terraform init 8 | 9 | apply: 10 | # that's how we roll here ;) 11 | - terraform apply -auto-approve 12 | 13 | lint: 14 | - terraform validate && terraform fmt -recursive 15 | -------------------------------------------------------------------------------- /terraform/env.sample: -------------------------------------------------------------------------------- 1 | DIGITALOCEAN_TOKEN= 2 | CLOUDFLARE_API_TOKEN= 3 | TF_VAR_cloudflare_caddy_api_token= 4 | TF_VAR_shynet_postgresql_password= 5 | TF_VAR_shynet_django_secret_key= 6 | TF_VAR_gitea_secret_key= 7 | TF_VAR_gitea_internal_token= 8 | TF_VAR_gitea_lfs_jwt_secret= 9 | TF_VAR_gitea_oauth2_jwt_secret= 10 | TF_VAR_restic_b2_account_id= 11 | TF_VAR_restic_b2_account_key= 12 | TF_VAR_restic_repository= 13 | TF_VAR_restic_password= -------------------------------------------------------------------------------- /terraform/main.tf: -------------------------------------------------------------------------------- 1 | module "servers" { 2 | source = "./modules/digitalocean" 3 | providers = { 4 | digitalocean = digitalocean 5 | } 6 | } 7 | 8 | module "cloudflare" { 9 | source = "./modules/cloudflare" 10 | ips = local.ips 11 | providers = { 12 | cloudflare = cloudflare 13 | } 14 | } 15 | 16 | module "caddy" { 17 | source = "./modules/caddy" 18 | cloudflare_api_token = var.cloudflare_caddy_api_token 19 | providers = { 20 | nomad = nomad 21 | } 22 | } 23 | 24 | module "pihole" { 25 | source = "./modules/pihole" 26 | providers = { 27 | nomad = nomad 28 | } 29 | } 30 | 31 | 32 | module "doggo" { 33 | source = "./modules/doggo" 34 | providers = { 35 | nomad = nomad 36 | } 37 | } 38 | 39 | module "shynet" { 40 | source = "./modules/shynet" 41 | shynet_postgresql_password = var.shynet_postgresql_password 42 | shynet_django_secret_key = var.shynet_django_secret_key 43 | providers = { 44 | nomad = nomad 45 | } 46 | } 47 | 48 | module "restic" { 49 | source = "./modules/restic" 50 | restic_b2_account_id = var.restic_b2_account_id 51 | restic_b2_account_key = var.restic_b2_account_key 52 | restic_repository = var.restic_repository 53 | restic_password = var.restic_password 54 | providers = { 55 | nomad = nomad 56 | } 57 | } 58 | 59 | 60 | module "gitea" { 61 | source = "./modules/gitea" 62 | gitea_secret_key = var.gitea_secret_key 63 | gitea_internal_token = var.gitea_internal_token 64 | gitea_lfs_jwt_secret = var.gitea_lfs_jwt_secret 65 | gitea_oauth2_jwt_secret = var.gitea_oauth2_jwt_secret 66 | providers = { 67 | nomad = nomad 68 | } 69 | } 70 | 71 | module "monitoring" { 72 | source = "./modules/monitoring" 73 | providers = { 74 | nomad = nomad 75 | } 76 | } 77 | 78 | module "syncthing" { 79 | source = "./modules/syncthing" 80 | providers = { 81 | nomad = nomad 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /terraform/modules/caddy/conf/Caddyfile-internal: -------------------------------------------------------------------------------- 1 | nomad.mrkaran.dev { 2 | reverse_proxy 100.119.138.27:4646 3 | tls { 4 | dns cloudflare "${cloudflare_api_token}" 5 | } 6 | } 7 | 8 | consul.mrkaran.dev { 9 | reverse_proxy 100.119.138.27:8500 10 | tls { 11 | dns cloudflare "${cloudflare_api_token}" 12 | } 13 | } 14 | 15 | pihole.mrkaran.dev { 16 | {{ range service "pihole-admin" }} 17 | reverse_proxy {{ .Address }}:{{ .Port }} 18 | {{ end }} 19 | tls { 20 | dns cloudflare "${cloudflare_api_token}" 21 | } 22 | } 23 | 24 | grafana.mrkaran.dev { 25 | {{ range service "grafana-web" }} 26 | reverse_proxy {{ .Address }}:{{ .Port }} 27 | {{ end }} 28 | tls { 29 | dns cloudflare "${cloudflare_api_token}" 30 | } 31 | } 32 | 33 | prometheus.mrkaran.dev { 34 | {{ range service "prometheus-web" }} 35 | reverse_proxy {{ .Address }}:{{ .Port }} 36 | {{ end }} 37 | tls { 38 | dns cloudflare "${cloudflare_api_token}" 39 | } 40 | } 41 | 42 | syncthing.mrkaran.dev { 43 | {{ range service "syncthing-web" }} 44 | reverse_proxy {{ .Address }}:{{ .Port }} 45 | {{ end }} 46 | tls { 47 | dns cloudflare "${cloudflare_api_token}" 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /terraform/modules/caddy/conf/Caddyfile-public: -------------------------------------------------------------------------------- 1 | shynet.mrkaran.dev { 2 | {{ range service "shynet-web" }} 3 | reverse_proxy {{ .Address }}:{{ .Port }} 4 | {{ end }} 5 | tls { 6 | dns cloudflare "${cloudflare_api_token}" 7 | } 8 | } 9 | 10 | git.mrkaran.dev { 11 | {{ range service "gitea-web" }} 12 | reverse_proxy {{ .Address }}:{{ .Port }} 13 | {{ end }} 14 | tls { 15 | dns cloudflare "${cloudflare_api_token}" 16 | } 17 | } 18 | 19 | doggo.mrkaran.dev { 20 | {{ range service "doggo-web" }} 21 | reverse_proxy {{ .Address }}:{{ .Port }} 22 | {{ end }} 23 | tls { 24 | dns cloudflare "${cloudflare_api_token}" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /terraform/modules/caddy/conf/caddy.nomad: -------------------------------------------------------------------------------- 1 | job "caddy" { 2 | datacenters = ["hydra"] 3 | type = "service" 4 | 5 | group "proxy" { 6 | count = 1 7 | 8 | network { 9 | port "http-internal" { 10 | static = 80 11 | to = 80 12 | host_network = "tailscale" 13 | } 14 | 15 | port "https-internal" { 16 | static = 443 17 | to = 443 18 | host_network = "tailscale" 19 | } 20 | 21 | port "https-public" { 22 | static = 80 23 | to = 80 24 | 25 | # host_network = "public" 26 | } 27 | 28 | port "http-public" { 29 | static = 443 30 | to = 443 31 | 32 | # host_network = "public" 33 | } 34 | } 35 | 36 | restart { 37 | attempts = 2 38 | interval = "2m" 39 | delay = "30s" 40 | mode = "fail" 41 | } 42 | 43 | task "internal" { 44 | driver = "docker" 45 | 46 | config { 47 | image = "mrkaran/caddy:latest" 48 | 49 | # Bind the config file to container. 50 | mount { 51 | type = "bind" 52 | source = "configs" 53 | target = "/etc/caddy" # Bind mount the template from `NOMAD_TASK_DIR`. 54 | } 55 | 56 | # Bind the data directory to preserve certs. 57 | mount { 58 | type = "bind" 59 | target = "/data" 60 | source = "/data/caddy" 61 | readonly = false 62 | } 63 | 64 | ports = ["http-internal", "https-internal"] 65 | } 66 | 67 | resources { 68 | cpu = 100 69 | memory = 100 70 | } 71 | 72 | template { 73 | data = < 11 | ``` 12 | 13 | ```shell 14 | tf init 15 | ``` 16 | 17 | ## Applying changes 18 | 19 | ```shell 20 | tf plan 21 | tf apply 22 | ``` 23 | -------------------------------------------------------------------------------- /terraform/modules/digitalocean/firewalls.tf: -------------------------------------------------------------------------------- 1 | data "http" "cloudflare_ip4_addrs" { 2 | url = "https://www.cloudflare.com/ips-v4" 3 | } 4 | 5 | data "http" "cloudflare_ip6_addrs" { 6 | url = "https://www.cloudflare.com/ips-v6" 7 | } 8 | 9 | resource "digitalocean_firewall" "web" { 10 | name = "allow-http-https-cloudflare" 11 | 12 | droplet_ids = [digitalocean_droplet.floyd.id] 13 | inbound_rule { 14 | protocol = "tcp" 15 | port_range = "80" 16 | source_addresses = concat( 17 | split("\n", trimspace(data.http.cloudflare_ip4_addrs.body)), 18 | split("\n", trimspace(data.http.cloudflare_ip6_addrs.body)) 19 | ) 20 | } 21 | 22 | inbound_rule { 23 | protocol = "tcp" 24 | port_range = "443" 25 | source_addresses = concat( 26 | split("\n", trimspace(data.http.cloudflare_ip4_addrs.body)), 27 | split("\n", trimspace(data.http.cloudflare_ip6_addrs.body)) 28 | ) 29 | } 30 | 31 | } 32 | 33 | resource "digitalocean_firewall" "icmp" { 34 | name = "allow-icmp-all" 35 | 36 | droplet_ids = [digitalocean_droplet.floyd.id] 37 | inbound_rule { 38 | protocol = "icmp" 39 | source_addresses = ["0.0.0.0/0", "::/0"] 40 | } 41 | 42 | } 43 | 44 | resource "digitalocean_firewall" "vpn" { 45 | name = "allow-all-tailscale-inbound" 46 | 47 | droplet_ids = [digitalocean_droplet.floyd.id] 48 | 49 | inbound_rule { 50 | protocol = "tcp" 51 | port_range = "1-65535" 52 | source_addresses = ["100.64.0.0/10"] 53 | } 54 | 55 | inbound_rule { 56 | protocol = "udp" 57 | port_range = "1-65535" 58 | source_addresses = ["100.64.0.0/10"] 59 | } 60 | 61 | } 62 | 63 | resource "digitalocean_firewall" "ssh" { 64 | name = "ssh-inbound" 65 | 66 | droplet_ids = [digitalocean_droplet.floyd.id] 67 | 68 | inbound_rule { 69 | protocol = "tcp" 70 | port_range = "22" 71 | source_addresses = ["0.0.0.0/0", "::/0"] 72 | } 73 | } 74 | 75 | 76 | resource "digitalocean_firewall" "outbound-all" { 77 | name = "allow-all-outbound" 78 | 79 | droplet_ids = [digitalocean_droplet.floyd.id] 80 | 81 | outbound_rule { 82 | protocol = "tcp" 83 | port_range = "1-65535" 84 | destination_addresses = ["0.0.0.0/0", "::/0"] 85 | } 86 | 87 | outbound_rule { 88 | protocol = "udp" 89 | port_range = "1-65535" 90 | destination_addresses = ["0.0.0.0/0", "::/0"] 91 | } 92 | 93 | outbound_rule { 94 | protocol = "icmp" 95 | destination_addresses = ["0.0.0.0/0", "::/0"] 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /terraform/modules/digitalocean/floyd.tf: -------------------------------------------------------------------------------- 1 | # `floyd` is the Nomad Serve which also runs Consul, Vault. 2 | resource "digitalocean_droplet" "floyd" { 3 | image = "ubuntu-20-04-x64" 4 | name = "floyd" 5 | region = "blr1" 6 | monitoring = true 7 | size = "s-2vcpu-4gb" 8 | ipv6 = true 9 | private_networking = true 10 | tags = [ 11 | "nomad", 12 | "control-plane" 13 | ] 14 | ssh_keys = [digitalocean_ssh_key.mrkaran.fingerprint] 15 | } 16 | 17 | # Attach the floating ip to droplet 18 | resource "digitalocean_floating_ip" "floyd" { 19 | droplet_id = digitalocean_droplet.floyd.id 20 | region = digitalocean_droplet.floyd.region 21 | } 22 | -------------------------------------------------------------------------------- /terraform/modules/digitalocean/output.tf: -------------------------------------------------------------------------------- 1 | output "floating_floyd" { 2 | value = digitalocean_floating_ip.floyd.ip_address 3 | description = "Floating IP of Floyd Node" 4 | } 5 | -------------------------------------------------------------------------------- /terraform/modules/digitalocean/project.tf: -------------------------------------------------------------------------------- 1 | # `hydra` tags all the resources assosciated with it under a project. 2 | resource "digitalocean_project" "hydra" { 3 | name = "hydra" 4 | description = "Self hosted Nomad cluster to deploy personal workloads" 5 | purpose = "Web Application" 6 | environment = "Production" 7 | # Tag the droplet IDs and Floating IPs. 8 | resources = [digitalocean_droplet.floyd.urn, digitalocean_floating_ip.floyd.urn] 9 | } 10 | 11 | -------------------------------------------------------------------------------- /terraform/modules/digitalocean/ssh.tf: -------------------------------------------------------------------------------- 1 | # Common SSH key which is attached to all servers. 2 | resource "digitalocean_ssh_key" "mrkaran" { 3 | name = "mrkaran.dev" 4 | public_key = file("~/.ssh/mrkaran_rsa.pub") 5 | } 6 | -------------------------------------------------------------------------------- /terraform/modules/digitalocean/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | digitalocean = { 4 | source = "digitalocean/digitalocean" 5 | } 6 | } 7 | required_version = ">= 0.13" 8 | } 9 | -------------------------------------------------------------------------------- /terraform/modules/doggo/conf/doggo.nomad: -------------------------------------------------------------------------------- 1 | job "doggo" { 2 | datacenters = ["hydra"] 3 | type = "service" 4 | 5 | group "app" { 6 | count = 1 7 | 8 | network { 9 | port "http" { 10 | to = 8080 11 | } 12 | } 13 | 14 | restart { 15 | attempts = 2 16 | interval = "2m" 17 | delay = "30s" 18 | mode = "fail" 19 | } 20 | 21 | task "web" { 22 | driver = "docker" 23 | 24 | service { 25 | name = "doggo-web" 26 | tags = ["doggo", "web"] 27 | port = "http" 28 | } 29 | 30 | config { 31 | image = "ghcr.io/mr-karan/doggo-api:v0.4.0" 32 | 33 | ports = ["http"] 34 | 35 | logging { 36 | type = "json-file" 37 | config { 38 | labels = "com.hashicorp.nomad.alloc_id,com.hashicorp.nomad.job_id,com.hashicorp.nomad.job_name,com.hashicorp.nomad.namespace,com.hashicorp.nomad.node_id,com.hashicorp.nomad.node_name,com.hashicorp.nomad.task_group_name,com.hashicorp.nomad.task_name" 39 | } 40 | } 41 | } 42 | 43 | resources { 44 | cpu = 200 45 | memory = 200 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /terraform/modules/doggo/job.tf: -------------------------------------------------------------------------------- 1 | resource "nomad_job" "app" { 2 | jobspec = templatefile("${path.module}/conf/doggo.nomad", { 3 | }) 4 | hcl2 { 5 | enabled = true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /terraform/modules/doggo/providers.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | nomad = { 4 | source = "hashicorp/nomad" 5 | version = "1.4.14" 6 | } 7 | } 8 | required_version = ">= 0.14" 9 | } 10 | -------------------------------------------------------------------------------- /terraform/modules/gitea/conf/app.ini.tpl: -------------------------------------------------------------------------------- 1 | ; This file lists the default values used by Gitea 2 | ; Sample file: https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini 3 | ; Docs: https://docs.gitea.io/en-us/config-cheat-sheet/ 4 | 5 | APP_NAME = Code by mrkaran 6 | RUN_MODE = prod 7 | RUN_USER = git 8 | 9 | [repository] 10 | ROOT = /data/git/repositories 11 | 12 | [repository.local] 13 | LOCAL_COPY_PATH = /data/gitea/tmp/local-repo 14 | 15 | [repository.upload] 16 | TEMP_PATH = /data/gitea/uploads 17 | 18 | [server] 19 | APP_DATA_PATH = /data/gitea 20 | DOMAIN = git.mrkaran.dev 21 | SSH_DOMAIN = koadings.mrkaran.dev 22 | HTTP_PORT = 3000 23 | ROOT_URL = https://git.mrkaran.dev/ 24 | DISABLE_SSH = false 25 | SSH_PORT = 4222 26 | SSH_LISTEN_PORT = 22 27 | LFS_START_SERVER = true 28 | LFS_CONTENT_PATH = /data/git/lfs 29 | LFS_JWT_SECRET = "${gitea_lfs_jwt_secret}" 30 | OFFLINE_MODE = true 31 | LANDING_PAGE = explore 32 | 33 | [ui] 34 | THEME_COLOR_META_TAG = "#6B46C1" 35 | 36 | [ui.meta] 37 | AUTHOR = Karan 38 | DESCRIPTION = Karan's self-hosted Gitea instance 39 | KEYWORDS = git, gitea, karan, git.mrkaran.dev, mrkaran 40 | 41 | [database] 42 | PATH = /data/gitea/gitea.db 43 | DB_TYPE = sqlite3 44 | HOST = localhost:3306 45 | NAME = gitea 46 | USER = root 47 | PASSWD = 48 | SCHEMA = 49 | SSL_MODE = disable 50 | CHARSET = utf8 51 | 52 | [indexer] 53 | ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve 54 | 55 | [session] 56 | PROVIDER_CONFIG = /data/gitea/sessions 57 | PROVIDER = file 58 | COOKIE_SECURE = true 59 | 60 | [picture] 61 | AVATAR_UPLOAD_PATH = /data/gitea/avatars 62 | REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars 63 | DISABLE_GRAVATAR = false 64 | ENABLE_FEDERATED_AVATAR = true 65 | 66 | [attachment] 67 | PATH = /data/gitea/attachments 68 | 69 | [log] 70 | ROOT_PATH = /data/gitea/log 71 | MODE = file 72 | LEVEL = info 73 | 74 | [security] 75 | INSTALL_LOCK = true 76 | SECRET_KEY = "${gitea_secret_key}" 77 | INTERNAL_TOKEN = "${gitea_internal_token}" 78 | 79 | [service] 80 | DISABLE_REGISTRATION = true 81 | REQUIRE_SIGNIN_VIEW = false 82 | REGISTER_EMAIL_CONFIRM = false 83 | ENABLE_NOTIFY_MAIL = false 84 | ALLOW_ONLY_EXTERNAL_REGISTRATION = false 85 | ENABLE_CAPTCHA = false 86 | DEFAULT_KEEP_EMAIL_PRIVATE = false 87 | DEFAULT_ALLOW_CREATE_ORGANIZATION = true 88 | DEFAULT_ENABLE_TIMETRACKING = true 89 | NO_REPLY_ADDRESS = noreply.localhost 90 | 91 | [oauth2] 92 | JWT_SECRET = "${gitea_oauth2_jwt_secret}" 93 | 94 | [mailer] 95 | ENABLED = false 96 | 97 | [openid] 98 | ENABLE_OPENID_SIGNIN = true 99 | ENABLE_OPENID_SIGNUP = true 100 | 101 | [metrics] 102 | ENABLED = true 103 | 104 | [cron] 105 | ENABLED = true 106 | RUN_AT_START = false 107 | 108 | [cron.archive_cleanup] 109 | RUN_AT_START = true 110 | SCHEDULE = @every 24h 111 | OLDER_THAN = 24h 112 | 113 | [cron.update_mirrors] 114 | SCHEDULE = @every 3h 115 | 116 | [cron.repo_health_check] 117 | SCHEDULE = @every 24h 118 | TIMEOUT = 60s 119 | 120 | [cron.check_repo_stats] 121 | RUN_AT_START = true 122 | SCHEDULE = @every 24h 123 | -------------------------------------------------------------------------------- /terraform/modules/gitea/conf/gitea.nomad: -------------------------------------------------------------------------------- 1 | job "gitea" { 2 | datacenters = ["hydra"] 3 | type = "service" 4 | 5 | group "app" { 6 | count = 1 7 | 8 | network { 9 | port "http" { 10 | to = 3000 11 | } 12 | 13 | port "ssh" { 14 | to = 22 15 | 16 | # Need a static assignment for SSH ops. 17 | static = 4222 18 | 19 | # SSH port on host only exposed to Tailscale IP. 20 | host_network = "tailscale" 21 | } 22 | } 23 | 24 | restart { 25 | attempts = 2 26 | interval = "2m" 27 | delay = "30s" 28 | mode = "fail" 29 | } 30 | 31 | task "web" { 32 | driver = "docker" 33 | 34 | service { 35 | name = "gitea-web" 36 | tags = ["gitea", "web"] 37 | port = "http" 38 | } 39 | 40 | service { 41 | name = "gitea-ssh" 42 | tags = ["gitea", "ssh"] 43 | port = "ssh" 44 | } 45 | 46 | config { 47 | image = "gitea/gitea:latest" 48 | 49 | ports = ["http", "ssh"] 50 | 51 | # Bind the config file to container. 52 | mount { 53 | type = "bind" 54 | source = "local/gitea.ini" 55 | target = "/data/gitea/conf/app.ini" 56 | } 57 | 58 | # Bind the data directory to preserve data. 59 | mount { 60 | type = "bind" 61 | target = "/data" 62 | source = "/data/gitea/" 63 | readonly = false 64 | } 65 | } 66 | 67 | template { 68 | data = <