--- - name: Set up the environment for the impress-2020 app hosts: webserver vars: email_address: "emi@matchu.dev" # TODO: Extract this to personal config? tasks: - name: Create web user group become: yes group: name: web - name: Add current user to web group become: yes user: name: "{{ ansible_user_id }}" group: web append: yes - name: Create the app folder become: yes file: path: /srv/impress-2020 state: directory # Root and the `web` group may read/write this folder. Everyone else # may only read it. group: web mode: "u=rwx,g=rwx,o=rx" - name: Add Nodesource apt key become: yes apt_key: id: 9FD3B784BC1C6FC31A8A0A1C1655A0AB68576280 url: https://deb.nodesource.com/gpgkey/nodesource.gpg.key - name: Add Node v16 apt repository become: yes apt_repository: repo: deb https://deb.nodesource.com/node_16.x focal main - name: Install Node v16 become: yes apt: update_cache: yes name: nodejs state: present - name: Install Yarn become: yes npm: name: yarn global: yes - name: Install pm2 become: yes npm: name: pm2 global: yes - name: Create pm2 startup script # The current user is going to become the pm2 owner of the app server # process. They'll be able to manage it without `sudo`, including during # normal deploys, and run `pm2 monit` from their shell to see status. become: yes command: "pm2 startup systemd {{ ansible_user_id }} --hp /home/{{ ansible_user_id }}" - name: Create pm2 ecosystem file copy: content: | module.exports = { apps: [ { name: "impress-2020", cwd: "/srv/impress-2020/current", // Instead of `yarn start`, we specify the `next` binary // directly, because it helps pm2 monitor our app correctly. // https://github.com/vercel/next.js/discussions/10675#discussioncomment-34615 script: "./node_modules/.bin/next", args: "start --port=3000", instances: "max", exec_mode: "cluster", } ] } dest: "~/ecosystem.config.js" # Create a temporary backup file, so we can use it to delete the old # version of the services. (This is important if e.g. a service is # removed or renamed, in which case deleting from the *new* config file # wouldn't include it.) backup: yes register: pm2_ecosystem_file - name: Delete old pm2 services if config file changed command: "pm2 delete {{ pm2_ecosystem_file.backup_file | quote }}" when: pm2_ecosystem_file is changed and pm2_ecosystem_file.backup_file is defined - name: Delete old pm2 config file if it changed file: path: "{{ pm2_ecosystem_file.backup_file }}" state: absent when: pm2_ecosystem_file is changed and pm2_ecosystem_file.backup_file is defined - name: Start pm2 services command: "pm2 start ~/ecosystem.config.js" - name: Save pm2 startup script command: pm2 save - name: Install core snap become: yes community.general.snap: name: core - name: Install certbot as a snap become: yes community.general.snap: name: certbot classic: yes - name: Set up certbot become: yes command: "certbot certonly --nginx -n --agree-tos --email {{ email_address }} --domains impress-2020-box.openneo.net" - name: Install nginx become: yes apt: update_cache: yes name: nginx - name: Add impress-2020 config file to nginx become: yes copy: content: | server { server_name impress-2020-box.openneo.net; listen 80; if ($host = impress-2020-box.openneo.net) { return 301 https://$host$request_uri; } } server { server_name impress-2020-box.openneo.net; listen 443 ssl; ssl_certificate /etc/letsencrypt/live/impress-2020-box.openneo.net/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/impress-2020-box.openneo.net/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; ssl_session_cache shared:SSL:10m; # https://superuser.com/q/1484466/14127 # TODO: Serve static files directly, instead of through the proxy location / { proxy_pass http://127.0.0.1:3000; } } dest: /etc/nginx/sites-enabled/impress-2020 notify: - Restart nginx - name: Install dependencies for the npm module node-canvas become: yes apt: update_cache: yes name: - build-essential - libcairo2-dev - libpango1.0-dev - libjpeg-dev - libgif-dev - librsvg2-dev handlers: - name: Restart nginx become: yes systemd: name: nginx state: restarted