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.exampleto.env. - Install
opensslor 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
emailDeliveryobject withproviderand astatusofsent,failed, ormanual. - A configured transport that cannot send — a missing
RESEND_API_KEY, a missingSMTP_HOST, a refused connection, an error response, or a timeout — reportsfailed, nevermanual, 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#
- Validate the environment through the repository configuration check.
- Start the stack and run migrations.
- Confirm
/api/readyzreports all dependencies healthy. - Sign in through HTTPS and reload the page to verify the secure refresh cookie returns a valid session.
- Upload a small document and wait for it to reach ready state.
- When
EMAIL_PROVIDERis notmanual, invite one real mailbox and confirm the delivery status issent. 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. |
Related#
- Deploy — apply the environment to the stack.
- Administration — provider and user configuration.
- Agent run API — the run contract the worker executes.