Environment Variables Configuration Guide

Rin requires two types of environment variables: Variables (plaintext) and Secrets (encrypted).

Quick Reference

TypeStoragePurposeExamples
VariablesPlaintext in wrangler.tomlConfiguration parameters, feature flagsBucket name, cache mode
SecretsEncrypted in CloudflareSensitive credentials, keysAPI keys, passwords, tokens

Variables (Plaintext)

These variables are stored in plaintext in wrangler.toml or GitHub Actions and control feature flags and basic parameters.

Site Configuration

VariableRequiredDescriptionDefault
NAMENoSite name & titleRin
DESCRIPTIONNoSite descriptionA lightweight personal blogging system
AVATARNoSite avatar URL-
PAGE_SIZENoDefault pagination size5
RSS_ENABLENoEnable RSS linkfalse
FRONTEND_URLNoCanonical site origin for sitemap.xml and robots.txt generation (recommended for multi-domain deployments)request origin
Tip

Site configuration can be modified via the Settings Page after deployment. Environment variables serve as initial defaults only.

Storage Configuration

VariableRequiredDescriptionDefaultExample
S3_FOLDERYesImage storage pathimages/images/
S3_CACHE_FOLDERNoCache file pathcache/cache/
S3_BUCKETYesS3 bucket name-my-bucket
S3_REGIONYesS3 region (use 'auto' for R2)-auto
S3_ENDPOINTYesS3 endpoint URL-https://xxx.r2.cloudflarestorage.com
S3_ACCESS_HOSTNoPublic access URLSame as S3_ENDPOINThttps://cdn.example.com
S3_FORCE_PATH_STYLENoForce path-style URLsfalsefalse

Feature Flags

VariableRequiredDescriptionDefaultRecommended
CACHE_STORAGE_MODENoCache mode: s3/databases3database
WEBHOOK_URLNoComment notification webhook--
RSS_TITLENoRSS feed titleRin Development-
RSS_DESCRIPTIONNoRSS feed descriptionDevelopment Environment-
For New Users

We recommend setting CACHE_STORAGE_MODE to database to reduce deployment complexity without additional S3 cache configuration.


Secrets (Encrypted)

These sensitive values must be configured as Cloudflare Workers Secrets, entered via CLI during deployment or set in advance.

Authentication

VariableRequiredDescriptionHow to Obtain
ADMIN_USERNAMEConditionalUsername for password loginSet yourself
ADMIN_PASSWORDConditionalPassword for password loginSet yourself
RIN_GITHUB_CLIENT_IDConditionalGitHub OAuth client IDGitHub OAuth App settings
RIN_GITHUB_CLIENT_SECRETConditionalGitHub OAuth client secretGitHub OAuth App settings
RIN_GITEE_CLIENT_IDConditionalGitee OAuth client IDGitee OAuth App settings
RIN_GITEE_CLIENT_SECRETConditionalGitee OAuth client secretGitee OAuth App settings
RIN_QQ_TOKENConditionalXinyue QQ login tokenApply at https://qq.wch666.com/
RIN_WECHAT_APPIDConditional聚合登录 WeChat App IDApply at https://login.mapay.cn/
RIN_WECHAT_APPKEYConditional聚合登录 WeChat App SecretApply at https://login.mapay.cn/
EMAIL_SEND_URLSConditionalMailPort send URLs (JSON array; a single sender may omit the array brackets — see the format notes below)Deploy MailPort and read the sender page
EMAIL_SEND_KEYSConditionalMailPort API keys (JSON array or a single string, matched with EMAIL_SEND_URLS in order)Generated on the MailPort sender page
EMAIL_RESEND_URLConditionalLegacy email relay service URL (Vercel-deployed Rin-Email project); used as fallback when EMAIL_SEND_URLS is not setDeploy Rin-Email to Vercel to get the URL
EMAIL_RESEND_PASSConditionalLegacy email relay service auth password (same as EMAIL_PASS in Vercel project)Set yourself
JWT_SECRETYesJWT signing key (any random string)Generate yourself
Email Relay Architecture

Cloudflare Workers does not support raw TCP SMTP. Email verification is handled by the MailPort sending service:

  1. Deploy MailPort, create a sender, and configure a delivery method (SMTP / HTTP API / Outlook or Gmail OAuth)
  2. Rin blog receives a verification code request and calls the endpoint from EMAIL_SEND_URLS, authenticating with Authorization: Bearer <EMAIL_SEND_KEYS>
  3. Allowed recipient domains are managed in the MailPort sender configuration

EMAIL_SEND_URLS and EMAIL_SEND_KEYS are matched one-to-one in order and polled: if the first endpoint fails, the next one is tried; an error is raised only when all of them fail.

When EMAIL_SEND_URLS is not set, Rin falls back to the legacy EMAIL_RESEND_URL / EMAIL_RESEND_PASS (Rin-Email project).

Format

EMAIL_SEND_URLS is a JSON array of send URLs; each element is a MailPort sender's full send endpoint, shaped like https://<your-domain>/api/<sender-id>/send. EMAIL_SEND_KEYS holds the matching API keys and can also be a JSON array.

With a single sender, EMAIL_SEND_KEYS may be a plain string, no array brackets needed:

EMAIL_SEND_URLS=["https://your-mailport.vercel.app/api/xxxxxx/send"]
EMAIL_SEND_KEYS=your-api-key

With multiple senders that each have their own key, the two arrays are matched by index:

EMAIL_SEND_URLS=["https://mail-a.vercel.app/api/aaaaaa/send","https://mail-b.vercel.app/api/bbbbbb/send"]
EMAIL_SEND_KEYS=["key-for-a","key-for-b"]

With multiple senders sharing one key, write a single key that is applied to every endpoint:

EMAIL_SEND_URLS=["https://mail-a.vercel.app/api/aaaaaa/send","https://mail-b.vercel.app/api/bbbbbb/send"]
EMAIL_SEND_KEYS=shared-api-key

When EMAIL_SEND_KEYS provides multiple values, the count must match EMAIL_SEND_URLS (or provide a single shared key); a mismatch fails at send time.

Captcha Image (Human Verification)

The self-service friend-link flow (apply / modify / delete via email) requires a captcha check on the applicant's first email to prevent automated abuse:

  1. The applicant sends "友链申请 / 友链修改 / 友链删除" (apply / modify / delete) to the receiving address
  2. Rin generates a captcha image (4 characters with noise lines and dots) and sends it as an inline image to the applicant
  3. The applicant replies in a new email containing only those 4 characters
  4. After the captcha passes, the normal JSON template flow continues

This relies on MailPort's inline-image support and requires no new environment variables — it reuses EMAIL_SEND_URLS + EMAIL_SEND_KEYS. The legacy Rin-Email relay has no inline-image support; if it is still in use, the captcha step is skipped automatically.

Authentication Required

You must configure at least one of the following authentication methods:

  • GitHub OAuth (RIN_GITHUB_CLIENT_ID + RIN_GITHUB_CLIENT_SECRET)
  • Gitee OAuth (RIN_GITEE_CLIENT_ID + RIN_GITEE_CLIENT_SECRET)
  • QQ Login (RIN_QQ_TOKEN)
  • WeChat Login (RIN_WECHAT_APPID + RIN_WECHAT_APPKEY)
  • Email Verification Code Login (EMAIL_SEND_URLS + EMAIL_SEND_KEYS, or the legacy EMAIL_RESEND_URL + EMAIL_RESEND_PASS)
  • Username/Password (ADMIN_USERNAME + ADMIN_PASSWORD)

Otherwise you cannot access the admin panel.

QQ Callback URL

The QQ login callback URL is fixed to https://<your-domain>/api/user/xinyueqq/callback. You must configure the same callback URL for the token in Xinyue. The path is hardcoded in the code, no env var needed.

S3 Storage Credentials

VariableRequiredDescriptionHow to Obtain
S3_ACCESS_KEY_IDConditionalS3 access key IDR2 API Token ID
S3_SECRET_ACCESS_KEYConditionalS3 secret access keyR2 API Token
Tip

When CACHE_STORAGE_MODE=database, S3 storage credentials are optional and only needed for image uploads.

Cloudflare Bindings (Not Environment Variables)

The following are Cloudflare Worker bindings configured in wrangler.toml, not environment variables:

BindingTypeDescription
DBD1 DatabaseDatabase binding
ASSETSR2 / Static AssetsStatic assets binding (optional)
AIAICloudflare AI model binding

GitHub Actions Variables

When using GitHub Actions for automated deployment, configure these in your Repository settings:

Repository Variables (Settings → Secrets and variables → Variables)

VariableRequiredDescriptionDefault
NAMENoSite nameRin
DESCRIPTIONNoSite descriptionA lightweight personal blogging system
AVATARNoSite avatar URL-
PAGE_SIZENoPagination size5
RSS_ENABLENoEnable RSSfalse
CACHE_STORAGE_MODENoCache modes3
S3_CACHE_FOLDERNoCache file pathcache/
S3_FOLDERNoImage storage pathimages/
S3_REGIONNoS3 regionauto
S3_FORCE_PATH_STYLENoForce path-stylefalse
RSS_TITLENoRSS titleRin Development
RSS_DESCRIPTIONNoRSS descriptionDevelopment Environment
WEBHOOK_URLNoComment notification webhook-
REPO_WORKER_NAMENoWorker namerin-server
REPO_DB_NAMENoD1 database namerin
R2_BUCKET_NAMENoR2 bucket name-
EMAIL_SEND_URLSConditionalMailPort send URLs (JSON array)-

Repository Secrets (Settings → Secrets and variables → Secrets)

VariableRequiredDescription
CLOUDFLARE_API_TOKENYesCloudflare API token
CLOUDFLARE_ACCOUNT_IDYesCloudflare account ID
S3_ENDPOINTConditionalS3/R2 endpoint URL
S3_ACCESS_HOSTConditionalS3/R2 access domain
S3_BUCKETConditionalS3 bucket name
S3_ACCESS_KEY_IDConditionalS3 access key ID
S3_SECRET_ACCESS_KEYConditionalS3 secret access key
JWT_SECRETYesJWT signing key
RIN_GITHUB_CLIENT_IDConditionalGitHub OAuth ID
RIN_GITHUB_CLIENT_SECRETConditionalGitHub OAuth Secret
RIN_GITEE_CLIENT_IDConditionalGitee OAuth ID
RIN_GITEE_CLIENT_SECRETConditionalGitee OAuth Secret
RIN_QQ_TOKENConditionalXinyue QQ login token
ADMIN_USERNAMEConditionalAdmin username
ADMIN_PASSWORDConditionalAdmin password
EMAIL_SEND_KEYSConditionalMailPort API keys (matched with EMAIL_SEND_URLS in order)

Local Development Environment

For local development, use .env file (see .env.example):

# Site Configuration
NAME="My Blog"
DESCRIPTION="A personal blog"
AVATAR=https://example.com/avatar.png
PAGE_SIZE=5
RSS_ENABLE=false

# S3 Storage (R2 or MinIO)
S3_FOLDER=images/
S3_CACHE_FOLDER=cache/
S3_BUCKET=my-bucket
S3_REGION=auto
S3_ENDPOINT=https://xxx.r2.cloudflarestorage.com
S3_ACCESS_HOST=https://cdn.example.com
S3_FORCE_PATH_STYLE=false

# Cache Mode
CACHE_STORAGE_MODE=database

# Webhook
WEBHOOK_URL=

# RSS
RSS_TITLE=My Blog
RSS_DESCRIPTION=My Personal Blog

# Authentication (configure at least one)

# Option 1: GitHub OAuth
RIN_GITHUB_CLIENT_ID=xxx
RIN_GITHUB_CLIENT_SECRET=xxx

# Option 2: Gitee OAuth
RIN_GITEE_CLIENT_ID=xxx
RIN_GITEE_CLIENT_SECRET=xxx

# Option 3: Xinyue QQ Login
RIN_QQ_TOKEN=xxx

# Option 4: 聚合登录 WeChat
RIN_WECHAT_APPID=xxx
RIN_WECHAT_APPKEY=xxx

# Option 5: Email Verification Code Login
# After deploying MailPort (https://github.com/wool-hmq/mailport), configure these variables:
# - MailPort project: create a sender, configure the delivery method and allowed domains, generate an API key
# - Rin blog env vars: EMAIL_SEND_URLS is a JSON array of send URLs, EMAIL_SEND_KEYS holds the matching keys
#   Single sender (the key may be a plain string):
EMAIL_SEND_URLS=["https://your-mailport.vercel.app/api/xxxxxx/send"]
EMAIL_SEND_KEYS=your-mailport-api-key
#   Multiple senders (keys matched by index, or one shared key):
# EMAIL_SEND_URLS=["https://mail-a.vercel.app/api/aaaaaa/send","https://mail-b.vercel.app/api/bbbbbb/send"]
# EMAIL_SEND_KEYS=["key-for-a","key-for-b"]
# Legacy fallback (used only when the two variables above are not set; requires deploying Rin-Email to Vercel):
EMAIL_RESEND_URL=https://your-rin-email.vercel.app/api/send
EMAIL_RESEND_PASS=your-email-pass

# Option 6: Username/Password Login
ADMIN_USERNAME=admin
ADMIN_PASSWORD=secure_password

# JWT Secret (required)
JWT_SECRET=random_secret_key

# S3 Credentials (required if using S3 storage)
S3_ACCESS_KEY_ID=xxx
S3_SECRET_ACCESS_KEY=xxx

Minimal Deployment Checklist

Username/Password Login Only (Minimal Config)

VariableTypeRequired
JWT_SECRETSecretYes
ADMIN_USERNAMESecretYes
ADMIN_PASSWORDSecretYes
S3_FOLDERVariableYes
S3_BUCKETVariableYes
S3_REGIONVariableYes
S3_ENDPOINTVariableYes
S3_ACCESS_KEY_IDSecretConditional
S3_SECRET_ACCESS_KEYSecretConditional

Full Configuration (All Features)

Includes site config, all OAuth providers, email login, S3 storage, webhook, and RSS.


FAQ

Q: Do I need S3 config when using CACHE_STORAGE_MODE=database?

No. database mode stores cache in D1 database without S3/R2. However, S3 config is still required if you need image uploads.

Q: Can I enable multiple login methods simultaneously?

Yes. Configure credentials for multiple methods and the frontend will display corresponding login buttons automatically.

Q: How to set up email verification code login?

Email verification is handled by the MailPort sending service:

  1. Deploy MailPort, create a sender, and configure a delivery method (SMTP / HTTP API / Outlook or Gmail OAuth)
  2. Generate an API key on the MailPort sender page, and configure allowed recipient domains as needed
  3. In your Cloudflare Worker, configure:
    • EMAIL_SEND_URLS = the full send endpoint(s) of your MailPort sender (JSON array, multiple allowed)
    • EMAIL_SEND_KEYS = the matching API key(s), paired with the endpoints in order

EMAIL_SEND_URLS and EMAIL_SEND_KEYS are polled in order: if the first endpoint fails, the next one is tried; an error is raised only when all of them fail. When these two variables are not set, Rin falls back to the legacy EMAIL_RESEND_URL / EMAIL_RESEND_PASS (Rin-Email).

Q: What JSON format do EMAIL_SEND_URLS and EMAIL_SEND_KEYS use?

EMAIL_SEND_URLS is a JSON array of send URLs, each shaped like https://<your-domain>/api/<sender-id>/send. EMAIL_SEND_KEYS holds the keys matched with them in order.

With a single sender, the key may be a plain string:

EMAIL_SEND_URLS=["https://your-mailport.vercel.app/api/xxxxxx/send"]
EMAIL_SEND_KEYS=your-api-key

With multiple senders that each have their own key, the arrays are matched by index:

EMAIL_SEND_URLS=["https://mail-a.vercel.app/api/aaaaaa/send","https://mail-b.vercel.app/api/bbbbbb/send"]
EMAIL_SEND_KEYS=["key-for-a","key-for-b"]

With multiple senders sharing one key, write a single key:

EMAIL_SEND_URLS=["https://mail-a.vercel.app/api/aaaaaa/send","https://mail-b.vercel.app/api/bbbbbb/send"]
EMAIL_SEND_KEYS=shared-api-key

The number of keys must match the number of URLs, or provide a single shared key; a mismatch fails at send time.

Q: How to restrict allowed email domains?

Add the allowed domains to the "allowed recipient domains" list in your MailPort sender configuration. Only recipients on those domains will be delivered to.

Leave the list empty to allow all domains.

Q: Which delivery methods does MailPort support?

MailPort supports the following delivery methods:

  • SMTP: any SMTP provider (163 Mail, QQ Mail, Gmail, etc.)
  • HTTP API: forward to a custom HTTP endpoint
  • Outlook OAuth2 / Gmail OAuth2: send without app passwords

See the MailPort project documentation.