mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-06-15 06:18:41 +00:00
feat(opensearch): Add BASE_URL config to support reverse proxy deployments
This commit is contained in:
31
README.md
31
README.md
@ -140,6 +140,37 @@ For more details, check out the full documentation [here](https://github.com/Itz
|
||||
|
||||
Perplexica runs on Next.js and handles all API requests. It works right away on the same network and stays accessible even with port forwarding.
|
||||
|
||||
### Running Behind a Reverse Proxy
|
||||
|
||||
When running Perplexica behind a reverse proxy (like Nginx, Apache, or Traefik), follow these steps to ensure proper functionality:
|
||||
|
||||
1. **Configure the BASE_URL setting**:
|
||||
- In `config.toml`, set the `BASE_URL` parameter under the `[GENERAL]` section to your public-facing URL (e.g., `https://perplexica.yourdomain.com`)
|
||||
|
||||
2. **Ensure proper headers forwarding**:
|
||||
- Your reverse proxy should forward the following headers:
|
||||
- `X-Forwarded-Host`
|
||||
- `X-Forwarded-Proto`
|
||||
- `X-Forwarded-Port` (if using non-standard ports)
|
||||
|
||||
3. **Example Nginx configuration**:
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name perplexica.yourdomain.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This ensures that OpenSearch descriptions, browser integrations, and all URLs work properly when accessing Perplexica through your reverse proxy.
|
||||
|
||||
## One-Click Deployment
|
||||
|
||||
[](https://usw.sealos.io/?openapp=system-template%3FtemplateName%3Dperplexica)
|
||||
|
@ -1,6 +1,7 @@
|
||||
[GENERAL]
|
||||
SIMILARITY_MEASURE = "cosine" # "cosine" or "dot"
|
||||
KEEP_ALIVE = "5m" # How long to keep Ollama models loaded into memory. (Instead of using -1 use "-1m")
|
||||
BASE_URL = "" # Optional. When set, overrides detected URL for OpenSearch and other public URLs
|
||||
|
||||
[MODELS.OPENAI]
|
||||
API_KEY = ""
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {
|
||||
getAnthropicApiKey,
|
||||
getBaseUrl,
|
||||
getCustomOpenaiApiKey,
|
||||
getCustomOpenaiApiUrl,
|
||||
getCustomOpenaiModelName,
|
||||
@ -60,6 +61,7 @@ export const GET = async (req: Request) => {
|
||||
config['customOpenaiApiUrl'] = getCustomOpenaiApiUrl();
|
||||
config['customOpenaiApiKey'] = getCustomOpenaiApiKey();
|
||||
config['customOpenaiModelName'] = getCustomOpenaiModelName();
|
||||
config['baseUrl'] = getBaseUrl();
|
||||
|
||||
return Response.json({ ...config }, { status: 200 });
|
||||
} catch (err) {
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getBaseUrl } from '@/lib/config';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
// Get the host from the request
|
||||
const url = new URL(request.url);
|
||||
const origin = url.origin;
|
||||
|
||||
// Create the OpenSearch XML with the correct origin
|
||||
/**
|
||||
* Creates an OpenSearch XML response with the given origin URL
|
||||
*/
|
||||
function generateOpenSearchResponse(origin: string): NextResponse {
|
||||
const opensearchXml = `<?xml version="1.0" encoding="utf-8"?>
|
||||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>Perplexica</ShortName>
|
||||
@ -17,10 +16,48 @@ export async function GET(request: Request) {
|
||||
<Url type="application/opensearchdescription+xml" rel="self" template="${origin}/api/opensearch"/>
|
||||
</OpenSearchDescription>`;
|
||||
|
||||
// Return the XML with the correct content type
|
||||
return new NextResponse(opensearchXml, {
|
||||
headers: {
|
||||
'Content-Type': 'application/opensearchdescription+xml',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
// Check if a BASE_URL is explicitly configured
|
||||
const configBaseUrl = getBaseUrl();
|
||||
|
||||
// If BASE_URL is configured, use it, otherwise detect from request
|
||||
if (configBaseUrl) {
|
||||
// Remove any trailing slashes for consistency
|
||||
let origin = configBaseUrl.replace(/\/+$/, '');
|
||||
return generateOpenSearchResponse(origin);
|
||||
}
|
||||
|
||||
// Detect the correct origin, taking into account reverse proxy headers
|
||||
const url = new URL(request.url);
|
||||
let origin = url.origin;
|
||||
|
||||
// Extract headers
|
||||
const headers = Object.fromEntries(request.headers);
|
||||
|
||||
// Check for X-Forwarded-Host and related headers to handle reverse proxies
|
||||
if (headers['x-forwarded-host']) {
|
||||
// Determine protocol: prefer X-Forwarded-Proto, fall back to original or https
|
||||
const protocol = headers['x-forwarded-proto'] || url.protocol.replace(':', '');
|
||||
// Build the correct public-facing origin
|
||||
origin = `${protocol}://${headers['x-forwarded-host']}`;
|
||||
|
||||
// Handle non-standard ports if specified in X-Forwarded-Port
|
||||
if (headers['x-forwarded-port']) {
|
||||
const port = headers['x-forwarded-port'];
|
||||
// Don't append standard ports (80 for HTTP, 443 for HTTPS)
|
||||
if (!((protocol === 'http' && port === '80') || (protocol === 'https' && port === '443'))) {
|
||||
origin = `${origin}:${port}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate and return the OpenSearch response
|
||||
return generateOpenSearchResponse(origin);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ interface Config {
|
||||
GENERAL: {
|
||||
SIMILARITY_MEASURE: string;
|
||||
KEEP_ALIVE: string;
|
||||
BASE_URL?: string;
|
||||
};
|
||||
MODELS: {
|
||||
OPENAI: {
|
||||
@ -70,6 +71,8 @@ export const getSimilarityMeasure = () =>
|
||||
|
||||
export const getKeepAlive = () => loadConfig().GENERAL.KEEP_ALIVE;
|
||||
|
||||
export const getBaseUrl = () => loadConfig().GENERAL.BASE_URL;
|
||||
|
||||
export const getOpenaiApiKey = () => loadConfig().MODELS.OPENAI.API_KEY;
|
||||
|
||||
export const getGroqApiKey = () => loadConfig().MODELS.GROQ.API_KEY;
|
||||
|
Reference in New Issue
Block a user