From d5fc917ac012122312f5bb03614bb2e8735f3d00 Mon Sep 17 00:00:00 2001 From: Rajat Saxena Date: Mon, 19 Oct 2026 23:10:23 +0530 Subject: [PATCH] docs: upgrade guide for v0.6.0 hashed API keys Moves the release-specific API key notes out of the self-hosting guide into an Upgrades page with backup, orphaned-media check and verification steps. Also fixes the count example, which is a POST. --- apps/docs/content/docs/api-keys.mdx | 2 +- apps/docs/content/docs/meta.json | 3 +- apps/docs/content/docs/self-hosting.mdx | 9 +- .../docs/upgrade-from-v0-5-x-to-v0-6-0.mdx | 85 +++++++++++++++++++ 4 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 apps/docs/content/docs/upgrade-from-v0-5-x-to-v0-6-0.mdx diff --git a/apps/docs/content/docs/api-keys.mdx b/apps/docs/content/docs/api-keys.mdx index 6596c8bb..245b6d5c 100644 --- a/apps/docs/content/docs/api-keys.mdx +++ b/apps/docs/content/docs/api-keys.mdx @@ -25,7 +25,7 @@ An app can have up to 10 keys. Send the key in the `x-medialit-apikey` header: ```sh -curl https://api.medialit.cloud/media/get/count \ +curl -X POST https://api.medialit.cloud/media/get/count \ -H "x-medialit-apikey: $MEDIALIT_API_KEY" ``` diff --git a/apps/docs/content/docs/meta.json b/apps/docs/content/docs/meta.json index bd6e90b6..733fd4d8 100644 --- a/apps/docs/content/docs/meta.json +++ b/apps/docs/content/docs/meta.json @@ -25,6 +25,7 @@ "---Resources---", "faqs", "---Upgrades---", - "upgrade-from-v0-4-0-to-v0-5-0" + "upgrade-from-v0-4-0-to-v0-5-0", + "upgrade-from-v0-5-x-to-v0-6-0" ] } diff --git a/apps/docs/content/docs/self-hosting.mdx b/apps/docs/content/docs/self-hosting.mdx index 1dd45ef9..9ad3b708 100644 --- a/apps/docs/content/docs/self-hosting.mdx +++ b/apps/docs/content/docs/self-hosting.mdx @@ -349,14 +349,9 @@ If your server reaches MediaLit on a different URL than browsers do, for example Back up the database before upgrading. Migrations can't be rolled back, and the hashed API keys migration removes plaintext keys for good. -### Upgrading to hashed API keys +### Upgrading from v0.5.x to v0.6.0 -This release stores API keys as hashes and lets an app have several keys. - -- Existing keys keep working. They can no longer be shown in the dashboard, so make sure you have them saved. -- Send keys in the `x-medialit-apikey` header. A key in the request body is no longer accepted. -- Requests from a deactivated account now get `403 account_inactive`. -- If the migration finds media whose key matches no app, it stops and changes nothing. Fix or delete those rows, then upgrade again. +v0.6.0 stores API keys as hashes. Follow the [upgrade guide](/upgrade-from-v0-5-x-to-v0-6-0) before you upgrade, because it needs a backup and a check for media that belongs to no app. ## Monitor your server diff --git a/apps/docs/content/docs/upgrade-from-v0-5-x-to-v0-6-0.mdx b/apps/docs/content/docs/upgrade-from-v0-5-x-to-v0-6-0.mdx new file mode 100644 index 00000000..d365cef2 --- /dev/null +++ b/apps/docs/content/docs/upgrade-from-v0-5-x-to-v0-6-0.mdx @@ -0,0 +1,85 @@ +--- +title: Upgrade from v0.5.x to v0.6.0 +description: Move a self-hosted MediaLit installation to hashed, revocable API keys +--- + +MediaLit v0.6.0 stores [API keys](/api-keys) as hashes instead of plaintext, and lets an app have several keys that you can create and revoke separately. Upgrading needs a database migration. It keeps your files, apps and existing keys working, but it can't be undone. + + + The migration removes every plaintext key for good. The only way back to v0.5.x is to restore a backup. + + +## What changes + +- **Existing keys keep working.** Each one becomes a "Default key" on its app, stored as a hash. The dashboard can no longer show the key, so make sure you have yours saved. +- **Keys go in the `x-medialit-apikey` header.** MediaLit no longer accepts a key in the request body. If your code sends it any other way, update it before you upgrade. The [Node.js SDK](/node-sdk) already uses the header. +- **An app can have up to 10 keys.** Create them under **Settings** > **API keys** in the dashboard. See [rotating a key](/api-keys#rotate-a-key). +- **Deactivated accounts get `403 account_inactive`** instead of a generic error. +- **Other services in your Compose file can get a key at startup.** See [create a key at startup](/self-hosting#create-a-key-at-startup). + +## 1. Back up the database + +With the bundled PostgreSQL service: + +```sh +docker compose exec -T postgres pg_dump -U medialit medialit > medialit-before-0.6.0.sql +``` + +If you manage PostgreSQL yourself, take a backup the way you normally do. Your files in S3 aren't touched by this upgrade. + +## 2. Look for media that belongs to no app + +The migration moves each file and setting from its plaintext key to the app that owns the key. If a row's key matches no app, the migration stops and changes nothing, because a person should decide what happens to that media. Old installations often have a few, for example from apps deleted before MediaLit linked them. + +Find them on the v0.5.x database: + +```sql +SELECT left(m.apikey, 6) AS key_start, count(*) AS files +FROM media m +WHERE NOT EXISTS (SELECT 1 FROM api_keys a WHERE a.key = m.apikey) +GROUP BY m.apikey +ORDER BY files DESC; + +SELECT left(s.apikey, 6) AS key_start +FROM media_settings s +WHERE NOT EXISTS (SELECT 1 FROM api_keys a WHERE a.key = s.apikey); +``` + +Run them with: + +```sh +docker compose exec postgres psql -U medialit medialit +``` + +If both return nothing, go to step 3. Otherwise, decide for each key whether the media matters. If it does, find the app it belongs to and fix the key in the `media` table. If it doesn't, delete the rows: + +```sql +DELETE FROM media m +WHERE NOT EXISTS (SELECT 1 FROM api_keys a WHERE a.key = m.apikey); + +DELETE FROM media_settings s +WHERE NOT EXISTS (SELECT 1 FROM api_keys a WHERE a.key = s.apikey); +``` + + + Deleting rows doesn't delete the files in your bucket. Remove them there too if you want the space back. + + +Upload signatures and resumable-upload records with an unknown key are deleted by the migration itself. They expire within days anyway. + +## 3. Upgrade + +```sh +docker compose pull +docker compose up -d +``` + +The `init` service runs the migration before the API starts. If it stops on orphaned media, `docker compose logs init` shows how many rows and which table. Fix them as in step 2 and run `docker compose up -d` again. The migration runs in one transaction, so a failed attempt leaves the database as it was. + +If you run the image without Docker Compose, run `bun apps/api/src/db/migrate.ts` with the new image before starting the API. + +## 4. Check it worked + +1. Call the API with one of your existing keys, for example `curl -X POST https://medialit.example.com/media/get/count -H "x-medialit-apikey: $MEDIALIT_API_KEY"`. It should return a count. +2. Sign in to the dashboard, open an app and check **Settings** > **API keys**. You should see a **Default key** showing only its first four characters. +3. Create a new key and use it in place of the old one when convenient. New keys are longer, and secret scanners recognize their `ml_live_` prefix.