├── .gitignore ├── roles ├── mattermost │ ├── handlers │ │ └── main.yml │ ├── templates │ │ ├── mattermost.conf.j2 │ │ ├── mattermost.service.j2 │ │ ├── init_script_rh6.j2 │ │ └── init_script_ubuntu.j2 │ └── tasks │ │ └── main.yml ├── nginx │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ ├── repository.yml │ │ └── main.yml │ └── templates │ │ └── mattermost.conf.j2 ├── letsencrypt │ ├── templates │ │ └── cli.ini.j2 │ └── tasks │ │ └── main.yml ├── postgres │ ├── tasks │ │ ├── main.yml │ │ ├── debian.yml │ │ └── redhat.yml │ └── files │ │ └── pg_hba.conf └── cron │ └── tasks │ └── main.yml ├── LICENSE.md ├── play.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | hosts 2 | *.swp 3 | *.retry 4 | testplay.yml 5 | -------------------------------------------------------------------------------- /roles/mattermost/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: start mattermost 3 | service: 4 | name: mattermost 5 | state: started 6 | -------------------------------------------------------------------------------- /roles/mattermost/templates/mattermost.conf.j2: -------------------------------------------------------------------------------- 1 | start on runlevel [2345] 2 | stop on runlevel [016] 3 | respawn 4 | chdir /opt/mattermost 5 | exec sudo -u {{ mattermost_user }} -g {{ mattermost_user }} bin/platform 6 | -------------------------------------------------------------------------------- /roles/nginx/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart nginx 3 | service: 4 | name: nginx 5 | state: restarted 6 | 7 | - name: start nginx 8 | service: 9 | name: nginx 10 | state: started 11 | -------------------------------------------------------------------------------- /roles/letsencrypt/templates/cli.ini.j2: -------------------------------------------------------------------------------- 1 | rsa-key-size = 4096 2 | 3 | email = {{ cert_email_address }} 4 | 5 | domains = {{ ansible_fqdn }} 6 | 7 | authenticator = standalone 8 | #webroot-path = /usr/share/nginx/html 9 | 10 | -------------------------------------------------------------------------------- /roles/mattermost/templates/mattermost.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Mattermost 3 | After=syslog.target network.target postgresql-9.4.service 4 | 5 | [Service] 6 | Type=simple 7 | WorkingDirectory=/opt/mattermost/bin 8 | User={{ mattermost_user }} 9 | ExecStart=/opt/mattermost/bin/platform 10 | PIDFile=/var/spool/mattermost/pid/master.pid 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /roles/postgres/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include_tasks: "{{ ansible_os_family | lower }}.yml" 3 | 4 | - name: ensure database is created 5 | become: true 6 | become_user: postgres 7 | postgresql_db: 8 | name: "{{ db_name }}" 9 | 10 | - name: ensure user has access to database 11 | become: yes 12 | become_user: postgres 13 | postgresql_user: 14 | db: "{{ db_name }}" 15 | name: "{{ db_user }}" 16 | password: "{{ db_password }}" 17 | priv: ALL 18 | 19 | - name: ensure user does not have unnecessary privilege 20 | become: yes 21 | become_user: postgres 22 | postgresql_user: 23 | name: "{{ db_user }}" 24 | role_attr_flags: NOSUPERUSER,NOCREATEDB 25 | 26 | # vim:ft=ansible: 27 | -------------------------------------------------------------------------------- /roles/postgres/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Add postgres repository key 3 | apt_key: 4 | url: https://www.postgresql.org/media/keys/ACCC4CF8.asc 5 | state: present 6 | 7 | - name: Add postgres apt repository 8 | apt_repository: 9 | repo: 'deb http://apt.postgresql.org/pub/repos/apt/ {{ ansible_distribution_release }}-pgdg main' 10 | state: present 11 | update_cache: yes 12 | 13 | - name: Ensure packages are installed 14 | apt: name={{item}} 15 | with_items: 16 | - postgresql-{{ postgres_version }} 17 | - libpq-dev 18 | - python-psycopg2 19 | 20 | - name: Enable and start postgres service 21 | service: 22 | name: postgresql 23 | enabled: yes 24 | state: started 25 | 26 | # vim:ft=ansible: 27 | -------------------------------------------------------------------------------- /roles/postgres/files/pg_hba.conf: -------------------------------------------------------------------------------- 1 | # TYPE DATABASE USER ADDRESS METHOD 2 | 3 | # "local" is for Unix domain socket connections only 4 | local all all peer 5 | # IPv4 local connections: 6 | host all all 127.0.0.1/32 password 7 | # IPv6 local connections: 8 | host all all ::1/128 ident 9 | # Allow replication connections from localhost, by a user with the 10 | # replication privilege. 11 | #local replication postgres peer 12 | #host replication postgres 127.0.0.1/32 ident 13 | #host replication postgres ::1/128 ident 14 | -------------------------------------------------------------------------------- /roles/nginx/tasks/repository.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Add nginx signing key (Debian/Ubuntu) 3 | apt_key: 4 | url: http://nginx.org/keys/nginx_signing.key 5 | state: present 6 | when: ansible_os_family == "Debian" 7 | 8 | - name: Add nginx repository 9 | apt_repository: 10 | repo: "{{ item }}" 11 | state: present 12 | update_cache: yes 13 | with_items: 14 | - 'deb http://nginx.org/packages/ubuntu/ {{ ansible_distribution_release }} nginx' 15 | - 'deb-src http://nginx.org/packages/ubuntu/ {{ ansible_distribution_release }} nginx' 16 | when: ansible_os_family == "Debian" 17 | 18 | - name: Add nginx repository 19 | yum_repository: 20 | name: nginx 21 | description: nginx repo 22 | baseurl: "http://nginx.org/packages/{{ ansible_distribution | lower }}/{{ ansible_distribution_major_version }}/$basearch/" 23 | gpgcheck: no 24 | state: present 25 | when: ansible_os_family == "RedHat" 26 | -------------------------------------------------------------------------------- /roles/nginx/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_tasks: repository.yml 3 | #Install the official nginx repository fdr supported OS's. Moved into a seperate file for readability. 4 | 5 | - name: install nginx 6 | package: 7 | name: nginx 8 | state: present 9 | 10 | - name: apply nginx config template to /etc/nginx/conf.d/mattermost.conf 11 | template: 12 | src: mattermost.conf.j2 13 | dest: /etc/nginx/conf.d/mattermost.conf 14 | notify: restart nginx 15 | 16 | - name: Allow nginx to connect to MatterMost 17 | command: setsebool httpd_can_network_connect true 18 | when: ansible_distribution == "RedHat" 19 | 20 | - name: Change nginx cache directory permissions 21 | file: 22 | path: /var/cache/nginx 23 | state: directory 24 | owner: nginx 25 | group: nginx 26 | recurse: yes 27 | when: ansible_distribution == "RedHat" 28 | notify: restart nginx 29 | 30 | - name: remove nginx default site 31 | file: 32 | path: /etc/nginx/conf.d/default.conf 33 | state: absent 34 | notify: restart nginx 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2017 Tyler Tomlinson 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 | -------------------------------------------------------------------------------- /roles/cron/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create cron job to automatically update SSL cert (non-systemd) 3 | cron: 4 | name: "Renew letsencrypt SSL certs" 5 | minute: "47" 6 | hour: "23" 7 | month: "*" 8 | day: "15" 9 | job: "service nginx stop && /opt/letsencrypt/letsencrypt-auto renew --quiet --no-self-upgrade && service nginx start" 10 | when: (ansible_os_family == "RedHat" and ansible_distribution_major_version is version("6", "=")) or (ansible_distribution == "Ubuntu" and ansible_distribution_major_version is version("14", "=")) 11 | 12 | - name: Create cron job to automatically update SSL cert (systemd) 13 | cron: 14 | name: "Renew letsencrypt SSL certs" 15 | minute: "47" 16 | hour: "23" 17 | month: "*" 18 | day: "15" 19 | job: "systemctl stop nginx && /opt/letsencrypt/letsencrypt-auto renew --quiet --no-self-upgrade && systemctl start nginx" 20 | when: (ansible_os_family == "RedHat" and ansible_distribution_major_version is version("7", ">=")) or (ansible_distribution == "Ubuntu" and ansible_distribution_major_version is version("16", ">=")) or (ansible_distribution == "Debian" and ansible_distribution_major_version is version("8", ">=")) 21 | -------------------------------------------------------------------------------- /play.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Define the host you want to run the playbook in a file called hosts 3 | # run "ansible-playbook play.yml -i hosts" from this directory 4 | - hosts: all 5 | remote_user: root 6 | become: yes 7 | gather_facts: no 8 | pre_tasks: 9 | - name: Install python 10 | raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal) 11 | changed_when: false 12 | 13 | - name: Gather Facts 14 | setup: 15 | 16 | vars: 17 | mattermost_version: 4.3.2 18 | postgres_version: 9.4 19 | 20 | # The user the mattermost process will run as. The group will match. 21 | mattermost_user: mattermost 22 | 23 | # These do not need to be edited. 24 | db_user: mmmost 25 | db_name: mattermost 26 | 27 | # Choose a secure password. It is recommended you create a random password using 28 | # an external utility. 29 | db_password: notReallyPassword 30 | 31 | # This is the email address you want to be attached to the letsencrypt certificate. It should be valid. 32 | cert_email_address: abc@123.com 33 | 34 | # This is the domain name to be used for letsencrypt. Be sure to point this at the host you're deploying to. 35 | mattermost_fqdn: mm.mydomain.com 36 | 37 | roles: 38 | - postgres 39 | - mattermost 40 | - letsencrypt 41 | - nginx 42 | - cron 43 | -------------------------------------------------------------------------------- /roles/letsencrypt/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install git 3 | package: 4 | name: git 5 | state: present 6 | 7 | - name: git clone letsencrypt/letsencrypt 8 | git: 9 | repo: https://github.com/letsencrypt/letsencrypt 10 | dest: /opt/letsencrypt/ 11 | 12 | - name: Install EPEL repository (CentOS/RHEL 6 only) 13 | yum: 14 | name: http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm 15 | state: present 16 | when: (ansible_os_family == "RedHat" and ansible_distribution_major_version == "6") 17 | 18 | - name: Enable RHEL Server Optional RPMs 19 | command: "subscription-manager repos --enable rhel-{{ ansible_distribution_major_version }}-server-optional-rpms" 20 | when: ansible_distribution == "RedHat" 21 | 22 | - name: Install letsencrypt dependencies (takes a while) 23 | command: /opt/letsencrypt/letsencrypt-auto --help ## This is a bit stupid but it installs the deps without input. 24 | 25 | - name: Create letsencrypt config file /opt/letsencrypt/cli.ini 26 | template: 27 | src: cli.ini.j2 28 | dest: /opt/letsencrypt/cli.ini 29 | 30 | - name: Let https through firewall (RHEL 7) 31 | firewalld: 32 | service: https 33 | permanent: true 34 | state: enabled 35 | immediate: true 36 | when: (ansible_distribution == "RedHat" and ansible_distribution_major_version == "7") 37 | 38 | - name: Let http through firewall (RHEL 7) 39 | firewalld: 40 | service: http 41 | permanent: true 42 | state: enabled 43 | immediate: true 44 | when: (ansible_distribution == "RedHat" and ansible_distribution_major_version == "7") 45 | 46 | - name: Stop and disable iptables (RHEL 6) 47 | service: 48 | name: iptables 49 | state: stopped 50 | enabled: no 51 | when: (ansible_distribution == "RedHat" and ansible_distribution_major_version == "6") 52 | 53 | - name: Get SSL certificate from letsencrypt 54 | command: /opt/letsencrypt/letsencrypt-auto certonly -d {{ mattermost_fqdn }} -c /opt/letsencrypt/cli.ini --agree-tos --non-interactive 55 | args: 56 | creates: /etc/letsencrypt/live/{{ mattermost_fqdn }}/fullchain.pem 57 | -------------------------------------------------------------------------------- /roles/nginx/templates/mattermost.conf.j2: -------------------------------------------------------------------------------- 1 | upstream backend { 2 | server 127.0.0.1:8065; 3 | } 4 | 5 | proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mattermost_cache:10m max_size=3g inactive=120m use_temp_path=off; 6 | 7 | # Redirect http to https 8 | server { 9 | listen 80 default_server; 10 | server_name {{ mattermost_fqdn }}; 11 | return 301 https://$server_name$request_uri; 12 | } 13 | 14 | server { 15 | listen 443 ssl http2; 16 | server_name {{ mattermost_fqdn }}; 17 | 18 | ssl on; 19 | ssl_certificate /etc/letsencrypt/live/{{ mattermost_fqdn }}/fullchain.pem; 20 | ssl_certificate_key /etc/letsencrypt/live/{{ mattermost_fqdn }}/privkey.pem; 21 | ssl_session_timeout 5m; 22 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 23 | ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; 24 | ssl_prefer_server_ciphers on; 25 | ssl_session_cache shared:SSL:10m; 26 | 27 | location ~ /api/v[0-9]+/(users/)?websocket$ { 28 | proxy_set_header Upgrade $http_upgrade; 29 | proxy_set_header Connection "upgrade"; 30 | client_max_body_size 50M; 31 | proxy_set_header Host $http_host; 32 | proxy_set_header X-Real-IP $remote_addr; 33 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 34 | proxy_set_header X-Forwarded-Proto $scheme; 35 | proxy_set_header X-Frame-Options SAMEORIGIN; 36 | proxy_buffers 256 16k; 37 | proxy_buffer_size 16k; 38 | proxy_read_timeout 600s; 39 | proxy_pass http://backend; 40 | } 41 | 42 | location / { 43 | client_max_body_size 50M; 44 | proxy_set_header Connection ""; 45 | proxy_set_header Host $http_host; 46 | proxy_set_header X-Real-IP $remote_addr; 47 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 48 | proxy_set_header X-Forwarded-Proto $scheme; 49 | proxy_set_header X-Frame-Options SAMEORIGIN; 50 | proxy_buffers 256 16k; 51 | proxy_buffer_size 16k; 52 | proxy_read_timeout 600s; 53 | proxy_cache mattermost_cache; 54 | proxy_cache_revalidate on; 55 | proxy_cache_min_uses 2; 56 | proxy_cache_use_stale timeout; 57 | proxy_cache_lock on; 58 | proxy_pass http://backend; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /roles/postgres/tasks/redhat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check to see if the second PostGres release is out 3 | uri: 4 | url: "https://download.postgresql.org/pub/repos/yum/{{ postgres_version }}/redhat/rhel-{{ ansible_distribution_major_version }}-{{ ansible_architecture | lower }}/pgdg-{{ ansible_distribution | lower }}{{ postgres_version | replace('.', '') }}-{{postgres_version }}-2.noarch.rpm" 5 | register: repo_test 6 | ignore_errors: yes 7 | no_log: true 8 | 9 | - name: Install postgres RPM repo (first release) 10 | yum: 11 | name: "https://download.postgresql.org/pub/repos/yum/{{ postgres_version }}/redhat/rhel-{{ ansible_distribution_major_version }}-{{ ansible_architecture | lower }}/pgdg-{{ ansible_distribution | lower }}{{ postgres_version | replace('.', '') }}-{{postgres_version }}-1.noarch.rpm" 12 | state: present 13 | when: repo_test.status == 404 14 | 15 | - name: Install postgres RPM repo (Second release) 16 | yum: 17 | name: "https://download.postgresql.org/pub/repos/yum/{{ postgres_version }}/redhat/rhel-{{ ansible_distribution_major_version }}-{{ ansible_architecture | lower }}/pgdg-{{ ansible_distribution | lower }}{{ postgres_version | replace('.', '') }}-{{postgres_version }}-2.noarch.rpm" 18 | state: present 19 | when: repo_test.status == 200 20 | 21 | - name: Install postgres packages and other deps 22 | yum: name={{item}} state=present 23 | with_items: 24 | - postgresql{{ postgres_version | replace('.', '') }}-server 25 | - postgresql{{ postgres_version | replace('.', '') }}-contrib 26 | - python-psycopg2 27 | - postgresql-libs 28 | - libselinux-python 29 | 30 | - name: Initialize postgres db 31 | command: service postgresql-{{ postgres_version }} initdb 32 | args: 33 | creates: /var/lib/pgsql/{{ postgres_version }}/data/postgresql.conf 34 | when: ansible_distribution_major_version is version("6", "=") 35 | 36 | - name: Initialize postgres db 37 | command: /usr/pgsql-{{ postgres_version }}/bin/postgresql{{ postgres_version | replace('.', '') }}-setup initdb 38 | args: 39 | creates: /var/lib/pgsql/{{ postgres_version }}/data/postgresql.conf 40 | when: ansible_distribution_major_version is version("7", ">=") 41 | 42 | - name: Enable and start postgres service 43 | service: 44 | name: postgresql-{{ postgres_version }} 45 | enabled: yes 46 | state: started 47 | 48 | # vim:ft=ansible: 49 | -------------------------------------------------------------------------------- /roles/mattermost/templates/init_script_rh6.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # chkconfig: 2345 90 90 3 | # description: mattermost 4 | ### BEGIN INIT INFO 5 | # Provides: program_name 6 | # Required-Start: network 7 | # Required-Stop: network 8 | # Default-Start: 2 3 4 5 9 | # Default-Stop: 0 1 6 10 | # Description: Init script to start mattermost service. 11 | ### END INIT INFO 12 | 13 | ### Fill in these bits: 14 | START_CMD="/opt/mattermost/bin/platform -config=\"/opt/mattermost/config/config.json\"" 15 | NAME="mattermost" 16 | PGREP_STRING="/opt/mattermost/bin/platform" 17 | PID_FILE="/var/run/mattermost/mattermost.pid" 18 | USER="{{ mattermost_user }}" 19 | 20 | ### No further muckin' about needed! 21 | 22 | CUR_USER=`whoami` 23 | 24 | killproc() { 25 | pkill -u $USER -f $PGREP_STRING 26 | } 27 | 28 | start_daemon() { 29 | eval "$*" 30 | } 31 | 32 | log_success_msg() { 33 | echo "$*" 34 | logger "$_" 35 | } 36 | 37 | log_failure_msg() { 38 | echo "$*" 39 | logger "$_" 40 | } 41 | 42 | check_proc() { 43 | pgrep -u $USER -f $PGREP_STRING >/dev/null 44 | } 45 | 46 | start_script() { 47 | if [ "${CUR_USER}" != "root" ] ; then 48 | log_failure_msg "$NAME can only be started as 'root'." 49 | exit -1 50 | fi 51 | 52 | check_proc 53 | if [ $? -eq 0 ]; then 54 | log_success_msg "$NAME is already running." 55 | exit 0 56 | fi 57 | 58 | [ -d /var/run/$NAME ] || (mkdir /var/run/$NAME ) 59 | 60 | # make go now 61 | start_daemon /bin/su $USER -c "$START_CMD" 62 | 63 | # Sleep for a while to see if anything cries 64 | sleep 5 65 | check_proc 66 | 67 | if [ $? -eq 0 ]; then 68 | log_success_msg "Started $NAME." 69 | else 70 | log_failure_msg "Error starting $NAME." 71 | exit -1 72 | fi 73 | } 74 | 75 | stop_script() { 76 | if [ "${CUR_USER}" != "root" ] ; then 77 | log_failure_msg "You do not have permission to stop $NAME." 78 | exit -1 79 | fi 80 | 81 | check_proc 82 | if [ $? -eq 0 ]; then 83 | killproc -p $PID_FILE >/dev/null 84 | 85 | # Make sure it's dead before we return 86 | until [ $? -ne 0 ]; do 87 | sleep 1 88 | check_proc 89 | done 90 | 91 | check_proc 92 | if [ $? -eq 0 ]; then 93 | log_failure_msg "Error stopping $NAME." 94 | exit -1 95 | else 96 | log_success_msg "Stopped $NAME." 97 | fi 98 | else 99 | log_failure_msg "$NAME is not running or you don't have permission to stop it" 100 | fi 101 | } 102 | 103 | check_status() { 104 | check_proc 105 | if [ $? -eq 0 ]; then 106 | log_success_msg "$NAME is running." 107 | else 108 | log_failure_msg "$NAME is stopped." 109 | exit -1 110 | fi 111 | } 112 | 113 | case "$1" in 114 | start) 115 | start_script 116 | ;; 117 | stop) 118 | stop_script 119 | ;; 120 | restart) 121 | stop_script 122 | start_script 123 | ;; 124 | status) 125 | check_status 126 | ;; 127 | *) 128 | echo "Usage: $0 {start|stop|restart|status}" 129 | exit 1 130 | esac 131 | 132 | exit 0 133 | -------------------------------------------------------------------------------- /roles/mattermost/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Download binary from MatterMost website 3 | get_url: 4 | url: https://releases.mattermost.com/{{ mattermost_version }}/mattermost-team-{{ mattermost_version }}-linux-amd64.tar.gz 5 | dest: /tmp/ 6 | when: (ansible_os_family == "RedHat" and ansible_distribution_major_version is version("7", ">=")) or (ansible_distribution == "Ubuntu" and ansible_distribution_major_version is version("16", ">=")) or (ansible_distribution == "Debian" and ansible_distribution_major_version is version("8", ">=")) 7 | 8 | - name: Download binary from MatterMost website (using wget because get_url fails if system python is older than 2.7.5) 9 | command: "wget https://releases.mattermost.com/{{ mattermost_version }}/mattermost-team-{{ mattermost_version }}-linux-amd64.tar.gz" 10 | args: 11 | chdir: /tmp/ 12 | creates: /tmp/mattermost-team-{{ mattermost_version }}-linux-amd64.tar.gz 13 | when: (ansible_os_family == "RedHat" and ansible_distribution_major_version is version("6", "=")) or (ansible_distribution == "Ubuntu" and ansible_distribution_major_version is version("14", "=")) 14 | 15 | - name: unpack mattermost archive 16 | unarchive: 17 | src: /tmp/mattermost-team-{{ mattermost_version }}-linux-amd64.tar.gz 18 | dest: /opt/ 19 | copy: no 20 | args: 21 | creates: /opt/mattermost/bin/platform 22 | 23 | - name: Edit /opt/mattermost/config/config.json 24 | lineinfile: 25 | dest: /opt/mattermost/config/config.json 26 | regexp: '"DriverName": "mysql",' 27 | line: ' "DriverName": "postgres",' 28 | backrefs: yes 29 | 30 | - name: Edit /opt/mattermost/config/config.json 31 | lineinfile: 32 | dest: /opt/mattermost/config/config.json 33 | regexp: '"DataSource":' 34 | line: ' "DataSource": "postgres://{{ db_user }}:{{ db_password }}@127.0.0.1:5432/{{ db_name }}?sslmode=disable&connect_timeout=10",' 35 | backrefs: yes 36 | 37 | - name: Create mattermost user 38 | user: 39 | name: "{{ mattermost_user }}" 40 | system: yes 41 | createhome: no 42 | 43 | - name: Create mattermost SystemV init script (Ubuntu 14.04) 44 | template: 45 | src: init_script_ubuntu.j2 46 | dest: /etc/init.d/mattermost 47 | owner: root 48 | group: root 49 | mode: 0755 50 | when: (ansible_distribution == "Ubuntu" and ansible_distribution_major_version is version("14", "=")) 51 | 52 | - name: Create mattermost upstart init script (RHEL/CentOS 6) 53 | template: 54 | src: mattermost.conf.j2 55 | dest: /etc/init/mattermost.conf 56 | owner: root 57 | group: root 58 | mode: 0644 59 | when: (ansible_os_family == "RedHat" and ansible_distribution_major_version is version("6", "=")) 60 | 61 | - name: Create mattermost systemd service (Ubuntu 16.04, RHEL/CentOS 7) 62 | template: 63 | src: mattermost.service.j2 64 | dest: /etc/systemd/system/mattermost.service 65 | owner: root 66 | group: root 67 | mode: 0664 68 | when: (ansible_os_family == "RedHat" and ansible_distribution_major_version is version("7", ">=")) or (ansible_distribution == "Ubuntu" and ansible_distribution_major_version is version("16", ">=")) or (ansible_distribution == "Debian" and ansible_distribution_major_version is version("8", ">=")) 69 | 70 | - name: Change mattermost directory permissions 71 | file: 72 | path: /opt/mattermost 73 | state: directory 74 | owner: "{{ mattermost_user }}" 75 | group: "{{ mattermost_user }}" 76 | recurse: yes 77 | 78 | - name: Enable Mattermost service 79 | service: 80 | name: mattermost 81 | enabled: yes 82 | state: started 83 | -------------------------------------------------------------------------------- /roles/mattermost/templates/init_script_ubuntu.j2: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### Source: https://github.com/mattermost/platform/blob/master/doc/install/Production-Debian.md 3 | ### BEGIN INIT INFO 4 | # Provides: mattermost 5 | # Required-Start: $network $syslog 6 | # Required-Stop: $network $syslog 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 0 1 6 9 | # Short-Description: Mattermost Group Chat 10 | # Description: Mattermost: An open-source Slack 11 | ### END INIT INFO 12 | 13 | PATH=/sbin:/usr/sbin:/bin:/usr/bin 14 | DESC="Mattermost" 15 | NAME=mattermost 16 | MATTERMOST_ROOT=/opt/mattermost 17 | MATTERMOST_GROUP={{ mattermost_user }} 18 | MATTERMOST_USER={{ mattermost_user }} 19 | DAEMON="$MATTERMOST_ROOT/bin/platform" 20 | PIDFILE=/var/run/$NAME.pid 21 | SCRIPTNAME=/etc/init.d/$NAME 22 | 23 | . /lib/lsb/init-functions 24 | 25 | do_start() { 26 | # Return 27 | # 0 if daemon has been started 28 | # 1 if daemon was already running 29 | # 2 if daemon could not be started 30 | start-stop-daemon --start --quiet \ 31 | --chuid $MATTERMOST_USER:$MATTERMOST_GROUP --chdir $MATTERMOST_ROOT --background \ 32 | --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ 33 | || return 1 34 | start-stop-daemon --start --quiet \ 35 | --chuid $MATTERMOST_USER:$MATTERMOST_GROUP --chdir $MATTERMOST_ROOT --background \ 36 | --make-pidfile --pidfile $PIDFILE --exec $DAEMON \ 37 | || return 2 38 | } 39 | 40 | # 41 | # Function that stops the daemon/service 42 | # 43 | do_stop() { 44 | # Return 45 | # 0 if daemon has been stopped 46 | # 1 if daemon was already stopped 47 | # 2 if daemon could not be stopped 48 | # other if a failure occurred 49 | start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \ 50 | --pidfile $PIDFILE --exec $DAEMON 51 | RETVAL="$?" 52 | [ "$RETVAL" = 2 ] && return 2 53 | # Wait for children to finish too if this is a daemon that forks 54 | # and if the daemon is only ever run from this initscript. 55 | # If the above conditions are not satisfied then add some other code 56 | # that waits for the process to drop all resources that could be 57 | # needed by services started subsequently. A last resort is to 58 | # sleep for some time. 59 | start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 \ 60 | --exec $DAEMON 61 | [ "$?" = 2 ] && return 2 62 | # Many daemons don't delete their pidfiles when they exit. 63 | rm -f $PIDFILE 64 | return "$RETVAL" 65 | } 66 | 67 | case "$1" in 68 | start) 69 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" 70 | do_start 71 | case "$?" in 72 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 73 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 74 | esac 75 | ;; 76 | stop) 77 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 78 | do_stop 79 | case "$?" in 80 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 81 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 82 | esac 83 | ;; 84 | status) 85 | status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? 86 | ;; 87 | restart|force-reload) 88 | # 89 | # If the "reload" option is implemented then remove the 90 | # 'force-reload' alias 91 | # 92 | log_daemon_msg "Restarting $DESC" "$NAME" 93 | do_stop 94 | case "$?" in 95 | 0|1) 96 | do_start 97 | case "$?" in 98 | 0) log_end_msg 0 ;; 99 | 1) log_end_msg 1 ;; # Old process is still running 100 | *) log_end_msg 1 ;; # Failed to start 101 | esac 102 | ;; 103 | *) 104 | # Failed to stop 105 | log_end_msg 1 106 | ;; 107 | esac 108 | ;; 109 | *) 110 | echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 111 | exit 3 112 | ;; 113 | esac 114 | 115 | exit 0 116 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Maintainer Wanted 2 | If someone would like to take over the maintenance of this repo, please submit an issue or PR. I originally wrote this as a way to learn ansible when I was in college, and no longer have the time/inclination to maintain it now that I have a real job - mostly working with ansible. 3 | 4 | # mattermost-ansible 5 | This is an Ansible Playbook that installs a standalone version of Mattermost, which is an open-source Slack alternative. 6 | This playbook installs Mattermost version 4.3.2 (Team Edition) by default. 7 | 8 | It downloads the binary from [mattermost.org](https://www.mattermost.org/download/). If you need to install the Enterprise 9 | edition, consult the Mattermost documentation. This playbook installs 10 | * `postgresql` - Database Server 11 | * `nginx` - Web Server (acts as a reverse proxy) 12 | * SSL certificates are automatically generated from the [letsencrypt](https://letsencrypt.org) project. A cron job is 13 | created that automatically renews the SSL certificates once a month. 14 | 15 | --- 16 | 17 | 18 | This playbook currently works with 19 | - [x] Ubuntu 14.04.5 LTS, Trusty Tahr (DigitalOcean) 20 | - [x] Ubuntu 16.04.2 LTS, Xenial Xerus (DigitalOcean) 21 | - [x] CentOS 6.9 (DigitalOcean) 22 | - [x] CentOS 7.3 (DigitalOcean) 23 | - [x] Red Hat Enterprise Linux 6.9 (Santiago) (Installed from RedHat DVD on a Vultr VPS) 24 | - [x] Red Hat Enterprise Linux 7.3 (Maipo) (Installed from RedHat DVD on a Vultr VPS) 25 | - [ ] Debian 7.11 Wheezy 26 | - [x] Debian 8.8 Jessie (thanks [fgbreel](https://github.com/fgbreel)!) 27 | 28 | 29 | --- 30 | I have no reason to think that versions of these operating systems installed locally or by other providers will not work, 31 | but I have not tested them. If you are going to run into an issue, it will probably be with the firewall, as DigitalOcean 32 | has very permissive firewall rules by default. If you are having an issue, try opening port `80` and `443`. 33 | 34 | ### Distro Specific Instructions/Info 35 | #### RHEL 6.8 36 | The playbook completely disables the `iptables` firewall. This is not strictly necessary, but I hate `iptables` with my 37 | whole body and I was tired of fighting with it. If you want or need it, you should re-enable it, but none of the required 38 | ports will be open. Even better, submit a PR that fixes this issue (so I don't have to do it). 39 | 40 | --- 41 | 42 | ## Usage 43 | * Install ansible with your package manager of choice. Ansible can also be installed via `pip`. This playbook was tested with Ansible 2.3.1 If you can, I would recommend running the most recent version of ansible. 44 | 45 | 46 | * Clone this repository. 47 | 48 | * Make sure that the server you are installing Mattermost is properly configured with a FQDN. You should also have root 49 | access via ssh. Reverse DNS should also be properly configured for letsencrypt to work. If you are using a cloud 50 | hosting provider, this should be trivial. 51 | 52 | 53 | * Edit `play.yml` and change the `vars` to reflect any changes you may want to make for your system. This playbook does 54 | not do a complete installation with full configuration of all of the Mattermost options, but rather installs it to the 55 | point where you can edit the relevant settings from within the web browser. 56 | 57 | 58 | * **You should *always* edit the email address and db_password fields.** 59 | 60 | 61 | * Create a `hosts` file in the project directory. It only needs to contain one line, which is the IP address of the server 62 | you wish to install Mattermost on. 63 | 64 | * Run `ansible-playbook play.yml -i hosts` from the top of level of the project directory. 65 | 66 | 67 | 68 | * Navigate to the FQDN of your server in a web browser. Consult the Mattermost documentation for further configuration 69 | options. 70 | 71 | --- 72 | 73 | ## Post-Install 74 | If you are planning to use MatterMost for any length of time, you should probably change the location of the 75 | data directory. A large volume of attached block storage would not be a bad idea. A working email server should also 76 | be configured for email notifications and invites. You can do most of this from within the browser without manually editing 77 | configuration files. 78 | 79 | --- 80 | 81 | ### Contributing 82 | Please submit pull requests! They make my day. 83 | 84 | ### Moving Forward 85 | I am currently working on porting this standalone playbook into a more defined Ansible role with a complete implementation of all the options in the Mattermost `config` file. You can check on the status of this project [here.](https://github.com/tjtoml/ansible-role-mattermost) 86 | --------------------------------------------------------------------------------