From 5f0ce9e7ad99cc9b489bd356c7a905fb8280026e Mon Sep 17 00:00:00 2001 From: evelyn masso Date: Thu, 23 May 2024 14:57:11 -0700 Subject: [PATCH 1/3] add deploy scripts copied from https://github.com/bocoup/deploy/tree/46b7e4828a3857585aa7e7baab3fe4365453712e --- .gitignore | 1 - deploy/deploy.yml | 26 +++++++ deploy/inventory.example.yml | 40 +++++++++++ deploy/lockdown.yml | 40 +++++++++++ deploy/provision.yml | 114 +++++++++++++++++++++++++++++++ deploy/templates/nginx.conf | 17 +++++ deploy/templates/start.sh | 3 + deploy/templates/systemd.service | 14 ++++ 8 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 deploy/deploy.yml create mode 100644 deploy/inventory.example.yml create mode 100644 deploy/lockdown.yml create mode 100644 deploy/provision.yml create mode 100644 deploy/templates/nginx.conf create mode 100644 deploy/templates/start.sh create mode 100644 deploy/templates/systemd.service diff --git a/.gitignore b/.gitignore index 202474a..08e9b68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .DS_Store node_modules inventory.yml -deploy /build /public/build diff --git a/deploy/deploy.yml b/deploy/deploy.yml new file mode 100644 index 0000000..60735a7 --- /dev/null +++ b/deploy/deploy.yml @@ -0,0 +1,26 @@ +- name: Deploy the app + hosts: all + remote_user: deploy + tasks: + - name: Copy app files to server + copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + loop: "{{ deploy_files }}" + + - name: Install npm deps + shell: + cmd: "source /home/deploy/.nvm/nvm.sh && nvm exec default npm install" + chdir: /home/{{ domain }} + args: + executable: /bin/bash + + - name: Run migrations + shell: + cmd: "source /home/deploy/.nvm/nvm.sh && nvm exec default npx prisma migrate deploy" + chdir: /home/{{ domain }} + args: + executable: /bin/bash + + - name: Start the app with systemd + shell: "sudo systemctl restart {{ domain }}" diff --git a/deploy/inventory.example.yml b/deploy/inventory.example.yml new file mode 100644 index 0000000..9021935 --- /dev/null +++ b/deploy/inventory.example.yml @@ -0,0 +1,40 @@ +# Our production server. +# Copy this whole block if you'd like to add a staging server +Production: + # The IP address of your server. + # Add a second one if you'd like to deploy twice. + # You can add as many as you want. + hosts: an.ip.add.ress + vars: + # Used for your app's domain name + domain: example.com + # Used for your certbot email, note you'll be agreeing to the ToS. + email: you@example.com + # Pick your node version + nodejs_version: 20 + # If you have an SSH key on your server for the root user, you don't need this + ansible_ssh_pass: "secret" + # List of files and folders to copy to the server on deploy. + # Change this to be the files your node app needs to run. + # Example set up for a remix.run indie stack app. + deploy_files: + - src: ../prisma/migrations + dest: /home/{{ domain }}/prisma/ + - src: ../prisma/schema.prisma + dest: /home/{{ domain }}/prisma/schema.prisma + - src: ../build/ + dest: /home/{{ domain }}/build + - src: ../public/ + dest: /home/{{ domain }}/public + - src: ../.env + dest: /home/{{ domain }}/ + - src: ../.npmrc + dest: /home/{{ domain }}/ + - src: ../package.json + dest: /home/{{ domain }}/ + - src: ../package-lock.json + dest: /home/{{ domain }}/ + - src: ../LICENSE.md + dest: /home/{{ domain }}/ + - src: ../README.md + dest: /home/{{ domain }}/ diff --git a/deploy/lockdown.yml b/deploy/lockdown.yml new file mode 100644 index 0000000..da9d300 --- /dev/null +++ b/deploy/lockdown.yml @@ -0,0 +1,40 @@ +- name: Add deploy user and disable root user + hosts: all + vars: + remote_user: root + tasks: + - name: Add a new user named deploy + user: name=deploy + + - name: Add deploy user to the sudoers + copy: + dest: "/etc/sudoers.d/deploy" + content: "deploy ALL=(ALL) NOPASSWD: ALL" + + - name: Deploy your SSH Key + authorized_key: user=deploy + key="{{ lookup('file', '~/.ssh/id_rsa.pub') }}" + state=present + + - name: Disable Password Authentication + lineinfile: dest=/etc/ssh/sshd_config + regexp='^PasswordAuthentication' + line="PasswordAuthentication no" + state=present + backup=yes + notify: + - restart ssh + + - name: Disable Root Login + lineinfile: dest=/etc/ssh/sshd_config + regexp='^PermitRootLogin' + line="PermitRootLogin no" + state=present + backup=yes + notify: + - restart ssh + + handlers: + - name: restart ssh + service: name=ssh + state=restarted diff --git a/deploy/provision.yml b/deploy/provision.yml new file mode 100644 index 0000000..87b49e0 --- /dev/null +++ b/deploy/provision.yml @@ -0,0 +1,114 @@ +- name: Update and upgrade apt packages + hosts: all + remote_user: deploy + become: yes + + tasks: + - name: Update apt repo and cache + apt: + update_cache: yes + force_apt_get: yes + cache_valid_time: 3600 + + - name: Upgrade all packages + apt: + upgrade: dist + force_apt_get: yes + + - name: Check if a reboot is needed + register: reboot_required_file + stat: + path: /var/run/reboot-required + + - name: Reboot the server if kernel updated + reboot: + msg: "Reboot initiated by Ansible for 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 + +- name: Install packages + hosts: all + remote_user: deploy + become: true + tasks: + - name: Install system packages with apt + register: updatesys + apt: + update_cache: yes + name: + - curl + - gnupg + - ufw + - nginx + - python3-certbot-nginx + state: present + + - name: Enable ufw firewall + community.general.ufw: + state: enabled + + - community.general.ufw: + rule: allow + name: OpenSSH + + - community.general.ufw: + rule: allow + name: "Nginx Full" + + - name: Create directory for the app + file: path=/home/{{domain}} + state=directory + owner=deploy + group=deploy + + - name: Copy nginx conf to server + template: src=./templates/nginx.conf + dest=/etc/nginx/sites-available/{{ domain }}.conf + + - name: Create symlink to new nginx conf + file: src=/etc/nginx/sites-available/{{ domain }}.conf + dest=/etc/nginx/sites-enabled/{{ domain }}.conf + state=link + + - name: Create ssl certificate with certbot + shell: "sudo certbot --nginx -d {{ domain }} --agree-tos --email {{ email }} --non-interactive" + notify: Restart nginx + + - name: Copy systemd service to server + template: src=./templates/systemd.service + dest=/lib/systemd/system/{{ domain }}.service + + - name: Copy systemd friendly start script to server + template: + src: ./templates/start.sh + dest: /home/{{ domain }}/start.sh + mode: +x + + - name: Reload and enable systemd service + shell: "sudo systemctl daemon-reload && sudo systemctl enable --now {{ domain }} && sudo systemctl start {{ domain }}" + + handlers: + - name: Restart nginx + service: + name: nginx + state: restarted + +- name: Install node and the app + hosts: all + remote_user: deploy + tasks: + - name: Install nvm + shell: > + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash + args: + creates: "{{ ansible_env.HOME }}/.nvm/nvm.sh" + + - name: Install node and set version + shell: > + source ~/.nvm/nvm.sh && nvm install {{ nodejs_version }} && nvm use {{ nodejs_version }} + args: + executable: /bin/bash diff --git a/deploy/templates/nginx.conf b/deploy/templates/nginx.conf new file mode 100644 index 0000000..72761ed --- /dev/null +++ b/deploy/templates/nginx.conf @@ -0,0 +1,17 @@ +server { + listen 80; + listen [::]:80; + server_name {{ domain }}; + access_log /var/log/nginx/{{ domain }}.log; + error_log /var/log/nginx/{{ domain }}-error.log error; + + location / { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $http_host; + proxy_pass http://127.0.0.1:3000; + proxy_redirect off; + client_max_body_size 10M; + } +} \ No newline at end of file diff --git a/deploy/templates/start.sh b/deploy/templates/start.sh new file mode 100644 index 0000000..7bbd22a --- /dev/null +++ b/deploy/templates/start.sh @@ -0,0 +1,3 @@ +#!/bin/bash +. /home/deploy/.nvm/nvm.sh +npm start diff --git a/deploy/templates/systemd.service b/deploy/templates/systemd.service new file mode 100644 index 0000000..ed501a9 --- /dev/null +++ b/deploy/templates/systemd.service @@ -0,0 +1,14 @@ +[Unit] +Description={{ domain }} +After=network.target + +[Service] +Environment=NODE_ENV=production +Type=simple +User=root +WorkingDirectory=/home/{{ domain }} +ExecStart=/home/{{ domain }}/start.sh +Restart=on-failure + +[Install] +WantedBy=multi-user.target From b69f9f8765f8e1df13ec418d57fe7e10c4356df9 Mon Sep 17 00:00:00 2001 From: evelyn masso Date: Thu, 23 May 2024 14:59:15 -0700 Subject: [PATCH 2/3] remove submodule init from remix --- remix.init/index.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/remix.init/index.js b/remix.init/index.js index fefd980..eca7943 100644 --- a/remix.init/index.js +++ b/remix.init/index.js @@ -191,11 +191,6 @@ const main = async ({ packageManager, rootDirectory }) => { fs.rm(path.join(rootDirectory, "LICENSE.md")), ]); - execSync("git submodule add git@github.com:bocoup/deploy.git", { - cwd: rootDirectory, - stdio: "inherit", - }); - execSync(pm.run("setup"), { cwd: rootDirectory, stdio: "inherit" }); execSync(pm.run("format", "--log-level warn"), { From 1b7da1064f2f8b8298a431633ad622545fd80df7 Mon Sep 17 00:00:00 2001 From: evelyn masso Date: Thu, 23 May 2024 16:50:41 -0700 Subject: [PATCH 3/3] remove license file from example inventory --- deploy/inventory.example.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/deploy/inventory.example.yml b/deploy/inventory.example.yml index 9021935..b9590f9 100644 --- a/deploy/inventory.example.yml +++ b/deploy/inventory.example.yml @@ -34,7 +34,5 @@ Production: dest: /home/{{ domain }}/ - src: ../package-lock.json dest: /home/{{ domain }}/ - - src: ../LICENSE.md - dest: /home/{{ domain }}/ - src: ../README.md dest: /home/{{ domain }}/