Compare commits

...

7 commits

Author SHA1 Message Date
377df4486c Remove link to blog
It hasn't been updated in a long time, let's just be rid of it!

It's possible I'll replace it with another blog sometime if we get the
chance to do more development work, it could be a useful way to improve
communication—but not yet!
2024-02-20 10:19:41 -08:00
abbde80f60 Install MySQL server during deployment setup
It's finally colocated onto this box, instead of being on the old
server! I think I'm noticing substantial perf improvements, probably
both from increased colocation (tho they were in the same house
before), and also from like ten years of performance optimizations LOL!

As part of this, I created a new `setup_secrets.yml` file that's
similar to `production.env`, but is for values that the setup script
itself needs access to, whereas `production.env` is for values that the
app needs at runtime. (Though they have some things in common, like the
MySQL user password!) It's gitignored for security, as per usual!
2024-02-19 13:21:24 -08:00
ead0003397 Add custom 502 error page, for when the app goes down but nginx is up 2024-02-19 13:19:31 -08:00
a6daef636c Extract error-grundo.png into an image file
Initially I put this all in the same thing cuz I wasn't sure I could
count on our nginx config to actually serve asset requests correctly…
I've figured it out now!
2024-02-19 11:19:28 -08:00
aa108190b6 Oops, only redirect to maintenance.html internally
Oh I see, if I start with a slash, then it's interpreted as a reference
to a file; whereas if I don't, it's interpreted as a URL redirect. Ok!
2024-02-19 11:18:28 -08:00
7c36ba81e5 Minor change to explanation text in authorized-ssh-keys.txt 2024-02-19 11:12:40 -08:00
974aaa48ff Add maintenance.html page 2024-02-19 09:45:45 -08:00
8 changed files with 234 additions and 7 deletions

View file

@ -61,7 +61,6 @@
%ul %ul
%li= link_to t('organization_name'), 'https://openneo.net/' %li= link_to t('organization_name'), 'https://openneo.net/'
%li= link_to t('.footer.blog'), 'https://blog.openneo.net/'
%li= link_to t('.footer.source_code'), 'https://github.com/openneo/impress' %li= link_to t('.footer.source_code'), 'https://github.com/openneo/impress'
%li= link_to t('.footer.terms'), terms_path %li= link_to t('.footer.terms'), terms_path

View file

@ -1 +1,2 @@
/production.env /production.env
/setup_secrets.yml

View file

@ -1,7 +1,7 @@
# These are the SSH public keys that allow a user to log in and setup or deploy. # These are the SSH public keys that allow a user to log in and setup or deploy.
# #
# It's dangerous to add a new key to this file! When you run # It's dangerous to add a new key to this file! When you run
# `yarn deploy-setup`, it will copy these keys to the deploy server, which will # `bin/deploy:setup`, it will copy these keys to the deploy server, which will
# allow the owner of these keys to log into the deploy server in the future. # allow the owner of these keys to log into the deploy server in the future.
# #
# But the keys themselves aren't necessarily sensitive data, except for the name # But the keys themselves aren't necessarily sensitive data, except for the name

View file

@ -8,6 +8,8 @@ server {
} }
server { server {
set $maintenance 0; # To enable maintenance mode, set this to 1.
server_name {{ impress_hostname }}; server_name {{ impress_hostname }};
listen 443 ssl; listen 443 ssl;
listen [::]:443 ssl; listen [::]:443 ssl;
@ -31,10 +33,24 @@ server {
add_header ETag ""; add_header ETag "";
} }
# On status 503, return the maintenance page. (We'll trigger this ourselves
# in the @app location, if $maintenance is on.)
error_page 503 /maintenance.html;
# On status 502, return the outage page. (nginx will trigger this if the
# `proxy_pass` to the application fails.)
error_page 502 /outage.html;
# Try serving static files first. If not found, fall back to the app. # Try serving static files first. If not found, fall back to the app.
try_files $uri/index.html $uri @app; try_files $uri/index.html $uri @app;
location @app { location @app {
# If we're hardcoded as being in maintenance mode, return status 503, which
# will show the maintenance page as specified above.
if ($maintenance = 1) {
return 503;
}
proxy_pass http://127.0.0.1:3000; proxy_pass http://127.0.0.1:3000;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

View file

@ -6,6 +6,10 @@
vars: vars:
email_address: "emi@matchu.dev" # TODO: Extract this to personal config? email_address: "emi@matchu.dev" # TODO: Extract this to personal config?
impress_hostname: impress.openneo.net impress_hostname: impress.openneo.net
vars_files:
# mysql_root_password, mysql_user_password, mysql_user_password_2020,
# dev_ips
- files/setup_secrets.yml
tasks: tasks:
- name: Create SSH folder for logged-in user - name: Create SSH folder for logged-in user
become: no become: no
@ -62,6 +66,22 @@
rule: allow rule: allow
port: "443" port: "443"
- name: Configure ufw firewall to allow MySQL connections from impress-2020
community.general.ufw:
rule: allow
port: "3306"
from_ip: "{{ item }}"
loop:
- "45.56.112.222"
- "2600:3c02::f03c:92ff:fe9a:4615"
- name: Configure ufw firewall to allow MySQL connections from known devs
community.general.ufw:
rule: allow
port: "3306"
from_ip: "{{ item }}"
loop: "{{ dev_ips }}"
- name: Enable ufw firewall with all other ports closed by default - name: Enable ufw firewall with all other ports closed by default
community.general.ufw: community.general.ufw:
state: enabled state: enabled
@ -290,7 +310,7 @@
src: files/sites-available/impress.conf src: files/sites-available/impress.conf
dest: /etc/nginx/sites-available/impress.conf dest: /etc/nginx/sites-available/impress.conf
notify: notify:
- Restart nginx - Reload nginx
- name: Enable impress config file in nginx - name: Enable impress config file in nginx
file: file:
@ -298,12 +318,84 @@
dest: /etc/nginx/sites-enabled/impress.conf dest: /etc/nginx/sites-enabled/impress.conf
state: link state: link
notify: notify:
- Restart nginx - Reload nginx
- name: Install MariaDB
apt:
name: mariadb-server
- name: Install a Python MySQL client, for Ansible to use when configuring
apt:
name: python3-mysqldb
- name: Update MariaDB root password
community.mysql.mysql_user:
name: root
host_all: true
password: "{{mysql_root_password}}"
- name: Create root's .my.cnf file
copy:
content: |
[client]
user=root
password='{{ mysql_root_password }}'
dest: /root/.my.cnf
mode: 0400
- name: Remove test database
community.mysql.mysql_db:
name: test
state: absent
login_unix_socket: "{{ login_unix_socket | default(omit) }}"
- name: Remove anonymous users
community.mysql.mysql_user:
name: ""
state: absent
host_all: true
- name: Remove remote root access
community.mysql.mysql_query:
query:
- DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')
- name: Expose MariaDB to the internet (but ufw will block most clients)
copy:
dest: /etc/mysql/mariadb.conf.d/80-bind-address.cnf
content: |
[mysqld]
skip-networking=0
skip-bind-address
notify: Restart MariaDB
- name: Create MySQL databases
community.mysql.mysql_db:
name:
- openneo_impress
- openneo_id
- name: Create MySQL user openneo_impress
community.mysql.mysql_user:
name: openneo_impress
password: "{{ mysql_user_password }}"
priv: "openneo_impress.*:ALL,openneo_id.*:ALL"
- name: Create MySQL user impress2020
community.mysql.mysql_user:
name: impress2020
password: "{{ mysql_user_password_2020 }}"
priv: "openneo_impress.*:ALL,openneo_id.*:ALL"
handlers: handlers:
- name: Restart nginx - name: Reload nginx
systemd: systemd:
name: nginx name: nginx
state: reloaded
- name: Restart MariaDB
systemd:
name: mariadb
state: restarted state: restarted
- name: Reload systemctl - name: Reload systemctl

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

56
public/maintenance.html Normal file
View file

@ -0,0 +1,56 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Dress to Impress: Maintenance Time!</title>
<style type="text/css">
body {
background-color: #fff;
color: #666;
font-family: arial, sans-serif;
padding: 2em 1em;
}
main {
border: 1px solid #ccc;
margin-inline: auto;
padding: 1em;
max-width: 600px;
display: grid;
grid-template-areas: "illustration body";
grid-template-columns: auto 1fr;
column-gap: 1em;
}
h1 {
font-size: 1.5em;
margin: 0;
margin-bottom: 0.5em;
}
p {
margin-bottom: 0.5em;
}
</style>
</head>
<body>
<main>
<img
width="100"
height="100"
alt="Distressed Grundo programmer"
src="/images/error-grundo.png"
/>
<div>
<h1>DTI is down for maintenance!</h1>
<p>
We're working on something for the moment, sorry for the
trouble!
</p>
<p>We're doing our best to be back up soon! 💖</p>
</div>
</main>
</body>
</html>

63
public/outage.html Normal file
View file

@ -0,0 +1,63 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Dress to Impress: Surprise Downtime?</title>
<style type="text/css">
body {
background-color: #fff;
color: #666;
font-family: arial, sans-serif;
padding: 2em 1em;
}
main {
border: 1px solid #ccc;
margin-inline: auto;
padding: 1em;
max-width: 600px;
display: grid;
grid-template-areas: "illustration body";
grid-template-columns: auto 1fr;
column-gap: 1em;
}
h1 {
font-size: 1.5em;
margin: 0;
margin-bottom: 0.5em;
}
p {
margin-bottom: 0.5em;
}
</style>
</head>
<body>
<main>
<img
width="100"
height="100"
alt="Distressed Grundo programmer"
src="/images/error-grundo.png"
/>
<div>
<h1>DTI is down for the count?!</h1>
<p>
Hrm, it looks like the DTI application has crashed all the
way into the ground?? 😬
</p>
<p>
This can happen when our system gets overloaded, or when the
team is working on something and we hit the wrong button 😓
</p>
<p>
We'll be notified of this outage, and we'll do our best to
be back up soon! 💖
</p>
</div>
</main>
</body>
</html>