From 2cbf191b69ca3ceeb644b2e06610ec86fb369cc8 Mon Sep 17 00:00:00 2001 From: Felix Date: Fri, 31 Jan 2020 12:03:26 +0100 Subject: [PATCH] Integrate email relay in Ansible setup --- ansible/VERSION | 1 + ansible/inventory.example | 2 +- ansible/lemmy.yml | 1 + ansible/lemmy_dev.yml | 100 +++++++++++++++++++++++++++ ansible/templates/config.hjson | 7 +- ansible/templates/docker-compose.yml | 7 +- ansible/templates/nginx.conf | 2 +- docker/dev/deploy.sh | 3 + server/src/lib.rs | 42 +++++------ server/src/settings.rs | 5 +- 10 files changed, 141 insertions(+), 29 deletions(-) create mode 100644 ansible/VERSION create mode 100644 ansible/lemmy_dev.yml diff --git a/ansible/VERSION b/ansible/VERSION new file mode 100644 index 000000000..08bc6bd09 --- /dev/null +++ b/ansible/VERSION @@ -0,0 +1 @@ +v0.6.5 diff --git a/ansible/inventory.example b/ansible/inventory.example index b85505cc4..52b45d3c3 100644 --- a/ansible/inventory.example +++ b/ansible/inventory.example @@ -1,6 +1,6 @@ [lemmy] # define the username and hostname that you use for ssh connection, and specify the domain -myuser@example.com domain=example.com letsencrypt_contact_email=your@email.com smtp_server=smtp@example.com smtp_login=your@email.com smtp_password=pass smtp_from_address="Example.com Admin " +myuser@example.com domain=example.com letsencrypt_contact_email=your@email.com [all:vars] ansible_connection=ssh diff --git a/ansible/lemmy.yml b/ansible/lemmy.yml index 6ec4f916a..87f71699d 100644 --- a/ansible/lemmy.yml +++ b/ansible/lemmy.yml @@ -41,6 +41,7 @@ vars: postgres_password: "{{ lookup('password', 'passwords/{{ inventory_hostname }}/postgres chars=ascii_letters,digits') }}" jwt_password: "{{ lookup('password', 'passwords/{{ inventory_hostname }}/jwt chars=ascii_letters,digits') }}" + lemmy_docker_image: "dessalines/lemmy:{{ lookup('file', 'VERSION') }}" - name: enable and start docker service systemd: diff --git a/ansible/lemmy_dev.yml b/ansible/lemmy_dev.yml new file mode 100644 index 000000000..c15569faf --- /dev/null +++ b/ansible/lemmy_dev.yml @@ -0,0 +1,100 @@ +--- +- hosts: all + vars: + lemmy_docker_image: "lemmy:dev" + + # Install python if required + # https://www.josharcher.uk/code/ansible-python-connection-failure-ubuntu-server-1604/ + gather_facts: False + pre_tasks: + - name: install python for Ansible + raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal python-setuptools) + args: + executable: /bin/bash + register: output + changed_when: output.stdout != "" + - setup: # gather facts + + tasks: + - name: install dependencies + apt: + pkg: ['nginx', 'docker-compose', 'docker.io', 'certbot', 'python-certbot-nginx'] + + - name: request initial letsencrypt certificate + command: certbot certonly --nginx --agree-tos -d '{{ domain }}' -m '{{ letsencrypt_contact_email }}' + args: + creates: '/etc/letsencrypt/live/{{domain}}/privkey.pem' + + - name: create lemmy folder + file: path={{item.path}} state=directory + with_items: + - { path: '/lemmy/' } + - { path: '/lemmy/volumes/' } + + - block: + - name: add template files + template: src={{item.src}} dest={{item.dest}} mode={{item.mode}} + with_items: + - { src: 'templates/docker-compose.yml', dest: '/lemmy/docker-compose.yml', mode: '0600' } + - { src: 'templates/nginx.conf', dest: '/etc/nginx/sites-enabled/lemmy.conf', mode: '0644' } + + - name: add config file (only during initial setup) + template: src='templates/config.hjson' dest='/lemmy/lemmy.hjson' mode='0600' force='no' owner='1000' group='1000' + vars: + postgres_password: "{{ lookup('password', 'passwords/{{ inventory_hostname }}/postgres chars=ascii_letters,digits') }}" + jwt_password: "{{ lookup('password', 'passwords/{{ inventory_hostname }}/jwt chars=ascii_letters,digits') }}" + + - name: build the dev docker image + local_action: shell cd .. && sudo docker build . -f docker/dev/Dockerfile -t lemmy:dev + register: image_build + + - name: find hash of the new docker image + set_fact: + image_hash: "{{ image_build.stdout | regex_search('(?<=Successfully built )[0-9a-f]{12}') }}" + + # this does not use become so that the output file is written as non-root user and is easy to delete later + - name: save dev docker image to file + local_action: shell sudo docker save lemmy:dev > lemmy-dev.tar + + - name: copy dev docker image to server + copy: src=lemmy-dev.tar dest=/lemmy/lemmy-dev.tar + + - name: import docker image + docker_image: + name: lemmy + tag: dev + load_path: /lemmy/lemmy-dev.tar + source: load + force_source: yes + register: image_import + + - name: delete remote image file + file: path=/lemmy/lemmy-dev.tar state=absent + + - name: delete local image file + local_action: file path=lemmy-dev.tar state=absent + + - name: enable and start docker service + systemd: + name: docker + enabled: yes + state: started + + # cant pull here because that fails due to lemmy:dev (without dessalines/) not being on docker hub, but that shouldnt + # be a problem for testing + - name: start docker-compose + docker_compose: + project_src: /lemmy/ + state: present + recreate: always + ignore_errors: yes + + - name: reload nginx with new config + shell: nginx -s reload + + - name: certbot renewal cronjob + cron: + special_time=daily + name=certbot-renew-lemmy + user=root + job="certbot certonly --nginx -d '{{ domain }}' --deploy-hook 'docker-compose -f /peertube/docker-compose.yml exec nginx nginx -s reload'" diff --git a/ansible/templates/config.hjson b/ansible/templates/config.hjson index 621b8bcb9..42698dfbb 100644 --- a/ansible/templates/config.hjson +++ b/ansible/templates/config.hjson @@ -7,9 +7,8 @@ jwt_secret: "{{ jwt_password }}" front_end_dir: "/app/dist" email: { - smtp_server: "{{ smtp_server }}" - smtp_login: "{{ smtp_login }}" - smtp_password: "{{ smtp_password }}" - smtp_from_address: "{{ smtp_from_address }}" + smtp_server: "postfix:25" + smtp_from_address: "noreply@{{ domain }}" + use_tls: false } } diff --git a/ansible/templates/docker-compose.yml b/ansible/templates/docker-compose.yml index db977c5b6..2693d7ad2 100644 --- a/ansible/templates/docker-compose.yml +++ b/ansible/templates/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.3' services: lemmy: - image: dessalines/lemmy:v0.6.9 + image: {{ lemmy_docker_image }} ports: - "127.0.0.1:8536:8536" restart: always @@ -30,6 +30,11 @@ services: - lemmy_pictshare:/usr/share/nginx/html/data restart: always + postfix: + image: mwader/postfix-relay + environment: + - POSTFIX_myhostname={{ domain }} + restart: "always" volumes: lemmy_db: lemmy_pictshare: diff --git a/ansible/templates/nginx.conf b/ansible/templates/nginx.conf index 1fc6e6746..9f31140b2 100644 --- a/ansible/templates/nginx.conf +++ b/ansible/templates/nginx.conf @@ -93,4 +93,4 @@ map $remote_addr $remote_addr_anon { } log_format main '$remote_addr_anon - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent"'; -access_log /dev/stdout main; +access_log /var/log/nginx/access.log main; diff --git a/docker/dev/deploy.sh b/docker/dev/deploy.sh index a1dad9670..38ea61618 100755 --- a/docker/dev/deploy.sh +++ b/docker/dev/deploy.sh @@ -14,6 +14,9 @@ git add "ui/src/version.ts" # Setting the version on the backend echo "pub const VERSION: &str = \"$(git describe --tags)\";" > "server/src/version.rs" git add "server/src/version.rs" +# Setting the version for Ansible +git describe --tags > "ansible/VERSION" +git add "ansible/VERSION" cd docker/dev diff --git a/server/src/lib.rs b/server/src/lib.rs index 2e6b6fd6e..3e22585de 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -36,7 +36,7 @@ use chrono::{DateTime, NaiveDateTime, Utc}; use lettre::smtp::authentication::{Credentials, Mechanism}; use lettre::smtp::extension::ClientId; use lettre::smtp::ConnectionReuseParameters; -use lettre::{SmtpClient, Transport}; +use lettre::{ClientSecurity, SmtpClient, Transport}; use lettre_email::Email; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; @@ -110,34 +110,36 @@ pub fn send_email( let email = Email::builder() .to((to_email, to_username)) - .from(( - email_config.smtp_login.to_owned(), - email_config.smtp_from_address.to_owned(), - )) + .from(email_config.smtp_from_address.to_owned()) .subject(subject) .html(html) .build() .unwrap(); - let mut mailer = SmtpClient::new_simple(&email_config.smtp_server) - .unwrap() - .hello_name(ClientId::Domain(Settings::get().hostname.to_owned())) - .credentials(Credentials::new( - email_config.smtp_login.to_owned(), - email_config.smtp_password.to_owned(), - )) - .smtp_utf8(true) - .authentication_mechanism(Mechanism::Plain) - .connection_reuse(ConnectionReuseParameters::ReuseUnlimited) - .transport(); + let mailer = if email_config.use_tls { + SmtpClient::new_simple(&email_config.smtp_server).unwrap() + } else { + SmtpClient::new(&email_config.smtp_server, ClientSecurity::None).unwrap() + } + .hello_name(ClientId::Domain(Settings::get().hostname.to_owned())) + .smtp_utf8(true) + .authentication_mechanism(Mechanism::Plain) + .connection_reuse(ConnectionReuseParameters::ReuseUnlimited); + let mailer = if let (Some(login), Some(password)) = + (&email_config.smtp_login, &email_config.smtp_password) + { + mailer.credentials(Credentials::new(login.to_owned(), password.to_owned())) + } else { + mailer + }; - let result = mailer.send(email.into()); - - mailer.close(); + let mut transport = mailer.transport(); + let result = transport.send(email.into()); + transport.close(); match result { Ok(_) => Ok(()), - Err(_) => Err("no_email_setup".to_string()), + Err(e) => Err(e.to_string()), } } diff --git a/server/src/settings.rs b/server/src/settings.rs index f4bb2a42a..ee3a3c072 100644 --- a/server/src/settings.rs +++ b/server/src/settings.rs @@ -33,9 +33,10 @@ pub struct RateLimitConfig { #[derive(Debug, Deserialize)] pub struct EmailConfig { pub smtp_server: String, - pub smtp_login: String, - pub smtp_password: String, + pub smtp_login: Option, + pub smtp_password: Option, pub smtp_from_address: String, + pub use_tls: bool, } #[derive(Debug, Deserialize)]