Init push
This commit is contained in:
commit
0abcf3f1cc
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
*.key
|
||||
ansible/.vault_pass
|
||||
ansible/ansible.cfg
|
||||
ansible/vars/vault.yml
|
||||
playground
|
||||
terraform/.terraform
|
||||
terraform/*.tfvars
|
||||
terraform/terraform.tfstate*
|
8
.vscode/extensions.json
vendored
Normal file
8
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"oderwat.indent-rainbow",
|
||||
"redhat.vscode-yaml",
|
||||
"hashicorp.terraform",
|
||||
"samuelcolvin.jinjahtml"
|
||||
]
|
||||
}
|
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"**wireguard**.conf": "jinja-properties",
|
||||
"**docker-compose**.j2": "jinja-yaml",
|
||||
},
|
||||
"yaml.schemas": {
|
||||
"https://json.schemastore.org/ansible-role-2.9": ["**/tasks/**.yml"],
|
||||
"https://json.schemastore.org/ansible-playbook": ["run.yml"],
|
||||
"https://json.schemastore.org/github-workflow": [".github/worflows/**.yml"],
|
||||
},
|
||||
}
|
38
ansible/group_vars/all.yml
Executable file
38
ansible/group_vars/all.yml
Executable file
@ -0,0 +1,38 @@
|
||||
ansible_become_password: "{{ secret_sudo }}"
|
||||
|
||||
ntp_timezone: "Europe/Oslo"
|
||||
|
||||
users:
|
||||
- username: roxedus
|
||||
groupname: roxedus
|
||||
home: yes
|
||||
uid: "1000"
|
||||
gid: "1000"
|
||||
github: Roxedus
|
||||
password: "{{ secret_rox_pass }}"
|
||||
|
||||
package_list:
|
||||
- bash-completion
|
||||
- ca-certificates
|
||||
- curl
|
||||
- git
|
||||
- gnupg2
|
||||
- htop
|
||||
- jq
|
||||
- ncdu
|
||||
- net-tools
|
||||
- python3
|
||||
- python3-apt
|
||||
- python3-pip
|
||||
- software-properties-common
|
||||
- tmux
|
||||
- wget
|
||||
|
||||
security_ssh_password_authentication: "no"
|
||||
security_ssh_permit_root_login: "no"
|
||||
security_ssh_port: "{{ secret_ssh_port }}"
|
||||
security_ssh_usedns: "no"
|
||||
security_autoupdate_enabled: true
|
||||
security_fail2ban_enabled: true
|
||||
security_sudoers_passwordless:
|
||||
- "{{ users.0.username }}"
|
3
ansible/group_vars/docker.yml
Executable file
3
ansible/group_vars/docker.yml
Executable file
@ -0,0 +1,3 @@
|
||||
docker_install_compose: false
|
||||
docker_users:
|
||||
- "{{ users.0.username }}"
|
5
ansible/group_vars/simple_login.yml
Normal file
5
ansible/group_vars/simple_login.yml
Normal file
@ -0,0 +1,5 @@
|
||||
sl_domain: domain.com
|
||||
mail_domain: "mail.{{ sl_domain }}"
|
||||
|
||||
sl_alt_domains:
|
||||
- mail.other_domain.com
|
5
ansible/hosts
Executable file
5
ansible/hosts
Executable file
@ -0,0 +1,5 @@
|
||||
[docker]
|
||||
mail
|
||||
|
||||
[simple_login]
|
||||
mail set_hostname="{{ mail_domain }}"
|
5
ansible/requirements.txt
Normal file
5
ansible/requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
wheel
|
||||
ansible==4.1.0
|
||||
ansible-base==2.10.10
|
||||
jmespath
|
||||
ansible-lint[yamllint]
|
7
ansible/requirements.yml
Executable file
7
ansible/requirements.yml
Executable file
@ -0,0 +1,7 @@
|
||||
---
|
||||
roles:
|
||||
- name: geerlingguy.docker
|
||||
- name: geerlingguy.ntp
|
||||
- name: geerlingguy.pip
|
||||
- name: geerlingguy.postfix
|
||||
- name: geerlingguy.security
|
1
ansible/roles/authentik/defaults/main.yml
Normal file
1
ansible/roles/authentik/defaults/main.yml
Normal file
@ -0,0 +1 @@
|
||||
AUTHENTIK_TAG: 2022.4.1
|
24
ansible/roles/authentik/tasks/main.yml
Normal file
24
ansible/roles/authentik/tasks/main.yml
Normal file
@ -0,0 +1,24 @@
|
||||
- name: Create Authentik appdata directory
|
||||
ansible.builtin.file:
|
||||
path: "/opt/{{ item.name }}"
|
||||
state: directory
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: "{{ item.mode | default('0755')}}"
|
||||
loop:
|
||||
- name: appdata
|
||||
- name: appdata/authentik
|
||||
- name: appdata/authentik/postgresql
|
||||
mode: "0700"
|
||||
- name: appdata/authentik/backups
|
||||
- name: appdata/authentik/certs
|
||||
- name: appdata/authentik/media
|
||||
- name: appdata/authentik/templates
|
||||
|
||||
- name: Seed compose
|
||||
ansible.builtin.template:
|
||||
src: "docker-compose.yml.j2"
|
||||
dest: "/opt/appdata/authentik/docker-compose.yml"
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: 0644
|
80
ansible/roles/authentik/templates/docker-compose.yml.j2
Normal file
80
ansible/roles/authentik/templates/docker-compose.yml.j2
Normal file
@ -0,0 +1,80 @@
|
||||
version: '3.2'
|
||||
|
||||
services:
|
||||
postgresql:
|
||||
image: postgres:12-alpine
|
||||
container_name: auth_postgres
|
||||
user: "{{ users.0.uid }}:{{ users.0.gid }}"
|
||||
volumes:
|
||||
- /etc/passwd:/etc/passwd:ro
|
||||
- /opt/appdata/authentik/postgresql:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_PASSWORD={{ secret_authentik.postgres.password }}
|
||||
- POSTGRES_USER={{ secret_authentik.postgres.user }}
|
||||
- POSTGRES_DB={{ secret_authentik.postgres.database }}
|
||||
networks:
|
||||
- auth
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- auth
|
||||
|
||||
server:
|
||||
image: ghcr.io/goauthentik/server:{{ AUTHENTIK_TAG }}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
user: "{{ users.0.uid }}:{{ users.0.gid }}"
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: {{ secret_authentik.postgres.user }}
|
||||
AUTHENTIK_POSTGRESQL__NAME: {{ secret_authentik.postgres.database }}
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: {{ secret_authentik.postgres.password }}
|
||||
AUTHENTIK_SECRET_KEY: {{ secret_authentik.secret_key }}
|
||||
# AUTHENTIK_ERROR_REPORTING__ENABLED: "true"
|
||||
# WORKERS: 2
|
||||
volumes:
|
||||
- /opt/appdata/authentik/media:/media
|
||||
- /opt/appdata/authentik/custom-templates:/templates
|
||||
- /opt/appdata/swag/config/geoip2db:/geoip:ro
|
||||
networks:
|
||||
- default
|
||||
- auth
|
||||
labels:
|
||||
- swag=enable
|
||||
- "swag_url=sso.{{ sl_domain }}"
|
||||
- swag_port=9443
|
||||
- swag_proto=https
|
||||
|
||||
worker:
|
||||
image: ghcr.io/goauthentik/server:{{ AUTHENTIK_TAG }}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: {{ secret_authentik.postgres.user }}
|
||||
AUTHENTIK_POSTGRESQL__NAME: {{ secret_authentik.postgres.database }}
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: {{ secret_authentik.postgres.password }}
|
||||
AUTHENTIK_SECRET_KEY: {{ secret_authentik.secret_key }}
|
||||
# AUTHENTIK_ERROR_REPORTING__ENABLED: "true"
|
||||
user: "{{ users.0.uid }}:{{ users.0.gid }}"
|
||||
volumes:
|
||||
- /opt/appdata/authentik/backups:/backups
|
||||
- /opt/appdata/authentik/certs:/certs
|
||||
- /opt/appdata/authentik/media:/media
|
||||
- /opt/appdata/authentik/custom-templates:/templates
|
||||
- /opt/appdata/swag/config/geoip2db:/geoip:ro
|
||||
networks:
|
||||
- auth
|
||||
|
||||
networks:
|
||||
default:
|
||||
external: true
|
||||
name: proxynet
|
||||
|
||||
auth:
|
||||
internal: true
|
||||
name: auth
|
12
ansible/roles/simple-login/defaults/main.yml
Normal file
12
ansible/roles/simple-login/defaults/main.yml
Normal file
@ -0,0 +1,12 @@
|
||||
mail_domain: mail.domain.com
|
||||
|
||||
sl_prem_domains: other.domain.com
|
||||
|
||||
sl_version: v4.2.2
|
||||
|
||||
sl_postgres_version: 12
|
||||
|
||||
postgres:
|
||||
user: user
|
||||
password: password
|
||||
dbname: dbname
|
88
ansible/roles/simple-login/tasks/main.yml
Normal file
88
ansible/roles/simple-login/tasks/main.yml
Normal file
@ -0,0 +1,88 @@
|
||||
- name: Install packages for simple-login
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
pkg:
|
||||
- dnsutils
|
||||
- postfix
|
||||
- postfix-pgsql
|
||||
- postgresql-client-common
|
||||
- "postgresql-client-{{ sl_postgres_version }}"
|
||||
|
||||
- name: Create sl dockernet
|
||||
community.docker.docker_network:
|
||||
name: sl_net
|
||||
#enable_ipv6: True
|
||||
|
||||
- name: Get sl_net info
|
||||
community.docker.docker_network_info:
|
||||
name: sl_net
|
||||
register: sl_net
|
||||
|
||||
- include_tasks: postfix.yml
|
||||
|
||||
- name: Create and chown simple appdata directories
|
||||
ansible.builtin.file:
|
||||
path: "/opt/{{ item.name }}"
|
||||
state: directory
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: "{{ item.mode | default('0755')}}"
|
||||
loop:
|
||||
- name: appdata
|
||||
- name: appdata/simple
|
||||
- name: appdata/simple/keys
|
||||
- name: appdata/simple/postgresql
|
||||
mode: "0700"
|
||||
- name: appdata/simple/sl
|
||||
- name: appdata/simple/sl/pgp
|
||||
- name: appdata/simple/upload
|
||||
|
||||
- name: Create and chown postgres socket dir
|
||||
ansible.builtin.file:
|
||||
path: "/opt/run/postgresql"
|
||||
state: directory
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: 0775
|
||||
|
||||
- name: Place certs
|
||||
ansible.builtin.copy:
|
||||
content: "{{ item.content }}"
|
||||
dest: "/opt/appdata/simple/keys/{{ item.name }}"
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: 0644
|
||||
loop:
|
||||
- name: dkim.key
|
||||
content: "{{ secret_dkim }}"
|
||||
- name: dkim.pub.key
|
||||
content: "{{ secret_dkim_pub }}"
|
||||
|
||||
- name: Premium script
|
||||
ansible.builtin.template:
|
||||
src: premium.j2
|
||||
dest: "/opt/scripts/premium.sh"
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: 0744
|
||||
|
||||
- name: Seed env-file
|
||||
ansible.builtin.template:
|
||||
src: .env.j2
|
||||
dest: "/opt/appdata/simple/sl.env"
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: 0644
|
||||
|
||||
- name: Seed composes
|
||||
ansible.builtin.template:
|
||||
src: "docker-compose.{{ item }}.j2"
|
||||
dest: "/opt/appdata/simple/docker-compose.{{ item }}.yml"
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: 0644
|
||||
loop:
|
||||
- app
|
||||
- db
|
||||
- init
|
||||
- migration
|
43
ansible/roles/simple-login/tasks/postfix.yml
Normal file
43
ansible/roles/simple-login/tasks/postfix.yml
Normal file
@ -0,0 +1,43 @@
|
||||
- name: Set mailname
|
||||
ansible.builtin.copy:
|
||||
content: "{{ mail_domain }}"
|
||||
dest: /etc/mailname
|
||||
mode: 0755
|
||||
|
||||
- name: Create postfix directory
|
||||
ansible.builtin.file:
|
||||
path: "/etc/postfix"
|
||||
state: directory
|
||||
owner: root
|
||||
mode: 0644
|
||||
|
||||
- name: Place main.cf
|
||||
ansible.builtin.template:
|
||||
src: main.j2
|
||||
dest: "/etc/postfix/main.cf"
|
||||
owner: root
|
||||
mode: 0644
|
||||
register: postfix_conf
|
||||
|
||||
- name: Place pgsql-relay-domains.cf
|
||||
ansible.builtin.template:
|
||||
src: pgsql-relay-domains.j2
|
||||
dest: "/etc/postfix/pgsql-relay-domains.cf"
|
||||
owner: root
|
||||
mode: 0644
|
||||
register: postfix_conf
|
||||
|
||||
- name: Place pgsql-transport-maps.cf
|
||||
ansible.builtin.template:
|
||||
src: pgsql-transport-maps.j2
|
||||
dest: "/etc/postfix/pgsql-transport-maps.cf"
|
||||
owner: root
|
||||
mode: 0644
|
||||
register: postfix_conf
|
||||
|
||||
- name: Restart Postfix
|
||||
ansible.builtin.service:
|
||||
name: postfix
|
||||
state: restarted
|
||||
when: postfix_conf.changed
|
||||
become: true
|
158
ansible/roles/simple-login/templates/.env.j2
Normal file
158
ansible/roles/simple-login/templates/.env.j2
Normal file
@ -0,0 +1,158 @@
|
||||
# OTHER ENVS
|
||||
|
||||
TZ={{ ntp_timezone }}
|
||||
|
||||
# This file contains all available options in SimpleLogin.
|
||||
# Some are optional and are commented out by default.
|
||||
# Some are only relevant for our SaaS version, for example for payment integration, analytics, etc.
|
||||
|
||||
# Server url
|
||||
URL=https://app.{{ sl_domain }}
|
||||
|
||||
|
||||
# Only print email content, not sending it, for local development
|
||||
# NOT_SEND_EMAIL=true
|
||||
|
||||
# domain used to create alias
|
||||
EMAIL_DOMAIN={{ mail_domain }}
|
||||
|
||||
# Allow SimpleLogin to enforce SPF by using the extra headers from postfix
|
||||
# ENFORCE_SPF=true
|
||||
|
||||
# other domains that can be used to create aliases, in addition to EMAIL_DOMAIN
|
||||
OTHER_ALIAS_DOMAINS={{ sl_alt_domains | safe }}
|
||||
|
||||
# domains that can be used to create aliases. If set, override OTHER_ALIAS_DOMAINS
|
||||
# ALIAS_DOMAINS={{ sl_alt_domains | safe }}
|
||||
|
||||
# (optional) domains that are only available to premium accounts
|
||||
PREMIUM_ALIAS_DOMAINS={{ sl_prem_domains | safe }}
|
||||
|
||||
# the alias domain used when creating the first alias for user, default to EMAIL_DOMAIN if not set
|
||||
# FIRST_ALIAS_DOMAIN = another-domain.com
|
||||
|
||||
# transactional email is sent from this email address
|
||||
SUPPORT_EMAIL=support@{{ mail_domain }}
|
||||
SUPPORT_NAME=Rox
|
||||
|
||||
# to receive general stats.
|
||||
# ADMIN_EMAIL=admin@sl.local
|
||||
|
||||
# Max number emails user can generate for free plan
|
||||
# Set to 5 by default
|
||||
MAX_NB_EMAIL_FREE_PLAN=50
|
||||
|
||||
# Close registration. Avoid people accidentally creating new account on a self-hosted SimpleLogin
|
||||
# DISABLE_REGISTRATION=1
|
||||
|
||||
# custom domain needs to point to these MX servers
|
||||
EMAIL_SERVERS_WITH_PRIORITY=[(10, "{{ mail_domain }}.")]
|
||||
|
||||
# these emails are ignored when computing stats
|
||||
# IGNORED_EMAILS = ["my_email@domain.com"]
|
||||
|
||||
# By default, new aliases must end with ".{random_word}". This is to avoid a person taking all "nice" aliases.
|
||||
# this option doesn't make sense in self-hosted. Set this variable to disable this option.
|
||||
DISABLE_ALIAS_SUFFIX=1
|
||||
|
||||
# If you want to use another MTA to send email, you could set the address of your MTA here
|
||||
# By default, emails are sent using the the same Postfix server that receives emails
|
||||
POSTFIX_SERVER={{ sl_net.network.IPAM.Config[0].Gateway }}
|
||||
|
||||
# the DKIM private key used to compute DKIM-Signature
|
||||
DKIM_PRIVATE_KEY_PATH=/keys/dkim.key
|
||||
|
||||
# delete and recreate the sqlite database, for local development
|
||||
# RESET_DB=true
|
||||
|
||||
# DB Connection
|
||||
DB_URI=postgresql://{{ postgres.user }}:{{ postgres.password }}@sl_postgres:5432/{{ postgres.dbname }}
|
||||
|
||||
FLASK_SECRET={{ secret_flask }}
|
||||
|
||||
# AWS params
|
||||
# BUCKET=to_fill
|
||||
# AWS_ACCESS_KEY_ID=to_fill
|
||||
# AWS_SECRET_ACCESS_KEY=to_fill
|
||||
# AWS_REGION=to_fill
|
||||
|
||||
# OpenId key
|
||||
# OPENID_PRIVATE_KEY_PATH=local_data/jwtRS256.key
|
||||
# OPENID_PUBLIC_KEY_PATH=local_data/jwtRS256.key.pub
|
||||
|
||||
# Words to generate random email alias
|
||||
# WORDS_FILE_PATH=local_data/words.txt
|
||||
|
||||
# Login with Github
|
||||
# GITHUB_CLIENT_ID=to_fill
|
||||
# GITHUB_CLIENT_SECRET=to_fill
|
||||
|
||||
# Login with Google
|
||||
# GOOGLE_CLIENT_ID=to_fill
|
||||
# GOOGLE_CLIENT_SECRET=to_fill
|
||||
|
||||
# Flask profiler
|
||||
# FLASK_PROFILER_PATH=/tmp/flask-profiler.sql
|
||||
# FLASK_PROFILER_PASSWORD=password
|
||||
|
||||
# Where to store GPG Keyring
|
||||
GNUPGHOME=/sl/pgp
|
||||
|
||||
# By default, files are uploaded to s3
|
||||
# Set this variable to use the local "static/upload/" directory instead
|
||||
LOCAL_FILE_UPLOAD=true
|
||||
|
||||
# The landing page
|
||||
LANDING_PAGE_URL=https://app.{{ sl_domain }}
|
||||
|
||||
# The status page
|
||||
# STATUS_PAGE_URL=https://status.simplelogin.io
|
||||
|
||||
# Used when querying info on Apple API
|
||||
# APPLE_API_SECRET=secret
|
||||
# MACAPP_APPLE_API_SECRET=secret
|
||||
|
||||
# Disable onboarding emails
|
||||
# For self-hosted instance
|
||||
# DISABLE_ONBOARDING=true
|
||||
|
||||
# By default use postfix port 25. This param is used to override the Postfix port,
|
||||
# useful when using another SMTP server when developing locally
|
||||
# POSTFIX_PORT=1025
|
||||
|
||||
# set the 2 below variables to enable hCaptcha
|
||||
# HCAPTCHA_SECRET=very_long_string
|
||||
# HCAPTCHA_SITEKEY=00000000-0000-0000-0000-000000000000
|
||||
|
||||
# Set the 2 below variables to enable Plausible Analytics
|
||||
PLAUSIBLE_HOST=https://views.roxedus.net
|
||||
PLAUSIBLE_DOMAIN=app.domain.com
|
||||
|
||||
# Spamassassin server
|
||||
# SPAMASSASSIN_HOST = 127.0.0.1
|
||||
|
||||
# if set, used to sign the forwarding emails
|
||||
# PGP_SENDER_PRIVATE_KEY_PATH=local_data/private-pgp.asc
|
||||
|
||||
# Coinbase
|
||||
# COINBASE_WEBHOOK_SECRET=to_fill
|
||||
# COINBASE_CHECKOUT_ID=to_fill
|
||||
# COINBASE_API_KEY=to_fill
|
||||
# COINBASE_YEARLY_PRICE=30.00
|
||||
|
||||
# set the frequency limit on alias creation
|
||||
# ALIAS_LIMIT = "100/day;50/hour;5/minute"
|
||||
|
||||
# whether to enable spam scan using SpamAssassin
|
||||
# ENABLE_SPAM_ASSASSIN = 1
|
||||
|
||||
# Have I Been Pwned
|
||||
# HIBP_SCAN_INTERVAL_DAYS = 7
|
||||
HIBP_API_KEYS={{ HIBP_secret }}
|
||||
|
||||
# domains that can be present in the &next= section when using absolute urls
|
||||
ALLOWED_REDIRECT_DOMAINS=[]
|
||||
|
||||
# DNS nameservers to be used by the app
|
||||
# Multiple nameservers can be specified, separated by ','
|
||||
NAMESERVERS="1.1.1.1"
|
49
ansible/roles/simple-login/templates/docker-compose.app.j2
Normal file
49
ansible/roles/simple-login/templates/docker-compose.app.j2
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
version: "2.1"
|
||||
services:
|
||||
sl_web:
|
||||
image: "simplelogin/app-ci:{{ sl_version }}"
|
||||
container_name: sl_web
|
||||
user: "{{ users.0.uid }}:{{ users.0.gid }}"
|
||||
depends_on:
|
||||
- sl_postgres
|
||||
env_file:
|
||||
- sl.env
|
||||
volumes:
|
||||
- /opt/appdata/simple/keys:/keys:ro
|
||||
- /opt/appdata/simple/sl:/sl
|
||||
- /opt/appdata/simple/sl/upload:/code/static/upload
|
||||
labels:
|
||||
- swag=enable
|
||||
- "swag_url=app.{{ sl_domain }}"
|
||||
ports:
|
||||
- 10.50.0.1:7777:7777
|
||||
networks:
|
||||
- default
|
||||
- proxynet
|
||||
restart: unless-stopped
|
||||
|
||||
sl_email:
|
||||
image: "simplelogin/app-ci:{{ sl_version }}"
|
||||
container_name: sl_email
|
||||
user: "{{ users.0.uid }}:{{ users.0.gid }}"
|
||||
command: python email_handler.py
|
||||
depends_on:
|
||||
- sl_postgres
|
||||
env_file:
|
||||
- sl.env
|
||||
volumes:
|
||||
- /opt/appdata/simple/keys:/keys:ro
|
||||
- /opt/appdata/simple/sl:/sl
|
||||
- /opt/appdata/simple/sl/upload:/code/static/upload
|
||||
ports:
|
||||
- 127.0.0.1:20381:20381
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
default:
|
||||
external: true
|
||||
name: sl_net
|
||||
proxynet:
|
||||
external: true
|
||||
name: proxynet
|
24
ansible/roles/simple-login/templates/docker-compose.db.j2
Normal file
24
ansible/roles/simple-login/templates/docker-compose.db.j2
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
version: "2.1"
|
||||
services:
|
||||
sl_postgres:
|
||||
image: "postgres:{{ sl_postgres_version }}"
|
||||
container_name: sl_postgres
|
||||
user: "{{ users.0.uid }}:{{ users.0.gid }}"
|
||||
environment:
|
||||
- "POSTGRES_DB={{ postgres.dbname }}"
|
||||
- "POSTGRES_PASSWORD={{ postgres.password }}"
|
||||
- "POSTGRES_USER={{ postgres.user }}"
|
||||
- "TZ={{ ntp_timezone }}"
|
||||
volumes:
|
||||
- /etc/passwd:/etc/passwd:ro
|
||||
- /opt/appdata/simple/postgresql:/var/lib/postgresql/data
|
||||
- /opt/run/postgresql:/var/run/postgresql
|
||||
ports:
|
||||
- 127.0.0.1:5432:5432
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
default:
|
||||
external: true
|
||||
name: sl_net
|
19
ansible/roles/simple-login/templates/docker-compose.init.j2
Normal file
19
ansible/roles/simple-login/templates/docker-compose.init.j2
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
version: "2.1"
|
||||
services:
|
||||
sl_init:
|
||||
image: "simplelogin/app-ci:{{ sl_version }}"
|
||||
container_name: sl_init
|
||||
user: "{{ users.0.uid }}:{{ users.0.gid }}"
|
||||
command: python init_app.py
|
||||
env_file:
|
||||
- sl.env
|
||||
volumes:
|
||||
- /opt/appdata/simple/keys:/keys:ro
|
||||
- /opt/appdata/simple/sl:/sl
|
||||
- /opt/appdata/simple/sl/upload:/code/static/upload
|
||||
|
||||
networks:
|
||||
default:
|
||||
external: true
|
||||
name: sl_net
|
@ -0,0 +1,20 @@
|
||||
---
|
||||
version: "2.1"
|
||||
services:
|
||||
sl_migration:
|
||||
image: "simplelogin/app-ci:{{ sl_version }}"
|
||||
container_name: sl_migration
|
||||
user: "{{ users.0.uid }}:{{ users.0.gid }}"
|
||||
command: alembic upgrade head
|
||||
env_file:
|
||||
- sl.env
|
||||
volumes:
|
||||
- /opt/appdata/simple/keys:/keys:ro
|
||||
- /opt/appdata/simple/sl:/sl
|
||||
- /opt/appdata/simple/sl/upload:/code/static/upload
|
||||
- /opt/appdata/simple/sl.env:/code/.env
|
||||
|
||||
networks:
|
||||
default:
|
||||
external: true
|
||||
name: sl_net
|
65
ansible/roles/simple-login/templates/main.j2
Normal file
65
ansible/roles/simple-login/templates/main.j2
Normal file
@ -0,0 +1,65 @@
|
||||
# POSTFIX config file, adapted for SimpleLogin
|
||||
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
|
||||
biff = no
|
||||
|
||||
# appending .domain is the MUA's job.
|
||||
append_dot_mydomain = no
|
||||
|
||||
# Uncomment the next line to generate "delayed mail" warnings
|
||||
#delay_warning_time = 4h
|
||||
|
||||
readme_directory = no
|
||||
|
||||
# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on
|
||||
# fresh installs.
|
||||
compatibility_level = 2
|
||||
|
||||
# TLS parameters
|
||||
smtpd_tls_cert_file=/opt/appdata/swag/config/etc/letsencrypt/live/{{ sl_domain }}/fullchain.pem
|
||||
smtpd_tls_key_file=/opt/appdata/swag/config/etc/letsencrypt/live/{{ sl_domain }}/privkey.pem
|
||||
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
|
||||
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
|
||||
smtp_tls_security_level = may
|
||||
smtpd_tls_security_level = may
|
||||
|
||||
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
|
||||
# information on enabling SSL in the smtp client.
|
||||
|
||||
alias_maps = hash:/etc/aliases
|
||||
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 {{ sl_net.network.IPAM.Config[0].Subnet }}
|
||||
|
||||
# Set your domain here
|
||||
mydestination =
|
||||
myhostname = app.{{ sl_domain }}
|
||||
mydomain = {{ mail_domain }}
|
||||
myorigin = {{ mail_domain }}
|
||||
|
||||
relay_domains = pgsql:/etc/postfix/pgsql-relay-domains.cf
|
||||
transport_maps = pgsql:/etc/postfix/pgsql-transport-maps.cf
|
||||
|
||||
# HELO restrictions
|
||||
smtpd_delay_reject = yes
|
||||
smtpd_helo_required = yes
|
||||
smtpd_helo_restrictions =
|
||||
permit_mynetworks,
|
||||
reject_non_fqdn_helo_hostname,
|
||||
reject_invalid_helo_hostname,
|
||||
permit
|
||||
|
||||
# Sender restrictions:
|
||||
smtpd_sender_restrictions =
|
||||
permit_mynetworks,
|
||||
reject_non_fqdn_sender,
|
||||
reject_unknown_sender_domain,
|
||||
permit
|
||||
|
||||
# Recipient restrictions:
|
||||
smtpd_recipient_restrictions =
|
||||
reject_unauth_pipelining,
|
||||
reject_non_fqdn_recipient,
|
||||
reject_unknown_recipient_domain,
|
||||
permit_mynetworks,
|
||||
reject_unauth_destination,
|
||||
reject_rbl_client zen.spamhaus.org,
|
||||
reject_rbl_client bl.spamcop.net,
|
||||
permit
|
@ -0,0 +1,8 @@
|
||||
# postgres config
|
||||
hosts = 127.0.0.1:5432
|
||||
user = {{ postgres.user }}
|
||||
password = {{ postgres.password }}
|
||||
dbname = {{ postgres.dbname }}
|
||||
|
||||
query = SELECT domain FROM custom_domain WHERE domain='%s' AND verified=true
|
||||
UNION SELECT '%s' WHERE '%s' IN ('{{ mail_domain }}', '{{ (sl_prem_domains + sl_alt_domains)|map('lower')|join("', '") }}') LIMIT 1;
|
@ -0,0 +1,9 @@
|
||||
# postgres config
|
||||
hosts = 127.0.0.1:5432
|
||||
user = {{ postgres.user }}
|
||||
password = {{ postgres.password }}
|
||||
dbname = {{ postgres.dbname }}
|
||||
|
||||
# forward to smtp:127.0.0.1:20381 for custom domain AND email domain
|
||||
query = SELECT 'smtp:127.0.0.1:20381' FROM custom_domain WHERE domain = '%s' AND verified=true
|
||||
UNION SELECT 'smtp:127.0.0.1:20381' WHERE '%s' IN ('{{ mail_domain }}', '{{ (sl_prem_domains + sl_alt_domains)|map('lower')|join("', '") }}') LIMIT 1;
|
3
ansible/roles/simple-login/templates/premium.j2
Normal file
3
ansible/roles/simple-login/templates/premium.j2
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
psql -d {{ postgres.dbname }} -h /opt/run/postgresql -c "UPDATE users SET lifetime = '1' WHERE email = '$1';"
|
33
ansible/roles/swag/tasks/main.yml
Normal file
33
ansible/roles/swag/tasks/main.yml
Normal file
@ -0,0 +1,33 @@
|
||||
- name: Create SWAG appdata directory
|
||||
ansible.builtin.file:
|
||||
path: "/opt/{{ item.name }}"
|
||||
state: directory
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: "{{ item.mode | default('0755')}}"
|
||||
loop:
|
||||
- name: appdata
|
||||
- name: appdata/swag
|
||||
- name: appdata/swag/config
|
||||
- name: appdata/swag/config/dns-conf
|
||||
|
||||
- name: Create proxynet
|
||||
community.docker.docker_network:
|
||||
name: proxynet
|
||||
|
||||
- name: Seed compose
|
||||
ansible.builtin.template:
|
||||
src: "docker-compose.yml"
|
||||
dest: "/opt/appdata/swag/docker-compose.yml"
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: 0644
|
||||
|
||||
- name: Install swag dns file
|
||||
template:
|
||||
src: "cloudflare.ini"
|
||||
dest: "/opt/appdata/swag/config/dns-conf/cloudflare.ini"
|
||||
mode: "600" # To prevent unnessecary nag in logs
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
become: true
|
3
ansible/roles/swag/templates/cloudflare.ini
Normal file
3
ansible/roles/swag/templates/cloudflare.ini
Normal file
@ -0,0 +1,3 @@
|
||||
{{ ansible_managed | comment }}
|
||||
|
||||
dns_cloudflare_api_token = {{ secret_cloudflare[sl_domain].apikey }}
|
55
ansible/roles/swag/templates/docker-compose.yml
Normal file
55
ansible/roles/swag/templates/docker-compose.yml
Normal file
@ -0,0 +1,55 @@
|
||||
---
|
||||
version: "2.1"
|
||||
services:
|
||||
swag:
|
||||
image: lscr.io/linuxserver/swag
|
||||
container_name: swag
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
environment:
|
||||
- PUID={{ users.0.uid }}
|
||||
- PGID={{ users.0.gid }}
|
||||
- TZ={{ ntp_timezone }}
|
||||
- URL={{ sl_domain }}
|
||||
- SUBDOMAINS=wildcard
|
||||
- EXTRA_DOMAINS=*.{{ mail_domain }}
|
||||
- VALIDATION=dns
|
||||
- DNSPLUGIN=cloudflare
|
||||
- EMAIL={{ secret_cloudflare.email }}
|
||||
- STAGING=false
|
||||
- DOCKER_MODS=linuxserver/mods:universal-docker|linuxserver/mods:swag-auto-proxy|swag-maxmind
|
||||
- DOCKER_HOST=dockerproxy:2375
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /opt/appdata/swag/config
|
||||
target: /config
|
||||
- type: tmpfs
|
||||
target: /config/nginx/proxy-confs
|
||||
networks:
|
||||
- default
|
||||
- docker
|
||||
ports:
|
||||
- 443:443
|
||||
- 80:80
|
||||
restart: unless-stopped
|
||||
|
||||
dockerproxy:
|
||||
image: ghcr.io/tecnativa/docker-socket-proxy:latest
|
||||
container_name: dockerproxy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- docker
|
||||
environment:
|
||||
- CONTAINERS=1
|
||||
- POST=0
|
||||
|
||||
networks:
|
||||
default:
|
||||
external: true
|
||||
name: proxynet
|
||||
|
||||
docker:
|
||||
internal: true
|
||||
name: docker
|
44
ansible/roles/ufw/tasks/main.yml
Normal file
44
ansible/roles/ufw/tasks/main.yml
Normal file
@ -0,0 +1,44 @@
|
||||
- name: Install ufw
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
pkg:
|
||||
- ufw
|
||||
|
||||
- name: Allow everything and enable UFW
|
||||
community.general.ufw:
|
||||
state: enabled
|
||||
policy: deny
|
||||
|
||||
- name: Allow ports
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: "{{ item | int }}"
|
||||
loop:
|
||||
- "{{ secret_ssh_port }}"
|
||||
- "{{ wireguard.port }}"
|
||||
- 110
|
||||
- 143
|
||||
- 22
|
||||
- 25
|
||||
- 443
|
||||
- 465
|
||||
- 587
|
||||
- 80
|
||||
- 993
|
||||
- 995
|
||||
|
||||
- name: Endlessh
|
||||
community.docker.docker_container:
|
||||
name: endlessh
|
||||
pull: yes
|
||||
restart_policy: unless-stopped
|
||||
recreate: yes
|
||||
env:
|
||||
PUID: "{{ users.0.uid }}"
|
||||
PGID: "{{ users.0.gid }}"
|
||||
TZ: "{{ ntp_timezone }}"
|
||||
image: lscr.io/linuxserver/endlessh
|
||||
ports:
|
||||
- "22:2222"
|
||||
tmpfs:
|
||||
- /config
|
56
ansible/roles/wireguard/tasks/main.yml
Normal file
56
ansible/roles/wireguard/tasks/main.yml
Normal file
@ -0,0 +1,56 @@
|
||||
- name: Install packages for wireguard
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
pkg:
|
||||
- qrencode
|
||||
- wireguard
|
||||
- wireguard-tools
|
||||
|
||||
- name: Wireguard server config
|
||||
ansible.builtin.template:
|
||||
src: wireguard-server.conf
|
||||
dest: /etc/wireguard/wg0.conf
|
||||
mode: "0600"
|
||||
backup: yes
|
||||
become: true
|
||||
register: wireguard_conf
|
||||
|
||||
- name: Enable wireguard
|
||||
ansible.builtin.service:
|
||||
name: wg-quick@wg0
|
||||
enabled: true
|
||||
become: true
|
||||
|
||||
- name: Restart wireguard
|
||||
ansible.builtin.service:
|
||||
name: wg-quick@wg0
|
||||
state: restarted
|
||||
when: wireguard_conf.changed
|
||||
become: true
|
||||
|
||||
- name: Create wireguard client directory
|
||||
ansible.builtin.file:
|
||||
path: "/home/{{ users.0.username }}/wireguard-clients"
|
||||
state: directory
|
||||
owner: "{{ users.0.username }}"
|
||||
mode: 0700
|
||||
|
||||
- name: Wireguard client configuration
|
||||
ansible.builtin.template:
|
||||
src: wireguard-client.conf
|
||||
dest: "/home/{{ users.0.username }}/wireguard-clients/{{ item.key }}.conf"
|
||||
owner: "{{ users.0.username }}"
|
||||
mode: 0600
|
||||
loop: "{{ wireguard.clients|dict2items }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
|
||||
- name: Enable p2p communication
|
||||
ansible.builtin.sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
value: "1"
|
||||
sysctl_set: yes
|
||||
state: present
|
||||
reload: yes
|
||||
sysctl_file: /etc/sysctl.d/99-sysctl.conf
|
||||
become: true
|
10
ansible/roles/wireguard/templates/wireguard-client.conf
Normal file
10
ansible/roles/wireguard/templates/wireguard-client.conf
Normal file
@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
Address = {{ item.value.ip }}
|
||||
PrivateKey = {{ item.value.private_key }}
|
||||
|
||||
[Peer]
|
||||
PublicKey = {{ wireguard.server.public_key }}
|
||||
Endpoint = {{ wireguard.public_ip }}:{{ wireguard.port }}
|
||||
AllowedIPs = {{ wireguard.cidr }}
|
||||
|
||||
PersistentKeepalive = 25
|
11
ansible/roles/wireguard/templates/wireguard-server.conf
Normal file
11
ansible/roles/wireguard/templates/wireguard-server.conf
Normal file
@ -0,0 +1,11 @@
|
||||
[Interface]
|
||||
Address = {{ wireguard.server.ip }}
|
||||
PrivateKey = {{ wireguard.server.private_key }}
|
||||
ListenPort = {{ wireguard.port }}
|
||||
|
||||
{% for name, config in wireguard.clients.items() %}
|
||||
[Peer]
|
||||
# {{ name }}
|
||||
PublicKey = {{ config.public_key }}
|
||||
AllowedIPs = {{ config.ip }}/32
|
||||
{% endfor %}
|
230
ansible/run.yml
Executable file
230
ansible/run.yml
Executable file
@ -0,0 +1,230 @@
|
||||
- hosts: all
|
||||
become: yes
|
||||
tags: [never, init]
|
||||
vars_files:
|
||||
- "vars/vault.yml"
|
||||
|
||||
collections:
|
||||
- ansible.builtin.hostname
|
||||
- ansible.builtin.group
|
||||
- ansible.builtin.user
|
||||
- ansible.posix.authorized_key
|
||||
- ansible.builtin.lineinfile
|
||||
- ansible.builtin.file
|
||||
- ansible.builtin.copy
|
||||
- ansible.builtin.reboot
|
||||
|
||||
pre_tasks:
|
||||
- include_tasks: tasks/user.yml
|
||||
with_items: "{{ users }}"
|
||||
loop_control:
|
||||
loop_var: user
|
||||
|
||||
- name: Change hostname
|
||||
when: "set_hostname is defined"
|
||||
register: new_hostname
|
||||
ansible.builtin.hostname:
|
||||
name: "{{ set_hostname }}"
|
||||
|
||||
- name: Change hostname in hosts
|
||||
when: new_hostname.changed
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/hosts
|
||||
regexp: '^127\.0\.0\.1 localhost'
|
||||
line: "127.0.0.1 localhost {{ set_hostname }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Create scripts directory
|
||||
ansible.builtin.file:
|
||||
path: "/opt/scripts"
|
||||
state: directory
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: "0775"
|
||||
register: script_dir
|
||||
|
||||
- name: Add bin dir to system-wide $PATH.
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/profile.d/custom-path.sh
|
||||
content: "PATH=$PATH:/opt/scripts"
|
||||
mode: "0644"
|
||||
when: script_dir.changed
|
||||
|
||||
- name: Reboot the server
|
||||
ansible.builtin.reboot:
|
||||
msg: "Reboot initiated by Ansible due to hostname change"
|
||||
connect_timeout: 5
|
||||
reboot_timeout: 300
|
||||
pre_reboot_delay: 2
|
||||
post_reboot_delay: 30
|
||||
test_command: uptime
|
||||
when: new_hostname.changed
|
||||
|
||||
- name: Update packages
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
cache_valid_time: 1
|
||||
|
||||
roles:
|
||||
- role: geerlingguy.ntp
|
||||
- role: geerlingguy.security
|
||||
|
||||
tasks:
|
||||
- name: Change ssh port
|
||||
set_fact:
|
||||
ansible_port: "{{ secret_ssh_port }}"
|
||||
|
||||
- hosts: all
|
||||
become: yes
|
||||
tags: [always]
|
||||
vars_files:
|
||||
- "vars/vault.yml"
|
||||
|
||||
collections:
|
||||
- ansible.builtin.apt
|
||||
|
||||
tasks:
|
||||
- name: Install packages
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
pkg: "{{ package_list }}"
|
||||
|
||||
- hosts: docker
|
||||
become: yes
|
||||
tags: [docker]
|
||||
vars_files:
|
||||
- "vars/vault.yml"
|
||||
|
||||
collections:
|
||||
- ansible.builtin.pip
|
||||
- ansible.builtin.copy
|
||||
- ansible.builtin.service
|
||||
- ansible.builtin.file
|
||||
- ansible.builtin.get_url
|
||||
|
||||
post_tasks:
|
||||
- name: Install pip packages
|
||||
tags: [never, init]
|
||||
ansible.builtin.pip:
|
||||
name:
|
||||
- docker
|
||||
- github3.py
|
||||
|
||||
- name: Set Default logging
|
||||
tags: [never, init, logging]
|
||||
register: docker_deamon
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/docker/daemon.json
|
||||
owner: "root"
|
||||
group: "root"
|
||||
content: |
|
||||
{
|
||||
"log-driver": "journald",
|
||||
"log-opts": {
|
||||
"mode": "non-blocking"
|
||||
}
|
||||
}
|
||||
mode: "0600"
|
||||
|
||||
- name: Restart service to apply changes
|
||||
tags: [never, init, logging]
|
||||
when: docker_deamon.changed
|
||||
ansible.builtin.service:
|
||||
name: docker
|
||||
state: restarted
|
||||
|
||||
- name: Create plugin directory if not present
|
||||
ansible.builtin.file:
|
||||
path: "/home/{{ users.0.username }}/.docker/cli-plugins/"
|
||||
state: directory
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
mode: "0775"
|
||||
|
||||
- name: Get latest release of a public repository
|
||||
community.general.github_release:
|
||||
user: docker
|
||||
repo: compose
|
||||
action: latest_release
|
||||
register: comp_cli
|
||||
|
||||
- name: Install compose plugin
|
||||
ansible.builtin.get_url:
|
||||
url: "https://github.com/docker/compose/releases/download/{{comp_cli.tag}}/docker-compose-linux-x86_64"
|
||||
dest: "/home/{{ users.0.username }}/.docker/cli-plugins/docker-compose"
|
||||
mode: "0755"
|
||||
owner: "{{ users.0.username }}"
|
||||
group: "{{ users.0.groupname }}"
|
||||
|
||||
roles:
|
||||
- role: geerlingguy.docker
|
||||
tags: [never, init]
|
||||
|
||||
- hosts: simple_login
|
||||
become: yes
|
||||
tags: [init, mail]
|
||||
vars_files:
|
||||
- "vars/vault.yml"
|
||||
|
||||
roles:
|
||||
- role: wireguard
|
||||
tags: [wireguard]
|
||||
- role: simple-login
|
||||
tags: [mail]
|
||||
- role: swag
|
||||
tags: [edge]
|
||||
- role: authentik
|
||||
tags: [edge]
|
||||
- role: ufw
|
||||
tags: [edge]
|
||||
|
||||
- hosts: all
|
||||
become: yes
|
||||
tags: [update, init]
|
||||
vars_files:
|
||||
- "vars/vault.yml"
|
||||
|
||||
collections:
|
||||
- ansible.builtin.apt
|
||||
- ansible.builtin.file
|
||||
- ansible.builtin.reboot
|
||||
|
||||
tasks:
|
||||
# https://www.cyberciti.biz/faq/ansible-apt-update-all-packages-on-ubuntu-debian-linux/
|
||||
- name: Update packages
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
force_apt_get: true
|
||||
cache_valid_time: 3600
|
||||
upgrade: true
|
||||
|
||||
- name: Remove ubuntu motd spam
|
||||
ansible.builtin.file:
|
||||
path: "/etc/update-motd.d/{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- 10-help-text
|
||||
- 50-landscape-sysinfo
|
||||
- 50-motd-news
|
||||
- 80-livepatch
|
||||
- 90-updates-available
|
||||
- 95-hwe-eol
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
- name: Check if a reboot is needed for Debian and Ubuntu boxes
|
||||
register: reboot_required_file
|
||||
stat:
|
||||
path: /var/run/reboot-required
|
||||
get_md5: no
|
||||
|
||||
- name: Reboot the server
|
||||
ansible.builtin.reboot:
|
||||
msg: "Reboot initiated by Ansible due to kernel updates"
|
||||
connect_timeout: 5
|
||||
reboot_timeout: 300
|
||||
pre_reboot_delay: 0
|
||||
post_reboot_delay: 30
|
||||
test_command: uptime
|
||||
when: reboot_required_file.stat.exists
|
20
ansible/tasks/user.yml
Normal file
20
ansible/tasks/user.yml
Normal file
@ -0,0 +1,20 @@
|
||||
- name: Ensure groups exists
|
||||
ansible.builtin.group:
|
||||
name: "{{ user.groupname }}"
|
||||
gid: "{{ user.gid | default(None) }}"
|
||||
state: present
|
||||
|
||||
- name: Add users
|
||||
ansible.builtin.user:
|
||||
name: "{{ user.username }}"
|
||||
uid: "{{ user.uid | default(None) }}"
|
||||
group: "{{ user.groupname | default(user.username) }}"
|
||||
shell: "{{ user.shell | default('/bin/bash') }}"
|
||||
move_home: "{{ user.home | default(None) }}"
|
||||
password: "{{ user.password | default(None) }}"
|
||||
|
||||
- name: Add a Github key ssh key
|
||||
when: "user.github is defined"
|
||||
ansible.posix.authorized_key:
|
||||
user: "{{ user.username }}"
|
||||
key: "https://github.com/{{ user.github }}.keys"
|
50
ansible/vars/example.yml
Normal file
50
ansible/vars/example.yml
Normal file
@ -0,0 +1,50 @@
|
||||
---
|
||||
secret_rox_pass: #Hash
|
||||
secret_ssh_port:
|
||||
secret_sudo:
|
||||
|
||||
secret_flask: #Used in SL
|
||||
|
||||
HIBP_secret: #Used in SL
|
||||
|
||||
sl_prem_domains:
|
||||
- mail.domain.com
|
||||
|
||||
postgres:
|
||||
user:
|
||||
password:
|
||||
dbname:
|
||||
|
||||
secret_dkim: |
|
||||
RSA Key
|
||||
|
||||
secret_dkim_pub: |
|
||||
Pub Key
|
||||
|
||||
wireguard:
|
||||
public_ip:
|
||||
port:
|
||||
cidr: 10.50.0.0/24
|
||||
server:
|
||||
ip: 10.50.0.1
|
||||
public_key:
|
||||
private_key:
|
||||
|
||||
clients:
|
||||
phone:
|
||||
ip: 10.50.0.10
|
||||
public_key:
|
||||
private_key:
|
||||
|
||||
secret_cloudflare:
|
||||
email:
|
||||
domain.com:
|
||||
apikey:
|
||||
zones:
|
||||
|
||||
secret_authentik:
|
||||
postgres:
|
||||
password:
|
||||
database:
|
||||
user:
|
||||
secret_key:
|
44
terraform/.terraform.lock.hcl
Normal file
44
terraform/.terraform.lock.hcl
Normal file
@ -0,0 +1,44 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/cloudflare/cloudflare" {
|
||||
version = "2.21.0"
|
||||
constraints = "2.21.0"
|
||||
hashes = [
|
||||
"h1:eSPGBjaFZ6xgfRLcicjFDq1Ic7H9ErtLD0hViJS0SDI=",
|
||||
"zh:10462d1f27dfeda3fadae75d05bb1b41791a3b69b70c8846745673649113a633",
|
||||
"zh:1f5520b083996c6ebae0cfacb313afe0d4694861c58677957a4f39242ca22497",
|
||||
"zh:39e3fc58f4ff8d1e2dd6a413f24bb9c49d6a619861218303727a7f2df4707b0c",
|
||||
"zh:68f2f1d34e2819d580d6f3534369e3d14ce2cba4707b216ff3ad0b908733bd84",
|
||||
"zh:6b175ba58094d8dfbcfbeee72dbef321146733e4e13029e0e41eb0f585ad4c88",
|
||||
"zh:71c2652f19e09fa6a2826f0d690e7d7bdbf96e3dbd7d53564f302b0b866c6fc4",
|
||||
"zh:7e903c7f55afcb9d17a76204392862670ff7131a248cd812bcf77be36e4403f9",
|
||||
"zh:816671387134fe1c6c14e803a62ee14e316bbf812b5973b2e83434434cebff0d",
|
||||
"zh:bb09e052c6f6d46484fa696ff2441834779f81e0c5e7631c722dc3123ab4fd57",
|
||||
"zh:c6e538a48cc213e3d29d3203697e52dd9c19ed7abe04f640cc696c3ec175f3bc",
|
||||
"zh:d01dce22be0bb7b63e201ac9186adc6a36781ef80c4446b0af7014f67dbba095",
|
||||
"zh:f733ffa3b4a63866daaa1e93687c92726ddb790d714edd2ea9bfc8b541ecb1d4",
|
||||
"zh:ff862bb0e1102ef6f44ac60737c8be3302f2540a0652c2899805b031e3220145",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/linode/linode" {
|
||||
version = "1.18.0"
|
||||
constraints = "1.18.0"
|
||||
hashes = [
|
||||
"h1:+8f4i5sj2WOd5bdWSPUafHdN+s1Fgq9/l1+Rc3TMf7U=",
|
||||
"zh:0ead391cba4eccff9d46c91e9260ce5e2ccfd69e2aebef253768ce29e2de3a7d",
|
||||
"zh:27708a55d1ba1594086c2015441243a38a608f68ea2f82f1d759c6baf2a0df14",
|
||||
"zh:3d355a270e7eaeafd5044a326c527c23742b312376368e1019e3caa779cdbc91",
|
||||
"zh:41dde82124e6c2e2640ef2963fe4f6faf16f8e8b82e7dbaebfdec7b781f5455a",
|
||||
"zh:51e9139cdc1386053c6834585139dc74d6fb7653a00b495377bc445b5e532218",
|
||||
"zh:6ba6560bf23736a2a6e4c0899afd2c25cac6697d90cf2573449fe9b655f87920",
|
||||
"zh:79c1fa8e3a8705eee73f171229ff47688deaff8468cdf28fddaafe5aef7e2d8d",
|
||||
"zh:80b008ded1c71313c4f76e5569142e3a56b866f7693e57270d15f13fc7af1e14",
|
||||
"zh:b0ebb1e83e8d999dc1d8feecf9c1e293cd61fe72271610284fdcce46d4a8a7ed",
|
||||
"zh:bdaa786f0381ccd61404ea1835733e852e9747f1daf9a63bd4149073dbce85b6",
|
||||
"zh:c67cd9e8d4880dfa6cbbd25aa7fcd9c07a76f4801180ac3988ff3f84ede6181f",
|
||||
"zh:c8ee62dfd07d83dd362b8ba5f13a957e1ec8107b22ac168da4fa8470c4537a33",
|
||||
"zh:cf7bdc5eac5df6cfc6ab5c7cafaba72b6bf5a155017e25edc6d9dc192bb6d2ed",
|
||||
]
|
||||
}
|
207
terraform/mail.tf
Normal file
207
terraform/mail.tf
Normal file
@ -0,0 +1,207 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
linode = {
|
||||
source = "linode/linode"
|
||||
version = "1.18.0"
|
||||
}
|
||||
cloudflare = {
|
||||
source = "cloudflare/cloudflare"
|
||||
version = "2.21.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "linode" {
|
||||
token = var.linode_token
|
||||
}
|
||||
|
||||
provider "cloudflare" {
|
||||
email = var.cloudflare_email
|
||||
api_token = var.cloudflare_api_token
|
||||
}
|
||||
|
||||
resource "linode_instance" "mail" {
|
||||
image = "linode/ubuntu20.04"
|
||||
label = "mail"
|
||||
group = "Terraform"
|
||||
region = "eu-central"
|
||||
type = "g6-standard-1"
|
||||
authorized_keys = var.authorized_keys
|
||||
root_pass = var.root_pass
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_mail4" {
|
||||
zone_id = var.cloudflare_zone_id
|
||||
name = "mail"
|
||||
value = linode_instance.mail.ip_address
|
||||
type = "A"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_mail4_app" {
|
||||
zone_id = var.cloudflare_zone_id
|
||||
name = "app"
|
||||
value = linode_instance.mail.ip_address
|
||||
type = "A"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_mail6_app" {
|
||||
zone_id = var.cloudflare_zone_id
|
||||
name = "app"
|
||||
value = trimsuffix(linode_instance.mail.ipv6, "/128")
|
||||
type = "AAAA"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_mail4_wild" {
|
||||
zone_id = var.cloudflare_zone_id
|
||||
name = "*.mail"
|
||||
value = linode_instance.mail.ip_address
|
||||
type = "A"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_mail6" {
|
||||
zone_id = var.cloudflare_zone_id
|
||||
name = "mail"
|
||||
value = trimsuffix(linode_instance.mail.ipv6, "/128")
|
||||
type = "AAAA"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_mail6_wild" {
|
||||
zone_id = var.cloudflare_zone_id
|
||||
name = "*.mail"
|
||||
value = trimsuffix(linode_instance.mail.ipv6, "/128")
|
||||
type = "AAAA"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_mx" {
|
||||
zone_id = var.cloudflare_zone_id
|
||||
name = "@"
|
||||
value = "mail.${var.domain}"
|
||||
type = "MX"
|
||||
priority = "1"
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_mx_wild" {
|
||||
zone_id = var.cloudflare_zone_id
|
||||
name = "*"
|
||||
value = "mail.${var.domain}"
|
||||
type = "MX"
|
||||
priority = "1"
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "spf" {
|
||||
zone_id = var.cloudflare_zone_id
|
||||
name = "@"
|
||||
value = "v=spf1 mx -all"
|
||||
type = "TXT"
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dmarc" {
|
||||
zone_id = var.cloudflare_zone_id
|
||||
name = "_dmarc.${var.domain}"
|
||||
value = "v=DMARC1; p=quarantine; adkim=r; aspf=r"
|
||||
type = "TXT"
|
||||
}
|
||||
###
|
||||
|
||||
resource "cloudflare_record" "dns_alt4" {
|
||||
zone_id = var.cloudflare_alt_zone_id
|
||||
name = "mail"
|
||||
value = linode_instance.mail.ip_address
|
||||
type = "A"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_alt4_app" {
|
||||
zone_id = var.cloudflare_alt_zone_id
|
||||
name = "app"
|
||||
value = linode_instance.mail.ip_address
|
||||
type = "A"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_alt4_wild" {
|
||||
zone_id = var.cloudflare_alt_zone_id
|
||||
name = "*.mail"
|
||||
value = linode_instance.mail.ip_address
|
||||
type = "A"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_alt6" {
|
||||
zone_id = var.cloudflare_alt_zone_id
|
||||
name = "mail"
|
||||
value = trimsuffix(linode_instance.mail.ipv6, "/128")
|
||||
type = "AAAA"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_alt6_wild" {
|
||||
zone_id = var.cloudflare_alt_zone_id
|
||||
name = "*.mail"
|
||||
value = trimsuffix(linode_instance.mail.ipv6, "/128")
|
||||
type = "AAAA"
|
||||
ttl = 3600
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_alt_mx" {
|
||||
zone_id = var.cloudflare_alt_zone_id
|
||||
name = "@"
|
||||
value = "mail.${var.alt_domain}"
|
||||
type = "MX"
|
||||
priority = "1"
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dns_alt_mx_wild" {
|
||||
zone_id = var.cloudflare_alt_zone_id
|
||||
name = "*"
|
||||
value = "mail.${var.alt_domain}"
|
||||
type = "MX"
|
||||
priority = "1"
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "spf_alt" {
|
||||
zone_id = var.cloudflare_alt_zone_id
|
||||
name = "@"
|
||||
value = "v=spf1 include:mail.domain.com -all"
|
||||
type = "TXT"
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "dmarc_alt" {
|
||||
zone_id = var.cloudflare_alt_zone_id
|
||||
name = "_dmarc.${var.alt_domain}"
|
||||
value = "v=DMARC1; p=quarantine; adkim=r; aspf=r"
|
||||
type = "TXT"
|
||||
}
|
||||
|
||||
###
|
||||
resource "linode_rdns" "rdns4" {
|
||||
address = linode_instance.mail.ip_address
|
||||
rdns = "mail.${var.domain}"
|
||||
}
|
||||
|
||||
resource "linode_rdns" "rdns6" {
|
||||
address = trimsuffix(linode_instance.mail.ipv6, "/128")
|
||||
rdns = "mail.${var.domain}"
|
||||
}
|
||||
|
||||
variable "linode_token" {}
|
||||
variable "cloudflare_email" {}
|
||||
variable "cloudflare_api_token" {}
|
||||
variable "authorized_keys" {}
|
||||
variable "root_pass" {}
|
||||
variable "cloudflare_zone_id" {}
|
||||
variable "cloudflare_alt_zone_id" {}
|
||||
variable "domain" {
|
||||
type = string
|
||||
default = "domain.com"
|
||||
}
|
||||
variable "alt_domain" {
|
||||
type = string
|
||||
default = "other_domain.com"
|
||||
}
|
Loading…
Reference in New Issue
Block a user