Go to production
This commit is contained in:
parent
0c962473ad
commit
b6e38107c2
3
deploy/.gitignore
vendored
Normal file
3
deploy/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
*.retry
|
||||||
|
.venv/
|
||||||
|
Pipfile.lock
|
5
deploy/README.md
Normal file
5
deploy/README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Run ansble
|
||||||
|
|
||||||
|
```
|
||||||
|
ansible-playbook website.yml
|
||||||
|
```
|
4
deploy/ansible.cfg
Normal file
4
deploy/ansible.cfg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[defaults]
|
||||||
|
inventory = inventory
|
||||||
|
nocows = 1
|
||||||
|
vault_password_file = ~/.ansible-hkis-vault
|
11
deploy/group_vars/all/vars
Normal file
11
deploy/group_vars/all/vars
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
ansible_python_interpreter: "/usr/bin/python3"
|
||||||
|
ansible_user: root
|
||||||
|
|
||||||
|
gandi_api_key: !vault |
|
||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
65306331316361633033373833316433313632336336653030623733363936643363393236393637
|
||||||
|
6635326137663133333038336665613566373365356364610a386437646238636336343965323730
|
||||||
|
61306638653939653437386530386663313338396266666136396637653061313036643730613335
|
||||||
|
6538613861643632310a386561343237303137633066343130333764353263663364326161653638
|
||||||
|
62313561333737313864303335626264636562626536613465326162323164666262
|
17
deploy/group_vars/all/vault
Normal file
17
deploy/group_vars/all/vault
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
65356533653563626232346137616263306533353638653434623434373466373639316433653261
|
||||||
|
6333616531306439383331313035306563656366303363610a646432353865323836396533343966
|
||||||
|
37383835633362616466646138666335663437393463346535656136373266313161336464316462
|
||||||
|
3335376432633766380a666437356434656564636536313162663630643034373338653366313334
|
||||||
|
32346562386136353531373361346139363733626261383031633762326137383031326136646563
|
||||||
|
63313939356236626138366538616361636230633530303633646562366237626462383736373262
|
||||||
|
37636632393839636531333237356537646465613962353835636262653531333063386338366139
|
||||||
|
63663563393134663064623461326537663935323832383730313863613130396633323533366566
|
||||||
|
66313465383931393965386261653233333039383363333364613163393637306134393762396262
|
||||||
|
37666164313661633866643037656466623136646161366531323433386639633334333236313337
|
||||||
|
62343835303461636330326531333564376630633339343030336163643566363930383531663861
|
||||||
|
32353961646336326238636236303539626661303864626135626638613865373738373131316365
|
||||||
|
66313666393331646235643664633061653162633962303664336263643466316632303738303833
|
||||||
|
36616439343238383463396139626134336131363666313164373033333964626630386463653134
|
||||||
|
34623263666433326530376665313962373531383966646534336336363136336463633037633065
|
||||||
|
35663537343339393866
|
2
deploy/inventory
Normal file
2
deploy/inventory
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[website]
|
||||||
|
eqy.fr
|
1
deploy/requirements.txt
Normal file
1
deploy/requirements.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ansible
|
7
deploy/roles/common/handlers/main.yml
Normal file
7
deploy/roles/common/handlers/main.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: sshd
|
||||||
|
service: name=sshd state=reloaded
|
||||||
|
|
||||||
|
- name: nftables
|
||||||
|
service: name=nftables state=reloaded
|
93
deploy/roles/common/tasks/common.yml
Normal file
93
deploy/roles/common/tasks/common.yml
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Configure hostname
|
||||||
|
hostname:
|
||||||
|
name: "{{ inventory_hostname_short }}"
|
||||||
|
|
||||||
|
- name: Configure FQDN
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/hosts
|
||||||
|
regexp: '^127\.0\.0\.1'
|
||||||
|
line: "127.0.0.1 {{ inventory_hostname }} {{ inventory_hostname_short }} localhost"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
|
- name: apt-get some packages
|
||||||
|
apt:
|
||||||
|
state: present
|
||||||
|
name:
|
||||||
|
- aptitude
|
||||||
|
- fail2ban
|
||||||
|
- nftables
|
||||||
|
- python3
|
||||||
|
- python3-dev
|
||||||
|
- python3-pip
|
||||||
|
- python3-venv
|
||||||
|
- rsync
|
||||||
|
|
||||||
|
- name: nftable service is started
|
||||||
|
service:
|
||||||
|
name: nftables
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Copy nftables config
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
#!/usr/sbin/nft -f
|
||||||
|
|
||||||
|
table inet filter
|
||||||
|
flush table inet filter
|
||||||
|
|
||||||
|
table inet filter {
|
||||||
|
chain input {
|
||||||
|
type filter hook input priority 0;
|
||||||
|
iif lo accept
|
||||||
|
ct state established,related accept
|
||||||
|
tcp dport { ssh, http, https } ct state new accept
|
||||||
|
# accept neighbour discovery otherwise connectivity breaks:
|
||||||
|
icmpv6 type { echo-request, nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
|
||||||
|
ip protocol icmp icmp type { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } accept
|
||||||
|
counter drop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest: /etc/nftables.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0755
|
||||||
|
notify: nftables
|
||||||
|
|
||||||
|
- name: Set some authorized keys
|
||||||
|
authorized_key: user=root key="{{item}}"
|
||||||
|
with_items:
|
||||||
|
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKA7DgTQ0G7+kdsX0lIUOAAOllwGSCu8s8TxPvr/61Y8q+pIO5mrZycI0xYcKP5NZaABqlFyXUUNfLj7RLqteBxqq2QZP4NOJ1MutYRIkzJ9YW0f565jHaOqSguz0MY+1sCHtuEPiUUZoNexkKN7SIx60SfoaMEvGjAj46txA7VFbJUuKcJtA1Yvmn0C0KoXUUQ/G+JqvjQ7QuKLQYdTZ8S9OEvNaqNfwNSwvy1/LCnuajFw0O+H5bz7AcS5Iuj+9k8wgHPK1a1rQEdteOcn2XBCvta/VOVlFLv6/9K3iU3EJ1pyaZ88UkuJef8aWnH/AJGaF2gLqUbBuL+UeXyD41 julien+yubikey4@palard.fr"
|
||||||
|
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8vv8vwmbyhFEa0chj8LklnnY6DRLKj2OM0NgaMTd9SsrtBeLMqTt34pU+kKl6/9EIe9P8Z1/fWFyOiTsE7Khf3rkNsoILPmEV14i18Bvtp4nMtljqZaKVkAcRjPvo7flRWNxxL2Zbo+BEr3wVCl3Sc6YV8oQzCwVPKf34AB39b+PW4f3580Aqcd4Ci6zca0Ol95tLDv1slX1A7QcpoZAne8kj5h6bb4cC7FLBC9+xOSKmzoLOlP7LsyxaUUGRyi/FeMoma1VES65aIJ5U23GtZrzZI3tKz+vpQvOVaozNTDkNLiiJkjd3Ew1I10wArpZixjwSndP8CvGFyJc1XUXZ julien+yubikey5@palard.fr"
|
||||||
|
|
||||||
|
- name: Drop mlocate or locate
|
||||||
|
apt:
|
||||||
|
name: ["mlocate", "locate"]
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
# From https://infosec.mozilla.org/guidelines/openssh
|
||||||
|
- name: SSHd hardening
|
||||||
|
blockinfile:
|
||||||
|
marker: "# {mark} ANSIBLE MANAGED BLOCK (KexAlgorithms, Ciphers, MACs)"
|
||||||
|
path: /etc/ssh/sshd_config
|
||||||
|
state: present
|
||||||
|
create: yes
|
||||||
|
block: |
|
||||||
|
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
|
||||||
|
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
|
||||||
|
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
|
||||||
|
|
||||||
|
HostKey /etc/ssh/ssh_host_ed25519_key
|
||||||
|
HostKey /etc/ssh/ssh_host_rsa_key
|
||||||
|
HostKey /etc/ssh/ssh_host_ecdsa_key
|
||||||
|
|
||||||
|
AuthenticationMethods publickey
|
||||||
|
LogLevel VERBOSE
|
||||||
|
notify: sshd
|
||||||
|
tags: ssh
|
7
deploy/roles/common/tasks/main.yml
Normal file
7
deploy/roles/common/tasks/main.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- include_role:
|
||||||
|
name: exim4
|
||||||
|
|
||||||
|
- include_tasks: common.yml
|
||||||
|
tags: common
|
21
deploy/roles/exim4/LICENSE.txt
Normal file
21
deploy/roles/exim4/LICENSE.txt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016 Tobias Schifftner, ambimax® GmbH
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
23
deploy/roles/exim4/defaults/main.yml
Normal file
23
deploy/roles/exim4/defaults/main.yml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
exim4_sendonly_fqdn: '{{ ansible_fqdn }}'
|
||||||
|
|
||||||
|
exim4_aws_access_key_id: ''
|
||||||
|
exim4_aws_secret_access_key: ''
|
||||||
|
|
||||||
|
exim4_aws_ses_region: 'eu-west-1'
|
||||||
|
|
||||||
|
exim4_sendonly_enable_tls: true
|
||||||
|
exim4_sendonly_smarthost: ''
|
||||||
|
exim4_sendonly_username: ''
|
||||||
|
exim4_sendonly_password: ''
|
||||||
|
|
||||||
|
exim4_sendonly_email_addresses: []
|
||||||
|
# root: 'your@email.com'
|
||||||
|
|
||||||
|
exim4_sendonly_email_aliases: []
|
||||||
|
# - regexp: '^root:'
|
||||||
|
# line: 'root: your@email.com'
|
||||||
|
|
||||||
|
exim4_sendonly_apt_packages:
|
||||||
|
- exim4-daemon-light
|
||||||
|
- mailutils
|
14
deploy/roles/exim4/files/logrotate
Normal file
14
deploy/roles/exim4/files/logrotate
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/var/mail/* {
|
||||||
|
su root mail
|
||||||
|
daily
|
||||||
|
missingok
|
||||||
|
rotate 8
|
||||||
|
size 5M
|
||||||
|
maxage 30
|
||||||
|
notifempty
|
||||||
|
compress
|
||||||
|
delaycompress
|
||||||
|
notifempty
|
||||||
|
create 0640 root root
|
||||||
|
sharedscripts
|
||||||
|
}
|
6
deploy/roles/exim4/handlers/main.yml
Normal file
6
deploy/roles/exim4/handlers/main.yml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
- name: restart exim4
|
||||||
|
service:
|
||||||
|
name: 'exim4'
|
||||||
|
state: restarted
|
||||||
|
enabled: yes
|
50
deploy/roles/exim4/tasks/configure.yml
Normal file
50
deploy/roles/exim4/tasks/configure.yml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Configure exim4
|
||||||
|
notify: restart exim4
|
||||||
|
template:
|
||||||
|
src: 'update-exim4.conf.conf'
|
||||||
|
dest: /etc/exim4/update-exim4.conf.conf
|
||||||
|
|
||||||
|
- name: Update mailname
|
||||||
|
notify: restart exim4
|
||||||
|
copy:
|
||||||
|
content: '{{ exim4_sendonly_fqdn }}'
|
||||||
|
dest: '/etc/mailname'
|
||||||
|
|
||||||
|
- name: Define email aliases
|
||||||
|
notify: restart exim4
|
||||||
|
lineinfile:
|
||||||
|
dest: /etc/aliases
|
||||||
|
regexp: "{{ item.regexp }}"
|
||||||
|
line: "{{ item.line }}"
|
||||||
|
with_items: '{{ exim4_sendonly_email_aliases }}'
|
||||||
|
when: exim4_sendonly_email_aliases|length
|
||||||
|
|
||||||
|
- name: Define email addresses
|
||||||
|
notify: restart exim4
|
||||||
|
template:
|
||||||
|
src: 'email-addresses.j2'
|
||||||
|
dest: '/etc/email-addresses'
|
||||||
|
when: exim4_sendonly_email_addresses|length
|
||||||
|
|
||||||
|
- name: Set auth for relay host
|
||||||
|
notify: restart exim4
|
||||||
|
template:
|
||||||
|
src: 'passwd.client'
|
||||||
|
dest: '/etc/exim4/passwd.client'
|
||||||
|
|
||||||
|
- name: Enable TLS
|
||||||
|
notify: restart exim4
|
||||||
|
template:
|
||||||
|
src: 'exim4.conf.localmacros'
|
||||||
|
dest: '/etc/exim4/exim4.conf.localmacros'
|
||||||
|
when: exim4_sendonly_enable_tls
|
||||||
|
|
||||||
|
- name: 'Set logrotate for local user mails in /var/mail'
|
||||||
|
copy:
|
||||||
|
src: 'logrotate'
|
||||||
|
dest: /etc/logrotate.d/local_user_mails
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
7
deploy/roles/exim4/tasks/install.yml
Normal file
7
deploy/roles/exim4/tasks/install.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Install exim4 packages
|
||||||
|
apt:
|
||||||
|
name: '{{ exim4_sendonly_apt_packages }}'
|
||||||
|
state: present
|
||||||
|
cache_valid_time: 86400
|
15
deploy/roles/exim4/tasks/main.yml
Normal file
15
deploy/roles/exim4/tasks/main.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Install exim4
|
||||||
|
import_tasks: install.yml
|
||||||
|
|
||||||
|
- name: Configure exim4
|
||||||
|
import_tasks: configure.yml
|
||||||
|
|
||||||
|
- name: Start exim4
|
||||||
|
service:
|
||||||
|
name: exim4
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
changed_when: false
|
||||||
|
tags: ['always']
|
3
deploy/roles/exim4/templates/email-addresses.j2
Normal file
3
deploy/roles/exim4/templates/email-addresses.j2
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{% for user, email in exim4_sendonly_email_addresses.items() %}
|
||||||
|
{{ user }}: {{ email }}
|
||||||
|
{% endfor %}
|
1
deploy/roles/exim4/templates/exim4.conf.localmacros
Normal file
1
deploy/roles/exim4/templates/exim4.conf.localmacros
Normal file
|
@ -0,0 +1 @@
|
||||||
|
MAIN_TLS_ENABLE = 1
|
10
deploy/roles/exim4/templates/passwd.client
Normal file
10
deploy/roles/exim4/templates/passwd.client
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# password file used when the local exim is authenticating to a remote
|
||||||
|
# host as a client.
|
||||||
|
#
|
||||||
|
# see exim4_passwd_client(5) for more documentation
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
### target.mail.server.example:login:password
|
||||||
|
{% if exim4_sendonly_username != '' %}
|
||||||
|
*:{{ exim4_sendonly_username }}:{{ exim4_sendonly_password }}
|
||||||
|
{% endif %}
|
30
deploy/roles/exim4/templates/update-exim4.conf.conf
Normal file
30
deploy/roles/exim4/templates/update-exim4.conf.conf
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# /etc/exim4/update-exim4.conf.conf
|
||||||
|
#
|
||||||
|
# Edit this file and /etc/mailname by hand and execute update-exim4.conf
|
||||||
|
# yourself or use 'dpkg-reconfigure exim4-config'
|
||||||
|
#
|
||||||
|
# Please note that this is _not_ a dpkg-conffile and that automatic changes
|
||||||
|
# to this file might happen. The code handling this will honor your local
|
||||||
|
# changes, so this is usually fine, but will break local schemes that mess
|
||||||
|
# around with multiple versions of the file.
|
||||||
|
#
|
||||||
|
# update-exim4.conf uses this file to determine variable values to generate
|
||||||
|
# exim configuration macros for the configuration file.
|
||||||
|
#
|
||||||
|
# Most settings found in here do have corresponding questions in the
|
||||||
|
# Debconf configuration, but not all of them.
|
||||||
|
#
|
||||||
|
# This is a Debian specific file
|
||||||
|
dc_eximconfig_configtype="{{ 'internet' if exim4_sendonly_smarthost == '' else 'satellite' }}"
|
||||||
|
dc_other_hostnames='{{ ansible_hostname }}; localhost.localdomain; localhost'
|
||||||
|
dc_local_interfaces='127.0.0.1'
|
||||||
|
dc_readhost=''
|
||||||
|
dc_relay_domains=''
|
||||||
|
dc_minimaldns='false'
|
||||||
|
dc_relay_nets=''
|
||||||
|
dc_smarthost='{{ exim4_sendonly_smarthost }}'
|
||||||
|
CFILEMODE='644'
|
||||||
|
dc_use_split_config='true'
|
||||||
|
dc_hide_mailname='true'
|
||||||
|
dc_mailname_in_oh='true'
|
||||||
|
dc_localdelivery='mail_spool'
|
10
deploy/roles/letsencrypt/README.md
Normal file
10
deploy/roles/letsencrypt/README.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Letsencrypt role
|
||||||
|
|
||||||
|
This role uses the standalone mode of certbot if no webserver is
|
||||||
|
running (typically during the first installation), else uses the nginx
|
||||||
|
module.
|
||||||
|
|
||||||
|
Note that existing certificates are renewed (using the nginx module)
|
||||||
|
as a cron task/systemd timer.
|
||||||
|
|
||||||
|
It creates snippets in `/etc/nginx/snippets/letsencrypt-{{ fqdn }}.conf`.
|
3
deploy/roles/letsencrypt/defaults/main.yml
Normal file
3
deploy/roles/letsencrypt/defaults/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
domains: [example.com]
|
66
deploy/roles/letsencrypt/tasks/main.yml
Normal file
66
deploy/roles/letsencrypt/tasks/main.yml
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Install ca-certificates
|
||||||
|
apt:
|
||||||
|
state: present
|
||||||
|
name: [cron, ca-certificates, nginx]
|
||||||
|
|
||||||
|
- name: Setup or upgrade venv
|
||||||
|
command: python3 -m venv --upgrade-deps /root/certbot-venv/
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Prepare certbot+gandi venv
|
||||||
|
pip:
|
||||||
|
chdir: /root/
|
||||||
|
virtualenv_command: /usr/bin/python3 -m venv
|
||||||
|
virtualenv: /root/certbot-venv/
|
||||||
|
state: latest
|
||||||
|
name:
|
||||||
|
- pip
|
||||||
|
|
||||||
|
- name: Install certbot+gandi in venv
|
||||||
|
pip:
|
||||||
|
chdir: /root/
|
||||||
|
state: latest
|
||||||
|
virtualenv_command: /usr/bin/python3 -m venv
|
||||||
|
virtualenv: /root/certbot-venv/
|
||||||
|
name:
|
||||||
|
- certbot
|
||||||
|
- certbot-plugin-gandi
|
||||||
|
|
||||||
|
- name: Setup Gandi credentials
|
||||||
|
copy:
|
||||||
|
content: "dns_gandi_api_key = {{ gandi_api_key }}"
|
||||||
|
mode: 0600
|
||||||
|
dest: /root/gandi.ini
|
||||||
|
|
||||||
|
- name: Create SSL dhparam
|
||||||
|
get_url:
|
||||||
|
url: https://ssl-config.mozilla.org/ffdhe2048.txt
|
||||||
|
dest: /etc/ssl/certs/dhparam.pem
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
|
- name: Generate TLS certificates
|
||||||
|
command: /root/certbot-venv/bin/certbot certonly --cert-name {{ cert_name | quote }} -n --agree-tos -d {{ domains | join(",") | quote }} -m {{ admin_email | quote }} --authenticator dns-gandi --dns-gandi-credentials /root/gandi.ini
|
||||||
|
register: certbot
|
||||||
|
changed_when: '"no action taken." not in certbot.stdout'
|
||||||
|
|
||||||
|
- name: Create letsencrypt snippets
|
||||||
|
template:
|
||||||
|
src: letsencrypt.conf.j2
|
||||||
|
dest: '/etc/nginx/snippets/letsencrypt-{{ cert_name }}.conf'
|
||||||
|
|
||||||
|
- name: Setup renewal cron
|
||||||
|
cron:
|
||||||
|
name: certbot
|
||||||
|
minute: "55"
|
||||||
|
hour: "8"
|
||||||
|
job: '/root/certbot-venv/bin/certbot -q renew'
|
||||||
|
|
||||||
|
- name: Setup renewal hook to reload nginx
|
||||||
|
copy:
|
||||||
|
mode: 0755
|
||||||
|
content: |
|
||||||
|
#!/bin/sh
|
||||||
|
systemctl reload nginx
|
||||||
|
dest: /etc/letsencrypt/renewal-hooks/deploy/01-reload-nginx
|
29
deploy/roles/letsencrypt/templates/letsencrypt.conf.j2
Normal file
29
deploy/roles/letsencrypt/templates/letsencrypt.conf.j2
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# https://ssl-config.mozilla.org/
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/{{ cert_name }}/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/{{ cert_name }}/privkey.pem;
|
||||||
|
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
|
||||||
|
ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
||||||
|
|
||||||
|
# intermediate configuration
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
|
|
||||||
|
# OCSP stapling
|
||||||
|
ssl_stapling on;
|
||||||
|
ssl_stapling_verify on;
|
||||||
|
|
||||||
|
# verify chain of trust of OCSP response using Root CA and Intermediate certs
|
||||||
|
ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
||||||
|
|
||||||
|
# replace with the IP address of your resolver
|
||||||
|
resolver 155.133.140.130;
|
19
deploy/roles/website/files/systemd/website.service
Normal file
19
deploy/roles/website/files/systemd/website.service
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[Unit]
|
||||||
|
Description=website daemon
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
PIDFile=/opt/website/website.pid
|
||||||
|
User=website
|
||||||
|
Group=website
|
||||||
|
WorkingDirectory=/opt/website/src
|
||||||
|
ExecStart=/opt/website/venv/bin/gunicorn --pid /opt/website/website.pid \
|
||||||
|
--bind unix:/opt/website/website.sock --timeout 60 eqy_fr.wsgi \
|
||||||
|
--access-logfile -
|
||||||
|
ExecReload=/bin/kill -s HUP $MAINPID
|
||||||
|
ExecStop=/bin/kill -s TERM $MAINPID
|
||||||
|
PrivateTmp=true
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
10
deploy/roles/website/handlers/main.yml
Normal file
10
deploy/roles/website/handlers/main.yml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: restart website
|
||||||
|
systemd: name=website state=restarted daemon_reload=yes
|
||||||
|
|
||||||
|
- name: reload nginx
|
||||||
|
service: name=nginx state=reloaded
|
||||||
|
|
||||||
|
- name: reload psql
|
||||||
|
service: name=postgresql state=reloaded
|
4
deploy/roles/website/meta/main.yml
Normal file
4
deploy/roles/website/meta/main.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- role: letsencrypt
|
212
deploy/roles/website/tasks/main.yml
Normal file
212
deploy/roles/website/tasks/main.yml
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
apt:
|
||||||
|
state: present
|
||||||
|
name:
|
||||||
|
- cron
|
||||||
|
- gettext
|
||||||
|
- git
|
||||||
|
- nginx
|
||||||
|
- postgresql
|
||||||
|
- postgresql-server-dev-all # To compile Python client.
|
||||||
|
- pgbadger
|
||||||
|
- python3
|
||||||
|
- python3-pip
|
||||||
|
- python3-psycopg2
|
||||||
|
- python3-venv
|
||||||
|
update_cache: true
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: Add unix user website
|
||||||
|
user:
|
||||||
|
name: website
|
||||||
|
shell: /bin/false
|
||||||
|
system: yes
|
||||||
|
home: /opt/website
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: install website.service (systemd)
|
||||||
|
copy:
|
||||||
|
src: systemd/website.service
|
||||||
|
dest: /etc/systemd/system/website.service
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0644
|
||||||
|
notify: restart website
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: add user website to pgsql
|
||||||
|
become: true
|
||||||
|
become_user: postgres
|
||||||
|
postgresql_user:
|
||||||
|
user: website
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: add database media
|
||||||
|
become: true
|
||||||
|
become_user: postgres
|
||||||
|
postgresql_db:
|
||||||
|
name: media
|
||||||
|
owner: website
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: Collect PostgreSQL version and extensions
|
||||||
|
become: yes
|
||||||
|
become_user: postgres
|
||||||
|
postgresql_info:
|
||||||
|
filter: ver*
|
||||||
|
register: db_info
|
||||||
|
|
||||||
|
- name: Configure psql
|
||||||
|
notify: reload psql
|
||||||
|
copy:
|
||||||
|
dest: "/etc/postgresql/{{ db_info.version.major }}/main/conf.d/media.conf"
|
||||||
|
owner: postgres
|
||||||
|
group: postgres
|
||||||
|
mode: 0644
|
||||||
|
content: |
|
||||||
|
log_min_duration_statement = 0
|
||||||
|
log_checkpoints = on
|
||||||
|
log_connections = on
|
||||||
|
log_disconnections = on
|
||||||
|
log_lock_waits = on
|
||||||
|
log_temp_files = 0
|
||||||
|
log_autovacuum_min_duration = 0
|
||||||
|
log_error_verbosity = default
|
||||||
|
lc_messages='en_US.UTF-8'
|
||||||
|
lc_messages='C'
|
||||||
|
|
||||||
|
- name: Synchronize source
|
||||||
|
ansible.posix.synchronize:
|
||||||
|
src: /home/mdk/eqy.fr/
|
||||||
|
dest: /opt/website/src/
|
||||||
|
notify: restart website
|
||||||
|
|
||||||
|
- name: Creates a /opt/website/venv for virtual environments
|
||||||
|
file:
|
||||||
|
path: /opt/website/venv
|
||||||
|
state: directory
|
||||||
|
mode: 0755
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: Setup or upgrade venv
|
||||||
|
command: python3 -m venv --upgrade-deps /opt/website/venv
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Creates a /opt/website/locale for translations
|
||||||
|
file:
|
||||||
|
path: /opt/website/locale
|
||||||
|
state: directory
|
||||||
|
mode: 0755
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: Creates a /opt/website/media for medias
|
||||||
|
file:
|
||||||
|
path: /opt/website/media
|
||||||
|
state: directory
|
||||||
|
mode: 0755
|
||||||
|
owner: website
|
||||||
|
group: website
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: Creates a /opt/website/static for static
|
||||||
|
file:
|
||||||
|
path: /opt/website/locale
|
||||||
|
state: directory
|
||||||
|
mode: 0755
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: pip installs requirements
|
||||||
|
pip:
|
||||||
|
chdir: /opt/website/src
|
||||||
|
requirements: requirements.txt
|
||||||
|
virtualenv: /opt/website/venv
|
||||||
|
virtualenv_command: /usr/bin/python3 -m venv
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: pip installs psycopg2
|
||||||
|
pip:
|
||||||
|
chdir: /opt/website/src
|
||||||
|
name: psycopg2
|
||||||
|
virtualenv: /opt/website/venv
|
||||||
|
virtualenv_command: /usr/bin/python3 -m venv
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: pip installs gunicorn
|
||||||
|
pip:
|
||||||
|
chdir: /opt/website/src
|
||||||
|
name: gunicorn
|
||||||
|
virtualenv: /opt/website/venv
|
||||||
|
virtualenv_command: /usr/bin/python3 -m venv
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: Install website configuration
|
||||||
|
template:
|
||||||
|
src: local_settings.py.j2
|
||||||
|
dest: /opt/website/src/local_settings.py
|
||||||
|
owner: root
|
||||||
|
group: website
|
||||||
|
mode: 0640
|
||||||
|
notify: restart website
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: Migrate db
|
||||||
|
command: "/opt/website/venv/bin/python manage.py migrate"
|
||||||
|
args:
|
||||||
|
chdir: "/opt/website/src"
|
||||||
|
register: migrate_result
|
||||||
|
changed_when: '" Applying " in migrate_result.stdout'
|
||||||
|
run_once: true
|
||||||
|
become: true
|
||||||
|
become_user: website
|
||||||
|
tags: [website, test]
|
||||||
|
|
||||||
|
- name: Collectstatic
|
||||||
|
command: "/opt/website/venv/bin/python manage.py collectstatic --noinput"
|
||||||
|
args:
|
||||||
|
chdir: "/opt/website/src"
|
||||||
|
register: collectstatic_result
|
||||||
|
changed_when: '"Copying " in collectstatic_result.stdout'
|
||||||
|
tags: [website, test]
|
||||||
|
|
||||||
|
- name: Compile gettext
|
||||||
|
command: "/opt/website/venv/bin/python manage.py compilemessages"
|
||||||
|
args:
|
||||||
|
chdir: "/opt/website/src"
|
||||||
|
notify: restart website
|
||||||
|
tags: [website, test]
|
||||||
|
|
||||||
|
- name: Ensure website is running
|
||||||
|
service: name=website state=started enabled=yes
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: Configure nginx host
|
||||||
|
template:
|
||||||
|
src: nginx-vhost
|
||||||
|
dest: "/etc/nginx/sites-available/{{ website_vhost }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0644
|
||||||
|
notify: reload nginx
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: Create symlink for API nginx site
|
||||||
|
file:
|
||||||
|
src: "/etc/nginx/sites-available/{{ website_vhost }}"
|
||||||
|
dest: "/etc/nginx/sites-enabled/{{ website_vhost }}"
|
||||||
|
state: link
|
||||||
|
notify: reload nginx
|
||||||
|
tags: website
|
||||||
|
|
||||||
|
- name: Daily backup
|
||||||
|
cron:
|
||||||
|
user: website
|
||||||
|
name: "backup"
|
||||||
|
job: "/usr/bin/pg_dump --clean media > backup.sql"
|
||||||
|
hour: '2'
|
||||||
|
minute: '0'
|
22
deploy/roles/website/templates/local_settings.py.j2
Normal file
22
deploy/roles/website/templates/local_settings.py.j2
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
DATABASES = {
|
||||||
|
"default": {
|
||||||
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
|
"NAME": "media",
|
||||||
|
"USER": "website",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC_ROOT = "/opt/website/static/"
|
||||||
|
MEDIA_ROOT = "/opt/website/media/"
|
||||||
|
|
||||||
|
DEBUG = False
|
||||||
|
|
||||||
|
SERVER_EMAIL = "julien@palard.fr"
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ["eqy.fr"]
|
||||||
|
|
||||||
|
SECRET_KEY = r'ephae4Xo Aeve8aic eeph7Eed Sho9oloo johY4ae5 ish0Eela areiy3Ia Joechoo6'
|
||||||
|
|
||||||
|
LOCALE_PATHS = ["/opt/website/locale"]
|
||||||
|
|
||||||
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTOCOL", "https")
|
34
deploy/roles/website/templates/nginx-vhost
Normal file
34
deploy/roles/website/templates/nginx-vhost
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
server {
|
||||||
|
listen [::]:80;
|
||||||
|
listen 80;
|
||||||
|
server_name {{ website_vhost }};
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 301 https://{{ website_vhost }}$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 http2 ssl;
|
||||||
|
listen [::]:443 http2 ssl;
|
||||||
|
server_name {{ website_vhost }};
|
||||||
|
|
||||||
|
client_max_body_size 666M;
|
||||||
|
|
||||||
|
include snippets/letsencrypt-{{ cert_name }}.conf;
|
||||||
|
|
||||||
|
location /static/ {
|
||||||
|
alias /opt/website/static/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /media/ {
|
||||||
|
alias /opt/website/media/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://unix:/opt/website/website.sock;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Protocol $scheme;
|
||||||
|
}
|
||||||
|
}
|
12
deploy/website.yml
Normal file
12
deploy/website.yml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- hosts: website
|
||||||
|
roles:
|
||||||
|
- common
|
||||||
|
- website
|
||||||
|
vars:
|
||||||
|
website_vhost: eqy.fr
|
||||||
|
admin_email: julien+photos@palard.fr
|
||||||
|
cert_name: eqy
|
||||||
|
domains:
|
||||||
|
- eqy.fr
|
|
@ -123,3 +123,8 @@ MEDIA_URL = 'media/'
|
||||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
try:
|
||||||
|
from local_settings import *
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
django
|
Loading…
Reference in New Issue
Block a user