PacketChatDocs

Configure PacketChat#

PacketChat reads deployment settings from .env. Generate fresh secrets for every installation and keep the file outside source control.

Before you start#

  • Copy .env.example to .env.
  • Install openssl or another cryptographically secure random generator.
  • Choose the public HTTPS URL and storage endpoints.
  • Decide whether invitation and password-reset links are delivered by hand, through an SMTP relay, or through Resend.

Generate required secrets#

Generate each value independently:

openssl rand -hex 16
openssl rand -hex 32
openssl rand -base64 32

Assign the outputs, in order, to BOOTSTRAP_TOKEN, JWT_SECRET, and ENCRYPTION_KEY_BASE64. The encryption value must decode to exactly 32 bytes. Changing it later makes existing stored provider credentials unreadable, so back it up in the deployment secret store.

Set APP_ENV=production, use an HTTPS APP_BASE_URL, and set COOKIE_SECURE=true for an internet-facing installation. Production startup rejects known development values.

Configure dependencies#

Set the PostgreSQL, Redis, and S3-compatible object-storage connection values in .env. Create and retain all configured buckets. The provided Compose stack initialises them automatically; external object storage must be prepared before readiness can succeed.

Review MAX_UPLOAD_BYTES and WORKER_CONCURRENCY together. Document ingestion can be memory intensive, so raise concurrency only after measuring the worker.

An optional setting that is absent from .env takes its documented default. EMAIL_SEND_TIMEOUT_MS and SMTP_PORT also take their default when the key is present but blank. Every other numeric setting rejects a blank value at startup, so remove the line rather than emptying it.

These settings have no default and must be supplied: DATABASE_URL, REDIS_URL, S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET_UPLOADS, S3_BUCKET_EXPORTS, S3_BUCKET_ARTIFACTS, and the three generated secrets above. The remaining object-storage settings do have defaults — S3_REGION is us-east-1 and S3_FORCE_PATH_STYLE is true, which suits MinIO — so set them only when your object store needs different values.

Configure the proxy#

Set APP_TRUSTED_PROXY=true only when the web container can be reached solely through a trusted reverse proxy. Forward the original HTTPS scheme and client address. Leaving the container directly reachable while trusting forwarded headers lets callers supply their own address information.

Configure account lifetimes#

The main session settings are:

Setting Default Purpose
ACCESS_TOKEN_TTL_SECONDS 600 Access-token lifetime
REFRESH_TOKEN_TTL_SECONDS 1,209,600 Maximum refresh session lifetime
SESSION_IDLE_TIMEOUT_SECONDS 86,400 Inactivity limit
PASSWORD_RESET_TOKEN_TTL_SECONDS 3,600 Password-reset link lifetime
INVITE_TOKEN_TTL_SECONDS 604,800 Invitation link lifetime

Configure email#

Invitation links and administrator-triggered password-reset links are the only mail PacketChat sends. There are no notification, digest, or run-completion emails.

EMAIL_PROVIDER selects the transport:

Value Behaviour Also required
manual (default) Nothing is sent. The link is returned to the administrator in Admin → Users for delivery by hand.
smtp Sends through an SMTP relay. SMTP_HOST, plus SMTP_USER and SMTP_PASSWORD when the relay authenticates
resend Posts the message to the Resend API. RESEND_API_KEY

Settings shared by both sending transports:

Setting Default Purpose
EMAIL_FROM PacketChat <noreply@example.com> Sender address; use one the relay or Resend domain is allowed to send as
EMAIL_SEND_TIMEOUT_MS 10000 Bound on each send, so a relay that accepts the connection and stops answering fails the send instead of holding the administrator request open

SMTP settings:

Setting Default Purpose
SMTP_PORT 587 Relay port
SMTP_SECURE false true opens the connection in TLS, which port 465 expects; false connects in the clear and upgrades with STARTTLS when the relay offers it
SMTP_REJECT_UNAUTHORIZED true Set to false only for an internal relay with a self-signed certificate; it turns the certificate check off rather than pinning a certificate

The link inside the message is built from APP_BASE_URL, so a wrong base URL sends mail pointing at the wrong host.

When a send fails#

The invitation or reset record is committed before the send, and the link is returned to the administrator either way. A dead relay costs a copy and paste, not the invitation.

  • The API response and the audit record both carry an emailDelivery object with provider and a status of sent, failed, or manual.
  • A configured transport that cannot send — a missing RESEND_API_KEY, a missing SMTP_HOST, a refused connection, an error response, or a timeout — reports failed, never manual, so a broken relay cannot be mistaken for a deliberate hand-delivery deployment.
  • Admin → Users reports the failure and its reason and keeps the link on screen. The reason has the SMTP password, the Resend key, and the link itself removed before it reaches the screen or the audit record.
  • There is no retry and no queue for these messages. Re-issue the invitation or the password reset to try again.

Verify#

  1. Validate the environment through the repository configuration check.
  2. Start the stack and run migrations.
  3. Confirm /api/readyz reports all dependencies healthy.
  4. Sign in through HTTPS and reload the page to verify the secure refresh cookie returns a valid session.
  5. Upload a small document and wait for it to reach ready state.
  6. When EMAIL_PROVIDER is not manual, invite one real mailbox and confirm the delivery status is sent. A failed send still returns the link, so nothing else signals a broken relay.

If it does not work#

Symptom Check
Startup rejects a secret Generate a new value rather than modifying a development example.
Provider keys fail after a configuration change Restore the original encryption key and rotate accounts through the UI.
Login works locally but loops through HTTPS Use the literal true for COOKIE_SECURE and confirm the public base URL.
Readiness fails on storage Confirm credentials, endpoint, region, and all buckets.
Startup rejects a numeric setting Remove the blank line from .env instead of leaving the key set to an empty value.
Invitation reports failed delivery Confirm the transport settings for the selected EMAIL_PROVIDER, then re-issue the invitation; the returned link stays valid meanwhile.
Mail arrives with links to the wrong host Correct APP_BASE_URL and re-issue; the link is built from it at send time.