What this runs
Before you start
You need:
Use security-group references, not public database endpoints:
- EC2 inbound: SSH only from the operator’s current IP. Do not expose port 3000.
- RDS inbound: PostgreSQL
5432only from the EC2 security group. - Redis inbound: TLS Redis
6379only from the EC2 security group. - EC2 outbound: HTTPS plus the approved RDS and Redis destinations.
Install
1
Connect to the EC2 instance
Connect through Session Manager when available. Otherwise use the temporary,
IP-restricted SSH rule:
2
Install Docker, Git, and PostgreSQL tools
Review the Docker installation script before running it if customer policy
requires source inspection.Install the AWS RDS CA bundle for administrative
psql commands:3
Create the Better Auth database with the RDS administrator
Run this once with a temporary administrative connection. The Better Auth role
must not retain administrative membership. Replace all angle-bracket values
before running it.If the role or database already exists, inspect it instead of blindly
rerunning the creation statements.
4
Clone the approved release
Clone the public repository for the initial sanity check. If your organization
maintains an approved private mirror, set Record the exact commit and tag:Published releases are listed at
github.com/LayerNorm/overlay-web/releases.
OVERLAY_REPOSITORY_URL to that
mirror instead. The commands below default to the tested v0.1.0-rc.1
release; change OVERLAY_RELEASE only when you have approved another published
release.5
Create the runtime files
The real environment file is ignored by Git.Edit Do not reuse a generated value. Do not paste secret values into chat,
tickets, logs, screenshots, Git, or the coding agent’s final report.Database passwords containing reserved URL characters must be URL-encoded
in
deploy/ec2/.env and replace every replace_me or replace-me
value. Generate every Overlay-owned secret independently:BETTER_AUTH_DATABASE_URL. NEXT_PUBLIC_CONVEX_URL points at the
convex-backend service on the same host; INTERNAL_API_SECRET must match the
value set on the backend deployment.6
Configure Google Workspace login
In a customer-controlled Google Cloud project, configure Google Auth Platform
with an Internal audience and create a Web application OAuth client.
Register these exact values:In
deploy/ec2/.env, replace example.edu with the Workspace domain and
set BETTER_AUTH_CONNECTION_CLIENT_ID and
BETTER_AUTH_CONNECTION_CLIENT_SECRET. Keep the connection ID as
workspace so it matches the callback path.Follow Google Workspace
for the complete console flow. If Auth0 is the approved broker instead,
follow Auth0 and use connection ID
auth0. Cognito, Okta, and Keycloak use Generic OIDC.7
Validate and pull the release image
Define a short helper for the remaining commands:Continue with
OVERLAY_WEB_IMAGE must name the approved versioned release, such as
ghcr.io/layernorm/overlay-web:0.1.0-rc.1. Do not use latest for a
customer qualification run. The web and migration roles use the same immutable
image; backend uses the pinned official convex-backend image.To build inspected or customized source instead, use the build override:compose_source instead of compose for the remaining steps
when using a source build. The override builds the tested enterprise runtime,
including the web server and migration tooling.8
Start the Convex backend and run migrations once
Start the backend and wait for its Then run the Better Auth migration once:The command must exit with status
/version health check:0 and report that Better Auth migrations
are current. Do not run migrations from every web container. Deploy the Convex
functions and schema to the backend once per release with the bootstrap flow
from
Self-hosted Convex backend, which also
sets INTERNAL_API_SECRET and INTERNAL_SERVICE_AUTH_SECRET on the deployment.9
Start the web service
web to become healthy. Backend logs should show the persistence
lease held and regular function traffic without restart loops.10
Open the SSH tunnel
From the operator’s computer, open a second terminal. The tunnel must carry
both the app and the Convex client/realtime port:Keep that terminal open and visit
http://localhost:3000. The browser, IdP, and Convex
client see localhost origins while the application runs inside the customer
VPC.
Verify the sanity check
Run these commands on EC2:- A signed-out user sees one
Continue with Googleoption on a single line. - Sign-in returns to
/app/chat. /api/auth/sessionreportsauthenticated: trueandemailVerified: true.- Create a conversation and send one model request.
- Rename the conversation and refresh the page.
- Restart only the web container with
compose restart web. - Refresh again and confirm the conversation and title persist.
- Sign out and confirm the session is cleared.
- Confirm the browser network and container logs reach only the local Convex backend URL.
provider: "convex". Features disabled by
the sanity profile should not appear as usable navigation or routes.
Troubleshooting
Stop and remove the sanity host
Paste into a coding agent
Paste the following only after authenticating the agent through the customer’s approved AWS mechanism:Next: Deploy On AWS
Replace the single EC2 host with the qualified ECS, RDS, Redis, S3, Secrets
Manager, and CloudWatch architecture.