Productionize palinks: systemd service + production Rails config #1

Closed
opened 2026-05-19 12:24:49 +00:00 by ldraney · 0 comments
Owner

Type

Feature

Lineage

Standalone — follow-up from initial deployment session. Site is live at https://palinks.tail5b443a.ts.net but runs as a manual rails server -d in development mode. No crash recovery, no boot persistence.

Repo

ldraney/palinks

User Story

As Lucas
I want palinks to survive reboots and crashes without manual intervention
So that my link dashboard is always available

Context

palinks is deployed as a reverse proxy tunnel: nginx in k8s (pal-e-deployments/overlays/palinks/) proxies to the local Puma server on 100.110.151.59:3921 via Tailscale. Currently running in development mode with bin/rails server -d. If Puma crashes or the machine reboots, the site goes dark.

The database is already production-ready — CNPG cluster with palinks database created, daily backups to MinIO, WAL archiving. The database.yml production config points to pal-e-postgres-rw.postgres.svc.cluster.local, but for the reverse-proxy model the app connects to the same local Postgres (the CNPG cluster connection only works from inside k8s).

File Targets

Files to create:

  • palinks.service — systemd unit file for Puma (auto-start, restart on crash)

Files to modify:

  • config/environments/production.rb — production config (assume_ssl, allowed hosts, log level)
  • config/database.yml — ensure local production database config works (local Postgres, not CNPG for the tunnel model)
  • config/puma.rb — production worker/thread tuning if needed

Steps outside the repo:

  • Create palinks production database on local Postgres
  • Set RAILS_MASTER_KEY or generate production credentials
  • RAILS_ENV=production bin/rails db:migrate
  • RAILS_ENV=production bin/rails assets:precompile
  • Install and enable the systemd unit: systemctl --user enable --now palinks

Acceptance Criteria

  • systemctl --user status palinks shows active/running
  • After systemctl --user stop palinks && systemctl --user start palinks, site recovers within 10s
  • After kill -9 $(pgrep -f palinks), systemd restarts Puma automatically
  • After machine reboot, palinks starts without manual intervention
  • https://palinks.tail5b443a.ts.net serves the dashboard in production mode
  • CSRF/form submission works through the funnel (assume_ssl)
  • Links persist across restarts (database survives)

Test Expectations

  • Manual: kill Puma PID, verify systemd restarts it
  • Manual: reboot machine, verify site comes back
  • Manual: submit a new link through the funnel URL, verify it saves
  • Run: curl -s -o /dev/null -w "%{http_code}" https://palinks.tail5b443a.ts.net → 200

Constraints

  • Use systemctl --user (user-level unit), not root — matches the dev workflow
  • Must enable lingering (loginctl enable-linger ldraney) so user services run without a login session
  • Production mode needs SECRET_KEY_BASE — either via rails credentials:edit or env var
  • Keep assume_ssl = true in production config (funnel terminates TLS)
  • Local Postgres for both dev and production (CNPG is for future containerized deployment)

Checklist

  • systemd unit created and tested
  • Production Rails config complete
  • Production database migrated
  • Assets precompiled
  • Lingering enabled
  • README updated with production setup instructions
  • PR opened
  • Verified on https://palinks.tail5b443a.ts.net
  • ldraney/pal-e-deployments — overlay at overlays/palinks/ (nginx reverse proxy)
### Type Feature ### Lineage Standalone — follow-up from initial deployment session. Site is live at https://palinks.tail5b443a.ts.net but runs as a manual `rails server -d` in development mode. No crash recovery, no boot persistence. ### Repo `ldraney/palinks` ### User Story As Lucas I want palinks to survive reboots and crashes without manual intervention So that my link dashboard is always available ### Context palinks is deployed as a reverse proxy tunnel: nginx in k8s (`pal-e-deployments/overlays/palinks/`) proxies to the local Puma server on `100.110.151.59:3921` via Tailscale. Currently running in development mode with `bin/rails server -d`. If Puma crashes or the machine reboots, the site goes dark. The database is already production-ready — CNPG cluster with `palinks` database created, daily backups to MinIO, WAL archiving. The `database.yml` production config points to `pal-e-postgres-rw.postgres.svc.cluster.local`, but for the reverse-proxy model the app connects to the same local Postgres (the CNPG cluster connection only works from inside k8s). ### File Targets Files to create: - `palinks.service` — systemd unit file for Puma (auto-start, restart on crash) Files to modify: - `config/environments/production.rb` — production config (assume_ssl, allowed hosts, log level) - `config/database.yml` — ensure local production database config works (local Postgres, not CNPG for the tunnel model) - `config/puma.rb` — production worker/thread tuning if needed Steps outside the repo: - Create `palinks` production database on local Postgres - Set `RAILS_MASTER_KEY` or generate production credentials - `RAILS_ENV=production bin/rails db:migrate` - `RAILS_ENV=production bin/rails assets:precompile` - Install and enable the systemd unit: `systemctl --user enable --now palinks` ### Acceptance Criteria - [ ] `systemctl --user status palinks` shows active/running - [ ] After `systemctl --user stop palinks && systemctl --user start palinks`, site recovers within 10s - [ ] After `kill -9 $(pgrep -f palinks)`, systemd restarts Puma automatically - [ ] After machine reboot, palinks starts without manual intervention - [ ] https://palinks.tail5b443a.ts.net serves the dashboard in production mode - [ ] CSRF/form submission works through the funnel (assume_ssl) - [ ] Links persist across restarts (database survives) ### Test Expectations - [ ] Manual: kill Puma PID, verify systemd restarts it - [ ] Manual: reboot machine, verify site comes back - [ ] Manual: submit a new link through the funnel URL, verify it saves - Run: `curl -s -o /dev/null -w "%{http_code}" https://palinks.tail5b443a.ts.net` → 200 ### Constraints - Use `systemctl --user` (user-level unit), not root — matches the dev workflow - Must enable lingering (`loginctl enable-linger ldraney`) so user services run without a login session - Production mode needs `SECRET_KEY_BASE` — either via `rails credentials:edit` or env var - Keep `assume_ssl = true` in production config (funnel terminates TLS) - Local Postgres for both dev and production (CNPG is for future containerized deployment) ### Checklist - [ ] systemd unit created and tested - [ ] Production Rails config complete - [ ] Production database migrated - [ ] Assets precompiled - [ ] Lingering enabled - [ ] README updated with production setup instructions - [ ] PR opened - [ ] Verified on https://palinks.tail5b443a.ts.net ### Related - `ldraney/pal-e-deployments` — overlay at `overlays/palinks/` (nginx reverse proxy)
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/palinks#1
No description provided.