diff --git a/README.md b/README.md
index 939da3290..685e0c281 100644
--- a/README.md
+++ b/README.md
@@ -82,7 +82,8 @@ the [past releases changelog](docs/changelog.md).


-Clone this repo, install the dependencies, and run the development server:
+Clone this repo, install the dependencies (all locally), and run the development server (which auto-watches the
+files for changes):
```bash
git clone https://github.com/enricoros/big-agi.git
@@ -91,15 +92,21 @@ npm install
npm run dev
```
-The app will be running on `http://localhost:3000`
+The development app will be running on `http://localhost:3000`. Development builds have the advantage of not requiring
+a build step, but can be slower than production builds. Also, development builds won't have timeout on edge functions.
-Integrations:
+## 🌐 Deploy manually
-* Local models: Ollama, Oobabooga, LocalAi, etc.
-* [ElevenLabs](https://elevenlabs.io/) Voice Synthesis (bring your own voice too) - Settings > Text To Speech
-* [Helicone](https://www.helicone.ai/) LLM Observability Platform - Models > OpenAI > Advanced > API Host: 'oai.hconeai.com'
-* [Paste.gg](https://paste.gg/) Paste Sharing - Chat Menu > Share via paste.gg
-* [Prodia](https://prodia.com/) Image Generation - Settings > Image Generation > Api Key & Model
+The _production_ build of the application is optimized for performance and is performed by the `npm run build` command,
+after installing the required dependencies.
+
+```bash
+# .. repeat the steps above up to `npm install`, then:
+npm run build
+npm run start --port 3000
+```
+
+The app will be running on the specified port, e.g. `http://localhost:3000`
## 🐳 Deploy with Docker
@@ -115,7 +122,7 @@ docker run -d -p 3000:3000 big-agi
Or run the official container:
- manually: `docker run -d -p 3000:3000 ghcr.io/enricoros/big-agi`
-- or, with docker-compose: `docker-compose up`
+- or, with docker-compose: `docker-compose up` or see [the documentation](docs/deploy-docker.md) for a composer file with integrated browsing
## ☁️ Deploy on Cloudflare Pages
@@ -127,7 +134,13 @@ Create your GitHub fork, create a Vercel project over that fork, and deploy it.
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fenricoros%2Fbig-agi&env=OPENAI_API_KEY,OPENAI_API_HOST&envDescription=OpenAI%20KEY%20for%20your%20deployment.%20Set%20HOST%20only%20if%20non-default.)
+## Integrations:
+* Local models: Ollama, Oobabooga, LocalAi, etc.
+* [ElevenLabs](https://elevenlabs.io/) Voice Synthesis (bring your own voice too) - Settings > Text To Speech
+* [Helicone](https://www.helicone.ai/) LLM Observability Platform - Models > OpenAI > Advanced > API Host: 'oai.hconeai.com'
+* [Paste.gg](https://paste.gg/) Paste Sharing - Chat Menu > Share via paste.gg
+* [Prodia](https://prodia.com/) Image Generation - Settings > Image Generation > Api Key & Model
diff --git a/docs/deploy-authentication.md b/docs/deploy-authentication.md
new file mode 100644
index 000000000..f4a5f9d4b
--- /dev/null
+++ b/docs/deploy-authentication.md
@@ -0,0 +1,39 @@
+# Authentication
+
+`big-AGI` does not come with built-in authentication. To secure your deployment, you can implement authentication
+in one of the following ways:
+
+1. Rebuild `big-AGI` with support for [HTTP Basic Authentication](#http-authentication)
+2. Utilize user authentication features provided by your [cloud deployment platform](#cloud-deployments-authentication)
+3. Develop a custom authentication solution
+
+## HTTP Authentication
+
+[HTTP Basic Authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication) is a simple method
+to secure your application. To enable it in `big-AGI`, you **must manually build the application**:
+
+- Build `big-AGI` with HTTP authentication enabled:
+ - Clone the repository
+ - Rename `middleware_BASIC_AUTH.ts` to `middleware_BASIC_AUTH.ts`
+ - Build: follow the build instructions in [Deploy manually](../README.md#-deploy-manually) or [Deploying with Docker](deploy-docker.md)
+
+- Configure the following [environment variables](environment-variables.md) before launching `big-AGI`:
+```dotenv
+HTTP_BASIC_AUTH_USERNAME=
+HTTP_BASIC_AUTH_PASSWORD=
+```
+
+- Start the application
+
+## Cloud Deployments Authentication
+
+> This approach allows you to enable authentication without rebuilding the application by using the features
+> provided by your cloud platform to manage user accounts and access.
+
+Many cloud deployment platforms offer built-in authentication mechanisms. Refer to the platform's documentation
+for setup instructions:
+
+1. [CloudFlare Access / Zero Trust](https://www.cloudflare.com/zero-trust/products/access/)
+2. [Vercel Authentication](https://vercel.com/docs/security/deployment-protection/methods-to-protect-deployments/vercel-authentication)
+3. [Vercel Password Protection](https://vercel.com/docs/security/deployment-protection/methods-to-protect-deployments/password-protection)
+4. Let us know when you test more solutions (Heroku, AWS IAM, Google IAP, etc.)
diff --git a/docs/environment-variables.md b/docs/environment-variables.md
index 785a96e1b..1272e5724 100644
--- a/docs/environment-variables.md
+++ b/docs/environment-variables.md
@@ -44,6 +44,10 @@ PUPPETEER_WSS_ENDPOINT=
# Backend Analytics
BACKEND_ANALYTICS=
+
+# Backend HTTP Basic Authentication
+HTTP_BASIC_AUTH_USERNAME=
+HTTP_BASIC_AUTH_PASSWORD=
```
## Variables Documentation
@@ -94,21 +98,23 @@ It is currently supported for:
Enable the app to Talk, Draw, and Google things up.
-| Variable | Description |
-|:-------------------------|:------------------------------------------------------------------------------------------------------------------------|
-| **Text-To-Speech** | [ElevenLabs](https://elevenlabs.io/) is a high quality speech synthesis service |
-| `ELEVENLABS_API_KEY` | ElevenLabs API Key - used for calls, etc. |
-| `ELEVENLABS_API_HOST` | Custom host for ElevenLabs |
-| `ELEVENLABS_VOICE_ID` | Default voice ID for ElevenLabs |
-| **Google Custom Search** | [Google Programmable Search Engine](https://programmablesearchengine.google.com/about/) produces links to pages |
-| `GOOGLE_CLOUD_API_KEY` | Google Cloud API Key, used with the '/react' command - [Link to GCP](https://console.cloud.google.com/apis/credentials) |
-| `GOOGLE_CSE_ID` | Google Custom/Programmable Search Engine ID - [Link to PSE](https://programmablesearchengine.google.com/) |
-| **Text-To-Image** | [Prodia](https://prodia.com/) is a reliable image generation service |
-| `PRODIA_API_KEY` | Prodia API Key - used with '/imagine ...' |
-| **Browse** | |
-| `PUPPETEER_WSS_ENDPOINT` | Puppeteer WebSocket endpoint - used for browsing, etc. |
-| **Backend** | |
-| `BACKEND_ANALYTICS` | Semicolon-separated list of analytics flags (see backend.analytics.ts). Flags: `domain` logs the responding domain. |
+| Variable | Description |
+|:---------------------------|:------------------------------------------------------------------------------------------------------------------------|
+| **Text-To-Speech** | [ElevenLabs](https://elevenlabs.io/) is a high quality speech synthesis service |
+| `ELEVENLABS_API_KEY` | ElevenLabs API Key - used for calls, etc. |
+| `ELEVENLABS_API_HOST` | Custom host for ElevenLabs |
+| `ELEVENLABS_VOICE_ID` | Default voice ID for ElevenLabs |
+| **Google Custom Search** | [Google Programmable Search Engine](https://programmablesearchengine.google.com/about/) produces links to pages |
+| `GOOGLE_CLOUD_API_KEY` | Google Cloud API Key, used with the '/react' command - [Link to GCP](https://console.cloud.google.com/apis/credentials) |
+| `GOOGLE_CSE_ID` | Google Custom/Programmable Search Engine ID - [Link to PSE](https://programmablesearchengine.google.com/) |
+| **Text-To-Image** | [Prodia](https://prodia.com/) is a reliable image generation service |
+| `PRODIA_API_KEY` | Prodia API Key - used with '/imagine ...' |
+| **Browse** | |
+| `PUPPETEER_WSS_ENDPOINT` | Puppeteer WebSocket endpoint - used for browsing, etc. |
+| **Backend** | |
+| `BACKEND_ANALYTICS` | Semicolon-separated list of analytics flags (see backend.analytics.ts). Flags: `domain` logs the responding domain. |
+| `HTTP_BASIC_AUTH_USERNAME` | Username for HTTP Basic Authentication. See the [Authentication](deploy-authentication.md) guide. |
+| `HTTP_BASIC_AUTH_PASSWORD` | Password for HTTP Basic Authentication. |
---
diff --git a/middleware_BASIC_AUTH.ts b/middleware_BASIC_AUTH.ts
new file mode 100644
index 000000000..1bb820a14
--- /dev/null
+++ b/middleware_BASIC_AUTH.ts
@@ -0,0 +1,55 @@
+import type { NextRequest } from 'next/server';
+import { NextResponse } from 'next/server';
+
+
+// noinspection JSUnusedGlobalSymbols
+/**
+ * Middleware to protect with HTTP Basic Authentication.
+ */
+export function middleware(request: NextRequest) {
+
+ // Validate http basic auth configuration
+ if (!process.env.HTTP_BASIC_AUTH_USERNAME || !process.env.HTTP_BASIC_AUTH_PASSWORD) {
+ console.warn('HTTP Basic Authentication is enabled but not configured');
+ return new Response('Unauthorized/Unconfigured', unauthResponse);
+ }
+
+ // Request client authentication if no credentials are provided
+ const authHeader = request.headers.get('authorization');
+ if (!authHeader?.startsWith('Basic '))
+ return new Response('Unauthorized', unauthResponse);
+
+ // Request authentication if credentials are invalid
+ const base64Credentials = authHeader.split(' ')[1];
+ const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
+ const [username, password] = credentials.split(':');
+ if (
+ !username || !password ||
+ username !== process.env.HTTP_BASIC_AUTH_USERNAME ||
+ password !== process.env.HTTP_BASIC_AUTH_PASSWORD
+ )
+ return new Response('Unauthorized', unauthResponse);
+
+ return NextResponse.next();
+}
+
+
+// Response to send when authentication is required
+const unauthResponse: ResponseInit = {
+ status: 401,
+ headers: {
+ 'WWW-Authenticate': 'Basic realm="Secure big-AGI"',
+ },
+};
+
+export const config = {
+ matcher: [
+ // Include root
+ '/',
+ // Include pages
+ '/(call|index|news|personas|link)(.*)',
+ // Include API routes (the most important part to block)
+ '/api(.*)',
+ // Note: this excludes _next, /images etc..
+ ],
+};
\ No newline at end of file
diff --git a/pages/api/auth/auth.ts b/pages/api/auth/auth.ts
new file mode 100644
index 000000000..9bf5eef42
--- /dev/null
+++ b/pages/api/auth/auth.ts
@@ -0,0 +1,7 @@
+import type { NextApiRequest, NextApiResponse } from 'next'
+
+export default function handler(_: NextApiRequest, res: NextApiResponse) {
+ res.setHeader('WWW-authenticate', 'Basic realm="Private Area"')
+ res.statusCode = 401
+ res.end(`Auth Required.`)
+}
\ No newline at end of file
diff --git a/src/server/env.mjs b/src/server/env.mjs
index 88be83455..40e218947 100644
--- a/src/server/env.mjs
+++ b/src/server/env.mjs
@@ -48,6 +48,10 @@ export const env = createEnv({
// Backend: Analytics flags (e.g. which hostname responds) for managed installs
BACKEND_ANALYTICS: z.string().optional().transform(list => (list || '').split(';').filter(flag => !!flag)),
+ // Backend: HTTP Basic Authentication
+ HTTP_BASIC_AUTH_USERNAME: z.string().optional(),
+ HTTP_BASIC_AUTH_PASSWORD: z.string().optional(),
+
},
onValidationError: error => {