aboutsummaryrefslogtreecommitdiffstats
path: root/docs/deployment.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/deployment.md')
-rw-r--r--docs/deployment.md147
1 files changed, 147 insertions, 0 deletions
diff --git a/docs/deployment.md b/docs/deployment.md
new file mode 100644
index 00000000..841e08c7
--- /dev/null
+++ b/docs/deployment.md
@@ -0,0 +1,147 @@
+# Deployment
+The default Dockerfile should do a good job at running a solid web server that
+automatically adjusts its worker count based on traffic. This is managed by
+uWSGI. You need to configure the `DATABASE_URL` and `SECRET_KEY` variables. If
+you want to deploy to a different host than the default, configure the
+`ALLOWED_HOSTS` variable.
+
+## Static file hosting
+You can either collect the static files in the container and use uWSGI to host
+them, or put them on your host and manage them through a web server running on
+the host like nginx.
+
+## Database migrations
+To bring the schema up-to-date, first stop an existing database container, then
+start a container that just runs the migrations and exits, and then starts the
+main container off the new container again.
+
+## Ansible task
+An example Ansible task to deploy the site is shown below, it should read fairly
+humanly and give you a rough idea of steps needed to deploy the site.
+
+```yml
+---
+- name: ensure the `{{ pysite_pg_username }}` postgres user exists
+ become: yes
+ become_user: postgres
+ postgresql_user:
+ name: "{{ pysite_pg_username }}"
+ password: "{{ pysite_pg_password }}"
+ when: pysite_pg_host == 'localhost'
+
+- name: ensure the `{{ pysite_pg_database }}` postgres database exists
+ become: yes
+ become_user: postgres
+ postgresql_db:
+ name: "{{ pysite_pg_database }}"
+ owner: "{{ pysite_pg_username }}"
+ when: pysite_pg_host == 'localhost'
+
+- name: ensure the `{{ pysite_hub_repository }}` image is up-to-date
+ become: yes
+ docker_image:
+ name: "{{ pysite_hub_repository }}"
+ force: yes
+
+- name: ensure the nginx HTTP vhosts are up-to-date
+ become: yes
+ template:
+ src: "nginx/{{ item.key }}.http.conf.j2"
+ dest: "/etc/nginx/sites-available/{{ item.value }}.http.conf"
+ with_dict: "{{ pysite_domains }}"
+ notify: reload nginx
+
+- name: ensure the nginx HTTPS vhosts are up-to-date
+ become: yes
+ template:
+ src: "nginx/{{ item.key }}.https.conf.j2"
+ dest: "/etc/nginx/sites-available/{{ item.value }}.https.conf"
+ with_dict: "{{ pysite_domains }}"
+ notify: reload nginx
+
+- name: ensure the nginx HTTP vhosts are symlinked to `/etc/nginx/sites-enabled`
+ become: yes
+ file:
+ src: /etc/nginx/sites-available/{{ item.value }}.http.conf
+ dest: /etc/nginx/sites-enabled/{{ item.value }}.http.conf
+ state: link
+ with_dict: "{{ pysite_domains }}"
+ notify: reload nginx
+
+- name: ensure we have HTTPS certificates
+ include_role:
+ name: thefinn93.letsencrypt
+ vars:
+ letsencrypt_cert_domains: "{{ pysite_domains | dict2items | map(attribute='value') | list }}"
+ letsencrypt_email: "[email protected]"
+ letsencrypt_renewal_command_args: '--renew-hook "systemctl restart nginx"'
+ letsencrypt_webroot_path: /var/www/_letsencrypt
+
+- name: ensure the nginx HTTPS vhosts are symlinked to `/etc/nginx/sites-enabled`
+ become: yes
+ file:
+ src: /etc/nginx/sites-available/{{ item.value }}.https.conf
+ dest: /etc/nginx/sites-enabled/{{ item.value }}.https.conf
+ state: link
+ with_dict: "{{ pysite_domains }}"
+ notify: reload nginx
+
+- name: ensure the web container is absent
+ become: yes
+ docker_container:
+ name: pysite
+ state: absent
+
+- name: ensure the `{{ pysite_static_file_dir }}` directory exists
+ become: yes
+ file:
+ path: "{{ pysite_static_file_dir }}"
+ state: directory
+ owner: root
+ group: root
+
+- name: collect static files
+ become: yes
+ docker_container:
+ image: "{{ pysite_hub_repository }}"
+ name: pysite-static-file-writer
+ command: python manage.py collectstatic --noinput
+ detach: no
+ cleanup: yes
+ network_mode: host
+ env:
+ DATABASE_URL: "{{ pysite_pg_database_url }}"
+ SECRET_KEY: "me-dont-need-no-secret-key"
+ STATIC_ROOT: "/html"
+ volumes:
+ - "/var/www/pythondiscord.com:/html"
+
+- name: ensure the database schema is up-to-date
+ become: yes
+ docker_container:
+ image: "{{ pysite_hub_repository }}"
+ name: pysite-migrator
+ detach: no
+ cleanup: yes
+ command: python manage.py migrate
+ network_mode: host
+ env:
+ DATABASE_URL: "postgres://{{ pysite_pg_username }}:{{ pysite_pg_password }}@{{ pysite_pg_host }}/{{ pysite_pg_database }}"
+ SECRET_KEY: "me-dont-need-no-secret-key"
+
+- name: ensure the website container is started
+ become: yes
+ docker_container:
+ image: "{{ pysite_hub_repository }}"
+ name: pysite
+ network_mode: host
+ restart: yes
+ restart_policy: unless-stopped
+ ports:
+ - "127.0.0.1:4000:4000"
+ env:
+ ALLOWED_HOSTS: "{{ pysite_domains | dict2items | map(attribute='value') | join(',') }}"
+ DATABASE_URL: "postgres://{{ pysite_pg_username }}:{{ pysite_pg_password }}@{{ pysite_pg_host }}/{{ pysite_pg_database }}"
+ PARENT_HOST: pysite.example.com
+ SECRET_KEY: "{{ pysite_secret_key }}"
+```