I bought OVH VPS at half price during Black Friday.
For the past few years, I ssh into the server and used the command to pull Docker images and config files from a git repo. This year, I tested out Ansible to automate setting up the VPS. The learning curve wasn’t too bad but I did run into a few problems here and there.
New User
This role starts firewall with ssh port, creates a new user for ssh and remove root ssh login.
- name : install unattended upgrade
apt :
name : "{{ item }}"
loop :
- unattended-upgrades
- fail2ban
- name : unattended upgrade config
template :
src : 10periodic.j2
dest : /etc/apt/apt.conf.d/10periodic
owner : root
group : root
mode : 0644
- name : start ufw with port 22
ufw :
state : enabled
rule : allow
port : 22
- name : Add a new user
user :
name : "{{ user_name }}"
groups : sudo
append : yes
shell : /bin/bash
password : "{{ user_password }}"
- name : Add ssh key
authorized_key :
user : "{{ user_name }}"
key : "{{ key_file }}"
- name : Setup ssh config
lineinfile :
path : /etc/ssh/sshd_config
regexp : "{{ item.regexp }}"
line : "{{ item.line }}"
loop :
- regexp : '^PasswordAuthentication'
line : 'PasswordAuthentication no'
- regexp : '^PermitRootLogin'
line : 'PermitRootLogin no'
notify :
- restart ssh
Secure VPS
This makes the server more secure and email me daily report. It’s pretty crazy how many ssh attempts my new VPS gets everyday.
- name : install postfix, fail2ban and logwatch
apt :
name : "{{ item }}"
update_cache : yes
loop :
- unattended-upgrades
- postfix
- logwatch
- fail2ban
- name : unattended upgrade config
template :
src : 10periodic.j2
dest : /etc/apt/apt.conf.d/10periodic
owner : root
group : root
mode : 0644
- name : Create fail2ban config
template :
src : jail.local.j2
dest : /etc/fail2ban/jail.local
owner : root
group : root
mode : 0644
notify :
- restart fail2ban
- name : Create postfix conf
template :
src : main.cf.j2
dest : "{{ postfix_conf_dir }}/main.cf"
owner : root
group : root
mode : 0644
- name : Create sasl password file
template :
src : mailgun.j2
dest : "{{ postfix_conf_dir }}/mailgun"
owner : root
group : root
mode : 0600
- name : Update postfix table
command : postmap "{{ postfix_conf_dir }}/mailgun"
notify :
- restart postfix
- name : Setup logwatch cron
lineinfile :
path : /etc/cron.daily/00logwatch
regexp : "^/usr/sbin/logwatch"
line : "/usr/sbin/logwatch --mailto {{ my_email }} --detail high"
Docker
I use gitlab to host some docker images. I utilise private repo to build docker images with sensitive data. I’m not sure it’s a good idea to keep username, password and api key inside images. Would it be better to expose those via env variables?
- name : Install packages
apt :
name : "{{ item }}"
update_cache : yes
loop :
- apt-transport-https
- ca-certificates
- python3-pip
- name : Add Docker's GPG key
apt_key :
url : https://download.docker.com/linux/ubuntu/gpg
id : 9DC858229FC7DD38854AE2D88D81803C0EBFCD88
- name : Add Docker repo
apt_repository :
repo : "{{ docker_apt_repo }}"
- name : Install docker
apt :
name : docker-ce
- name : Install docker compose
get_url :
url : "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-Linux-x86_64"
dest : /usr/local/bin/docker-compose
mode : 0755
- name : Install docker and docker-compose pip
pip :
name : "{{ item }}"
loop :
- docker
- docker-compose
- name : Add docker group
group :
name : docker
- name : Add user to docker group
user :
name : "{{ user_name }}"
groups : docker
append : yes
notify :
- reboot
- name : Log into gitlab docker repo
docker_login :
registry : registry.gitlab.com
username : "{{ gitlab_username }}"
password : "{{ gitlab_password }}"
config_path : "/home/{{ user_name }}/.docker/config.json"
- name : Copy docker-compose.yml to remote
template :
src : docker-compose.yml.j2
dest : "/home/{{ user_name }}/docker-compose.yml"
owner : "{{ user_name }}"
group : "{{ user_name }}"
- name : Start docker compose
become : false
docker_service :
project_src : "/home/{{ user_name }}"
VPN
- name: Add wireguard ppa
apt_repository:
repo: "ppa:wireguard/wireguard"
- name: Install wireguard
apt:
name: wireguard
- name: Allow forwarding
lineinfile:
path: /etc/sysctl.conf
regexp: "{{ item.regexp }}"
line: "{{item.line }}"
loop:
- regexp: '^#net.ipv4.ip_forward'
line: 'net.ipv4.ip_forward=1'
- regexp: '^#net.ipv6.conf.all.forwarding'
line: 'net.ipv6.conf.all.forwarding=1'
notify:
- restart sysctl
- name: Open ufw port
ufw:
state: enabled
rule: allow
port: "{{ wg_port }}"
- name: Create wg config
template:
src: wg.conf.j2
dest: "{{ wg_config_dir }}/wg.conf"
owner: root
group: root
mode: 0600
- name: Start wg
service:
name: wg-quick@wg
state: started
enabled: yes
- name: Allow ovh ipv6
template:
src: 50-cloud-init.yaml.j2
dest: "{{ netplan_config_dir }}/50-cloud-init.yaml"
owner: root
group: root
mode: 0644
when: (ansible_distribution == "Ubuntu" and ansible_distribution_major_version == "18")
notify:
- restart netplan