Skip to content

Commit b791982

Browse files
committed
Updated deployment docs
1 parent f1866d9 commit b791982

2 files changed

Lines changed: 111 additions & 146 deletions

File tree

DIGITALOCEAN.md

Lines changed: 111 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,149 +1,139 @@
1-
# DigitalOcean Configuration
1+
# Freehub Deployment on Digital Ocean
22

3-
Configuration changes required for running Freehub (Rails 2.3) on DigitalOcean.
3+
https://freehub.bikekitchen.org is hosted on the [DigitalOcean App Platform](https://www.digitalocean.com/products/app-platform) with a managed MySQL database.
44

5-
---
6-
7-
### 1. App Platform Environment Variables
8-
9-
Set these app-level environment variables:
5+
> **Tip**: [Claude Code](https://docs.anthropic.com/en/docs/claude-code) is a helpful assistant for configuring and managing the DigitalOcean application environment.
106
11-
1. Go to **App Platform** → your app → **Settings**
12-
2. Under **App-Level Environment Variables**, add:
13-
- `RAILS_ENV` = `production`
14-
- `SITE_URL` = `https://freehub.bikekitchen.org` (staging: `https://freehub-staging.bikekitchen.org`)
15-
- `AIRBRAKE_API_KEY` = *(Airbrake API key)*
16-
- `RESEND_API_KEY` = *(Resend SMTP API key)*
7+
## Overview
178

18-
`RAILS_ENV` is required — without it, Rails defaults to development mode and won't use the production database configuration.
9+
| Component | Service | Notes |
10+
|-----------|---------|-------|
11+
| **Application** | DigitalOcean App Platform | Rails 2.3 app in Docker |
12+
| **Database** | DigitalOcean Managed MySQL 8 | Premium AMD, 2GB RAM |
13+
| **DNS** | Bluehost | bikekitchen.org domain |
14+
| **SSL** | DigitalOcean (Let's Encrypt) | Auto-managed, auto-renewed |
15+
| **Email** | Resend | Transactional emails via SMTP |
16+
| **Error Tracking** | Airbrake | Automatic error notifications |
17+
| **Analytics** | Google Analytics (GA4) | Usage statistics |
18+
| **Uptime Monitoring** | DigitalOcean | Alerts on downtime |
1919

2020
---
2121

22-
### 2. MySQL Password Encryption (Legacy)
22+
## DNS
2323

24-
Changed the `freehub_app` database user to use legacy MySQL 5.x password encryption:
24+
DNS for `freehub.bikekitchen.org` is managed in **Bluehost** (bikekitchen.org domain).
2525

26-
1. Go to **Databases** → your database cluster → **Users & Databases**
27-
2. Find the `freehub_app` user
28-
3. Click **More** (three dots) → **Edit Password Encryption**
29-
4. Select **Legacy - MySQL 5.x** (`mysql_native_password`) → **Save**
30-
31-
**Why**: The old `mysql` gem in Rails 2.3 doesn't support MySQL 8.0's default `caching_sha2_password` authentication plugin.
32-
33-
**Security note**: `mysql_native_password` is less secure than `caching_sha2_password`, but is required for compatibility with older MySQL client libraries.
26+
```
27+
freehub.bikekitchen.org CNAME freehub-app-s65go.ondigitalocean.app
28+
freehub-staging.bikekitchen.org CNAME freehub-staging-hkbze.ondigitalocean.app
29+
```
3430

3531
---
3632

37-
### 3. Disable sql_require_primary_key
38-
39-
We disabled `sql_require_primary_key` on the DigitalOcean managed MySQL database to support Rails 2.3 HABTM (has_and_belongs_to_many) join tables which don't have primary keys.
40-
41-
**What was changed:**
33+
## External Services
4234

43-
Disabled `sql_require_primary_key` via DigitalOcean API:
35+
### Email (Resend)
4436

45-
```bash
46-
doctl databases configuration update af845ccd-eb8d-4f0d-99b5-2c8cffc71681 --engine mysql --config-json '{"sql_require_primary_key": false}'
47-
```
37+
Transactional emails (account activation, password reset, etc.) are sent via [Resend](https://resend.com) SMTP.
4838

49-
**Why**: The `roles_users` join table (for the `Role has_and_belongs_to_many :users` relationship) doesn't have a primary key. Rails 2.3 HABTM doesn't support primary keys on join tables, but DigitalOcean's default MySQL 8.0 configuration requires them for replication purposes.
39+
- **SMTP host**: `smtp.resend.com`
40+
- **Port**: 2587
41+
- **Domain**: `bikekitchen.org`
5042

51-
**Affected tables:**
43+
The API key is configured via the `RESEND_API_KEY` environment variable.
5244

53-
| Table | Purpose | Notes |
54-
|-------|---------|-------|
55-
| `roles_users` | User role assignments (HABTM join table) | Small, rarely updated |
56-
| `schema_info` | Legacy Rails 1.x migration tracking | Not used at runtime, may exist in old backups |
57-
| `schema_migrations` | Rails migration version tracking | Only written during deploys |
45+
### Error Tracking (Airbrake)
5846

59-
**Implications:**
47+
Errors are tracked by [Airbrake](https://airbrake.io) and notifications are sent to configured team members.
6048

61-
- **Single-node cluster**: No impact
62-
- **Multi-node cluster**: Potential replication lag on updates/deletes to tables without PKs, since MySQL must do full table scans to identify rows. Risk is minimal for `roles_users` due to its small size and infrequent updates.
49+
The API key is configured via the `AIRBRAKE_API_KEY` environment variable.
6350

64-
**How to revert:**
51+
### Analytics (Google Analytics)
6552

66-
1. Add a primary key to `roles_users`:
67-
```sql
68-
ALTER TABLE roles_users ADD COLUMN id INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST;
69-
```
53+
Usage statistics are tracked in Google Analytics (GA4). Access via the Google Analytics dashboard.
7054

71-
2. Re-enable the requirement:
72-
```bash
73-
doctl databases configuration update af845ccd-eb8d-4f0d-99b5-2c8cffc71681 --engine mysql --config-json '{"sql_require_primary_key": true}'
74-
```
55+
---
7556

76-
3. Optionally, convert the HABTM to `has_many :through` in the Rails models for a cleaner long-term solution.
57+
## DigitalOcean Configuration
7758

78-
---
59+
### Apps
7960

80-
### 4. Database Tier
61+
| App | URL | Auto-deploy |
62+
|-----|-----|-------------|
63+
| **Production** | https://freehub.bikekitchen.org | OFF (manual) |
64+
| **Staging** | https://freehub-staging.bikekitchen.org | ON (from master) |
8165

82-
Using **Premium AMD, 1 vCPU, 2GB RAM** ($36/mo) with NVMe storage. Upgraded from Regular 1 vCPU/1GB for better query performance — dedicated CPU and NVMe disk significantly improve aggregation queries across large tables.
66+
### Environment Variables
8367

84-
---
68+
Set in App Platform → Settings → App-Level Environment Variables:
8569

86-
### 5. Database Trusted Sources
70+
| Variable | Value |
71+
|----------|-------|
72+
| `RAILS_ENV` | `production` |
73+
| `SITE_URL` | `https://freehub.bikekitchen.org` |
74+
| `AIRBRAKE_API_KEY` | *(Airbrake API key)* |
75+
| `RESEND_API_KEY` | *(Resend SMTP API key)* |
8776

88-
By default, DigitalOcean managed databases block external connections. To allow developers to connect directly to the database:
77+
`RAILS_ENV` is required — without it, Rails defaults to development mode.
8978

90-
1. Go to **Databases** → your database cluster → **Settings**
91-
2. Scroll to **Trusted Sources**
92-
3. Add the developer's IP address (find it with `curl ifconfig.me`)
79+
### Database
9380

94-
**Note**: For security, avoid using "Allow all IPv4". Add specific IPs as needed.
81+
**Tier**: Premium AMD, 1 vCPU, 2GB RAM ($36/mo) with NVMe storage.
9582

96-
**To connect locally**:
83+
**Connect locally** (requires your IP in Trusted Sources):
9784
```bash
98-
mysql -h db-mysql-sfo3-freehub-do-user-32369540-0.d.db.ondigitalocean.com -P 25060 -u doadmin -p --ssl-mode=REQUIRED freehub_production
85+
mysql -h db-mysql-sfo3-freehub-do-user-32369540-0.d.db.ondigitalocean.com \
86+
-P 25060 -u doadmin -p --ssl-mode=REQUIRED freehub_production
9987
```
10088

101-
---
89+
To add your IP to Trusted Sources:
90+
1. Go to **Databases** → your cluster → **Settings****Trusted Sources**
91+
2. Add your IP (find it with `curl ifconfig.me`)
10292

103-
## Deployment Workflow
93+
### SSL Certificates
10494

105-
### Overview
95+
Managed automatically by App Platform via Let's Encrypt. Certificates auto-renew before expiration.
10696

107-
- **Staging** (`freehub-staging`): Auto-deploys from `master` branch
108-
- **Production** (`freehub-production`): Manual deploy from `master` branch
97+
### Uptime Monitoring
10998

110-
### App Platform Configuration
99+
Checks that the site is accessible and emails `freehub@bikekitchen.org` if down for 2+ minutes.
111100

112-
Configure each app's deploy settings:
101+
| Resource | ID |
102+
|----------|-----|
103+
| Uptime check | `290bf29b-2886-4c2f-bedb-eef81a150606` |
104+
| Down alert | `f77f8306-b692-4a21-96e9-898618c437a2` |
113105

114-
1. **Staging**: Settings → Component → Auto-deploy: **ON**
115-
2. **Production**: Settings → Component → Auto-deploy: **OFF**
106+
```bash
107+
# View status
108+
doctl monitoring uptime get 290bf29b-2886-4c2f-bedb-eef81a150606
116109

117-
### Making Changes
110+
# List alerts
111+
doctl monitoring uptime alert list 290bf29b-2886-4c2f-bedb-eef81a150606
112+
```
118113

119-
1. **Create a feature branch** (optional for small changes):
120-
```bash
121-
git checkout -b my-feature
122-
# make changes
123-
git commit -m "Description of changes"
124-
git push origin my-feature
125-
```
114+
---
115+
116+
## Deployment
126117

127-
2. **Merge to master**:
118+
### Making Changes
119+
120+
1. **Push to master** — automatically deploys to staging
128121
```bash
129122
git checkout master
130-
git merge my-feature
123+
git commit -m "Description of changes"
131124
git push origin master
132125
```
133-
This automatically deploys to **staging**.
134126

135-
3. **Test on staging**:
136-
- Visit the staging app URL
137-
- Verify changes work correctly
127+
2. **Test on staging** — verify changes work at staging URL
138128

139-
4. **Deploy to production**:
140-
- Go to **App Platform**`freehub-production`**Actions****Deploy**
141-
- Or use CLI: `doctl apps create-deployment e1229281-8c8b-46ec-a930-9737caab742d`
129+
3. **Deploy to production**:
130+
- App Platform → `freehub-production`**Actions****Deploy**
131+
- Or: `doctl apps create-deployment e1229281-8c8b-46ec-a930-9737caab742d`
142132

143-
5. **Tag the release** (for history):
133+
4. **Tag the release**:
144134
```bash
145-
git tag v1.0.1
146-
git push origin v1.0.1
135+
git tag v2.0.1
136+
git push origin v2.0.1
147137
```
148138

149139
### Tagging Conventions
@@ -153,11 +143,34 @@ Use semantic versioning: `vMAJOR.MINOR.PATCH`
153143
- `v1.1.0` - minor: new features, backwards compatible
154144
- `v2.0.0` - major: breaking changes
155145

156-
List existing tags:
146+
### Rollback
147+
148+
In App Platform console: **Activity** → select previous deployment → **Redeploy**.
149+
150+
---
151+
152+
## Database Compatibility Notes
153+
154+
These settings were required for Rails 2.3 compatibility with MySQL 8.
155+
156+
### Legacy Password Encryption
157+
158+
The `freehub_app` user uses legacy MySQL 5.x password encryption (`mysql_native_password`) because the old `mysql` gem doesn't support MySQL 8.0's default `caching_sha2_password`.
159+
160+
To configure: **Databases** → cluster → **Users & Databases**`freehub_app`**Edit Password Encryption****Legacy - MySQL 5.x**
161+
162+
### Disabled sql_require_primary_key
163+
164+
Rails 2.3 HABTM join tables don't have primary keys, but MySQL 8 requires them by default.
165+
157166
```bash
158-
git tag -l
167+
doctl databases configuration update af845ccd-eb8d-4f0d-99b5-2c8cffc71681 \
168+
--engine mysql --config-json '{"sql_require_primary_key": false}'
159169
```
160170

161-
### Rollback
171+
**Affected tables:**
162172

163-
To rollback production to a previous version, redeploy a previous commit from the App Platform console under **Activity** → select a previous deployment → **Redeploy**.
173+
| Table | Purpose |
174+
|-------|---------|
175+
| `roles_users` | User role assignments (HABTM join table) |
176+
| `schema_migrations` | Rails migration tracking |

MIGRATION_CHECKLIST.md

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)