diff --git a/openflare_server/model/goose/goose_202606030004_add_pages_api_proxy.go b/openflare_server/model/goose/goose_202606030004_add_pages_api_proxy.go
new file mode 100644
index 00000000..fc0eb9ee
--- /dev/null
+++ b/openflare_server/model/goose/goose_202606030004_add_pages_api_proxy.go
@@ -0,0 +1,35 @@
+package goose
+
+import (
+ "fmt"
+
+ presslygoose "github.com/pressly/goose/v3"
+ "gorm.io/gorm"
+)
+
+const versionPagesAPIProxy int64 = 202606030004
+
+// migration202606030004 adds API proxying fields (enabled, path, pass, rewrite)
+// to Pages projects.
+func migration202606030004(backend string, ctx Context) *presslygoose.Migration {
+ return newGORMMigration(
+ versionPagesAPIProxy,
+ "202606030004_add_pages_api_proxy.go",
+ backend,
+ ctx,
+ migratePagesAPIProxy,
+ )
+}
+
+func migratePagesAPIProxy(ctx Context, db *gorm.DB, backend string) error {
+ if err := ctx.ApplyCurrentSchema(db, backend); err != nil {
+ return err
+ }
+ // Verify that the columns exist
+ for _, col := range []string{"api_proxy_enabled", "api_proxy_path", "api_proxy_pass", "api_proxy_rewrite"} {
+ if !db.Migrator().HasColumn("pages_projects", col) {
+ return fmt.Errorf("column pages_projects.%s is missing", col)
+ }
+ }
+ return nil
+}
diff --git a/openflare_server/model/goose/migrations.go b/openflare_server/model/goose/migrations.go
index afa6437a..ea20ef00 100644
--- a/openflare_server/model/goose/migrations.go
+++ b/openflare_server/model/goose/migrations.go
@@ -44,6 +44,7 @@ func registeredMigrations(backend string, ctx Context) []*presslygoose.Migration
migration202606030001(backend, ctx),
migration202606030002(backend, ctx),
migration202606030003(backend, ctx),
+ migration202606030004(backend, ctx),
}
}
diff --git a/openflare_server/model/pages.go b/openflare_server/model/pages.go
index eea88464..58e9a770 100644
--- a/openflare_server/model/pages.go
+++ b/openflare_server/model/pages.go
@@ -15,6 +15,10 @@ type PagesProject struct {
Enabled bool `json:"enabled" gorm:"not null;default:true"`
SPAFallbackEnabled bool `json:"spa_fallback_enabled" gorm:"not null;default:false"`
SPAFallbackPath string `json:"spa_fallback_path" gorm:"size:512;not null;default:'/index.html'"`
+ APIProxyEnabled bool `json:"api_proxy_enabled" gorm:"not null;default:false"`
+ APIProxyPath string `json:"api_proxy_path" gorm:"size:255;not null;default:''"`
+ APIProxyPass string `json:"api_proxy_pass" gorm:"size:2048;not null;default:''"`
+ APIProxyRewrite string `json:"api_proxy_rewrite" gorm:"size:255;not null;default:''"`
ActiveDeploymentID *uint `json:"active_deployment_id" gorm:"index"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
diff --git a/openflare_server/service/config_version.go b/openflare_server/service/config_version.go
index 5fb5a615..17f3a7e4 100644
--- a/openflare_server/service/config_version.go
+++ b/openflare_server/service/config_version.go
@@ -104,6 +104,10 @@ type snapshotPagesDeployment struct {
EntryFile string `json:"entry_file"`
SPAFallbackEnabled bool `json:"spa_fallback_enabled"`
SPAFallbackPath string `json:"spa_fallback_path"`
+ APIProxyEnabled bool `json:"api_proxy_enabled"`
+ APIProxyPath string `json:"api_proxy_path"`
+ APIProxyPass string `json:"api_proxy_pass"`
+ APIProxyRewrite string `json:"api_proxy_rewrite"`
LocalRoot string `json:"local_root"`
}
@@ -615,6 +619,10 @@ func buildSnapshotPagesDeployment(projectID *uint) (*snapshotPagesDeployment, er
EntryFile: deployment.EntryFile,
SPAFallbackEnabled: project.SPAFallbackEnabled,
SPAFallbackPath: normalizeStoredPagesFallbackPath(project.SPAFallbackPath),
+ APIProxyEnabled: project.APIProxyEnabled,
+ APIProxyPath: project.APIProxyPath,
+ APIProxyPass: project.APIProxyPass,
+ APIProxyRewrite: project.APIProxyRewrite,
LocalRoot: fmt.Sprintf("%s/deployments/%d/current", openrestyrender.PagesDirPlaceholder, deployment.ID),
}, nil
}
diff --git a/openflare_server/service/pages.go b/openflare_server/service/pages.go
index ba147291..c842dec4 100644
--- a/openflare_server/service/pages.go
+++ b/openflare_server/service/pages.go
@@ -8,6 +8,7 @@ import (
"fmt"
"io"
"mime/multipart"
+ "net/url"
"openflare/common"
"openflare/model"
"os"
@@ -36,6 +37,10 @@ type PagesProjectInput struct {
Enabled bool `json:"enabled"`
SPAFallbackEnabled bool `json:"spa_fallback_enabled"`
SPAFallbackPath string `json:"spa_fallback_path"`
+ APIProxyEnabled bool `json:"api_proxy_enabled"`
+ APIProxyPath string `json:"api_proxy_path"`
+ APIProxyPass string `json:"api_proxy_pass"`
+ APIProxyRewrite string `json:"api_proxy_rewrite"`
}
type PagesProjectView struct {
@@ -46,6 +51,10 @@ type PagesProjectView struct {
Enabled bool `json:"enabled"`
SPAFallbackEnabled bool `json:"spa_fallback_enabled"`
SPAFallbackPath string `json:"spa_fallback_path"`
+ APIProxyEnabled bool `json:"api_proxy_enabled"`
+ APIProxyPath string `json:"api_proxy_path"`
+ APIProxyPass string `json:"api_proxy_pass"`
+ APIProxyRewrite string `json:"api_proxy_rewrite"`
ActiveDeploymentID *uint `json:"active_deployment_id"`
ActiveDeployment *PagesDeploymentView `json:"active_deployment,omitempty"`
DeploymentCount int64 `json:"deployment_count"`
@@ -137,6 +146,10 @@ func UpdatePagesProject(id uint, input PagesProjectInput) (*PagesProjectView, er
"enabled": project.Enabled,
"spa_fallback_enabled": project.SPAFallbackEnabled,
"spa_fallback_path": project.SPAFallbackPath,
+ "api_proxy_enabled": project.APIProxyEnabled,
+ "api_proxy_path": project.APIProxyPath,
+ "api_proxy_pass": project.APIProxyPass,
+ "api_proxy_rewrite": project.APIProxyRewrite,
}).Error; err != nil {
if model.IsUniqueConstraintError(err) {
return nil, errors.New("Pages 项目标识已存在")
@@ -413,6 +426,31 @@ func buildPagesProject(project *model.PagesProject, input PagesProjectInput) (*m
return nil, err
}
project.SPAFallbackPath = fallbackPath
+
+ project.APIProxyEnabled = input.APIProxyEnabled
+ apiProxyPath := strings.TrimSpace(input.APIProxyPath)
+ apiProxyPass := strings.TrimSpace(input.APIProxyPass)
+ apiProxyRewrite := strings.TrimSpace(input.APIProxyRewrite)
+
+ if project.APIProxyEnabled {
+ if apiProxyPath == "" {
+ return nil, errors.New("启用 API 反代时,匹配路径不能为空")
+ }
+ if !strings.HasPrefix(apiProxyPath, "/") {
+ return nil, errors.New("API 反代匹配路径必须以 '/' 开头")
+ }
+ if apiProxyPass == "" {
+ return nil, errors.New("启用 API 反代时,后端服务地址不能为空")
+ }
+ parsedURL, err := url.Parse(apiProxyPass)
+ if err != nil || (parsedURL.Scheme != "http" && parsedURL.Scheme != "https") || parsedURL.Host == "" {
+ return nil, errors.New("API 反代后端服务地址必须是有效的 HTTP/HTTPS URL")
+ }
+ }
+ project.APIProxyPath = apiProxyPath
+ project.APIProxyPass = apiProxyPass
+ project.APIProxyRewrite = apiProxyRewrite
+
return project, nil
}
@@ -428,6 +466,10 @@ func buildPagesProjectView(project *model.PagesProject) (*PagesProjectView, erro
Enabled: project.Enabled,
SPAFallbackEnabled: project.SPAFallbackEnabled,
SPAFallbackPath: normalizeStoredPagesFallbackPath(project.SPAFallbackPath),
+ APIProxyEnabled: project.APIProxyEnabled,
+ APIProxyPath: project.APIProxyPath,
+ APIProxyPass: project.APIProxyPass,
+ APIProxyRewrite: project.APIProxyRewrite,
ActiveDeploymentID: project.ActiveDeploymentID,
CreatedAt: project.CreatedAt,
UpdatedAt: project.UpdatedAt,
diff --git a/openflare_server/service/pages_test.go b/openflare_server/service/pages_test.go
index f1a4ff01..1b3bfd51 100644
--- a/openflare_server/service/pages_test.go
+++ b/openflare_server/service/pages_test.go
@@ -271,3 +271,57 @@ func TestUploadPagesDeploymentWithTopLevelFolder(t *testing.T) {
t.Fatalf("expected EntryFile to be index.html, got %q", deployment.EntryFile)
}
}
+
+func TestPagesProjectAPIProxyValidation(t *testing.T) {
+ setupServiceTestDB(t)
+
+ // 1. Invalid configuration: enabled but empty fields
+ _, err := CreatePagesProject(PagesProjectInput{
+ Name: "API Proxy 1",
+ Enabled: true,
+ APIProxyEnabled: true,
+ })
+ if err == nil || !strings.Contains(err.Error(), "匹配路径不能为空") {
+ t.Fatalf("expected error for empty match path, got: %v", err)
+ }
+
+ // 2. Invalid path: must start with '/'
+ _, err = CreatePagesProject(PagesProjectInput{
+ Name: "API Proxy 2",
+ Enabled: true,
+ APIProxyEnabled: true,
+ APIProxyPath: "api",
+ APIProxyPass: "http://127.0.0.1:8080",
+ })
+ if err == nil || !strings.Contains(err.Error(), "必须以 '/' 开头") {
+ t.Fatalf("expected error for path not starting with /, got: %v", err)
+ }
+
+ // 3. Invalid target URL
+ _, err = CreatePagesProject(PagesProjectInput{
+ Name: "API Proxy 3",
+ Enabled: true,
+ APIProxyEnabled: true,
+ APIProxyPath: "/api",
+ APIProxyPass: "127.0.0.1:8080",
+ })
+ if err == nil || !strings.Contains(err.Error(), "有效的 HTTP/HTTPS URL") {
+ t.Fatalf("expected error for invalid pass URL, got: %v", err)
+ }
+
+ // 4. Valid configuration
+ project, err := CreatePagesProject(PagesProjectInput{
+ Name: "API Proxy Valid",
+ Enabled: true,
+ APIProxyEnabled: true,
+ APIProxyPath: "/api",
+ APIProxyPass: "http://127.0.0.1:8080",
+ APIProxyRewrite: "/",
+ })
+ if err != nil {
+ t.Fatalf("unexpected error creating valid project: %v", err)
+ }
+ if !project.APIProxyEnabled || project.APIProxyPath != "/api" || project.APIProxyPass != "http://127.0.0.1:8080" || project.APIProxyRewrite != "/" {
+ t.Fatalf("unexpected project state: %+v", project)
+ }
+}
diff --git a/openflare_server/utils/render/openresty/render.go b/openflare_server/utils/render/openresty/render.go
index 3e2c1d24..0b83d687 100644
--- a/openflare_server/utils/render/openresty/render.go
+++ b/openflare_server/utils/render/openresty/render.go
@@ -421,8 +421,50 @@ func renderHTTPProxyServer(serverNames string, siteName string, originURL string
return fmt.Sprintf("server {\n listen 80;\n server_name %s;\n%s%s location / {\n%s%s%s%s%s }\n%s}\n\n", serverNames, renderAccessBlock(siteName, powEnabled), renderPowLocationBlocks(powEnabled), renderBasicAuthBlock(basicAuthEnabled, basicAuthUsername, basicAuthPassword), renderProxyHeaderBlock(originURL, originHost, customHeaders, upstreamConfig, cfg), renderRouteLimitBlock(limitConfig), renderRouteCacheBlock(cacheConfig, cfg), renderProxyPassBlock(originURL, upstreamConfig), renderPowStaticLocationBlock(powEnabled))
}
+func renderPagesAPIProxyLocationBlock(deployment *PagesDeployment) string {
+ if deployment == nil || !deployment.APIProxyEnabled {
+ return ""
+ }
+ path := strings.TrimSpace(deployment.APIProxyPath)
+ pass := strings.TrimSpace(deployment.APIProxyPass)
+ rewrite := strings.TrimSpace(deployment.APIProxyRewrite)
+ if path == "" || pass == "" {
+ return ""
+ }
+ if !strings.HasPrefix(path, "/") {
+ path = "/" + path
+ }
+ cleanPath := strings.TrimSuffix(path, "/")
+
+ var builder strings.Builder
+ builder.WriteString(fmt.Sprintf("\n location %s {\n", cleanPath))
+ if rewrite != "" {
+ if !strings.HasPrefix(rewrite, "/") {
+ rewrite = "/" + rewrite
+ }
+ cleanRewrite := strings.TrimSuffix(rewrite, "/")
+ if cleanRewrite == "" {
+ builder.WriteString(fmt.Sprintf(" rewrite ^%s/(.*)$ /$1 break;\n", regexp.QuoteMeta(cleanPath)))
+ builder.WriteString(fmt.Sprintf(" rewrite ^%s$ / break;\n", regexp.QuoteMeta(cleanPath)))
+ } else {
+ builder.WriteString(fmt.Sprintf(" rewrite ^%s/(.*)$ %s/$1 break;\n", regexp.QuoteMeta(cleanPath), cleanRewrite))
+ builder.WriteString(fmt.Sprintf(" rewrite ^%s$ %s break;\n", regexp.QuoteMeta(cleanPath), cleanRewrite))
+ }
+ }
+ builder.WriteString(fmt.Sprintf(" proxy_pass %s;\n", pass))
+ builder.WriteString(" proxy_http_version 1.1;\n")
+ builder.WriteString(" proxy_set_header Host $http_host;\n")
+ builder.WriteString(" proxy_set_header X-Real-IP $remote_addr;\n")
+ builder.WriteString(" proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n")
+ builder.WriteString(" proxy_set_header X-Forwarded-Proto $scheme;\n")
+ builder.WriteString(" proxy_set_header Upgrade $http_upgrade;\n")
+ builder.WriteString(" proxy_set_header Connection $connection_upgrade;\n")
+ builder.WriteString(" }\n")
+ return builder.String()
+}
+
func renderHTTPPagesServer(serverNames string, siteName string, deployment *PagesDeployment, limitConfig routeLimitConfig, powEnabled bool, basicAuthEnabled bool, basicAuthUsername string, basicAuthPassword string) string {
- return fmt.Sprintf("server {\n listen 80;\n server_name %s;\n%s%s root %s;\n index %s;\n\n location / {\n%s%s }\n%s}\n\n", serverNames, renderAccessBlock(siteName, powEnabled), renderPowLocationBlocks(powEnabled), quoteNginxStringLiteral(pagesDeploymentRoot(deployment)), quoteNginxStringLiteral(pagesEntryFile(deployment)), renderBasicAuthBlock(basicAuthEnabled, basicAuthUsername, basicAuthPassword), renderPagesLocationBlock(deployment, limitConfig), renderPowStaticLocationBlock(powEnabled))
+ return fmt.Sprintf("server {\n listen 80;\n server_name %s;\n%s%s root %s;\n index %s;%s\n\n location / {\n%s%s }\n%s}\n\n", serverNames, renderAccessBlock(siteName, powEnabled), renderPowLocationBlocks(powEnabled), quoteNginxStringLiteral(pagesDeploymentRoot(deployment)), quoteNginxStringLiteral(pagesEntryFile(deployment)), renderPagesAPIProxyLocationBlock(deployment), renderBasicAuthBlock(basicAuthEnabled, basicAuthUsername, basicAuthPassword), renderPagesLocationBlock(deployment, limitConfig), renderPowStaticLocationBlock(powEnabled))
}
func renderHTTPRedirectServer(serverNames string) string {
@@ -450,7 +492,7 @@ func renderHTTPSPagesServer(serverNames string, siteName string, certificateID u
h3Listen = " listen 443 quic;\n"
h3Header = " add_header Alt-Svc 'h3=\":443\"; ma=86400';\n"
}
- return fmt.Sprintf("server {\n listen 443 ssl;\n%s http2 on;\n server_name %s;\n ssl_certificate %s;\n ssl_certificate_key %s;\n%s%s%s root %s;\n index %s;\n\n location / {\n%s%s }\n%s}\n\n", h3Listen, serverNames, certPath, keyPath, h3Header, renderAccessBlock(siteName, powEnabled), renderPowLocationBlocks(powEnabled), quoteNginxStringLiteral(pagesDeploymentRoot(deployment)), quoteNginxStringLiteral(pagesEntryFile(deployment)), renderBasicAuthBlock(basicAuthEnabled, basicAuthUsername, basicAuthPassword), renderPagesLocationBlock(deployment, limitConfig), renderPowStaticLocationBlock(powEnabled))
+ return fmt.Sprintf("server {\n listen 443 ssl;\n%s http2 on;\n server_name %s;\n ssl_certificate %s;\n ssl_certificate_key %s;\n%s%s%s root %s;\n index %s;%s\n\n location / {\n%s%s }\n%s}\n\n", h3Listen, serverNames, certPath, keyPath, h3Header, renderAccessBlock(siteName, powEnabled), renderPowLocationBlocks(powEnabled), quoteNginxStringLiteral(pagesDeploymentRoot(deployment)), quoteNginxStringLiteral(pagesEntryFile(deployment)), renderPagesAPIProxyLocationBlock(deployment), renderBasicAuthBlock(basicAuthEnabled, basicAuthUsername, basicAuthPassword), renderPagesLocationBlock(deployment, limitConfig), renderPowStaticLocationBlock(powEnabled))
}
func renderPagesLocationBlock(deployment *PagesDeployment, limitConfig routeLimitConfig) string {
diff --git a/openflare_server/utils/render/openresty/render_test.go b/openflare_server/utils/render/openresty/render_test.go
new file mode 100644
index 00000000..8083f2c6
--- /dev/null
+++ b/openflare_server/utils/render/openresty/render_test.go
@@ -0,0 +1,100 @@
+package openresty
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestRenderPagesAPIProxyLocationBlock(t *testing.T) {
+ tests := []struct {
+ name string
+ deployment *PagesDeployment
+ expected []string
+ unexpected []string
+ }{
+ {
+ name: "nil deployment",
+ deployment: nil,
+ expected: []string{""},
+ },
+ {
+ name: "disabled proxy",
+ deployment: &PagesDeployment{
+ APIProxyEnabled: false,
+ APIProxyPath: "/api",
+ APIProxyPass: "http://127.0.0.1:8080",
+ },
+ expected: []string{""},
+ },
+ {
+ name: "enabled proxy without rewrite",
+ deployment: &PagesDeployment{
+ APIProxyEnabled: true,
+ APIProxyPath: "/api",
+ APIProxyPass: "http://127.0.0.1:8080",
+ APIProxyRewrite: "",
+ },
+ expected: []string{
+ "location /api {",
+ "proxy_pass http://127.0.0.1:8080;",
+ "proxy_http_version 1.1;",
+ "proxy_set_header Host $http_host;",
+ },
+ unexpected: []string{
+ "rewrite",
+ },
+ },
+ {
+ name: "enabled proxy with rewrite to root",
+ deployment: &PagesDeployment{
+ APIProxyEnabled: true,
+ APIProxyPath: "/api",
+ APIProxyPass: "http://127.0.0.1:8080",
+ APIProxyRewrite: "/",
+ },
+ expected: []string{
+ "location /api {",
+ "rewrite ^/api/(.*)$ /$1 break;",
+ "rewrite ^/api$ / break;",
+ "proxy_pass http://127.0.0.1:8080;",
+ },
+ },
+ {
+ name: "enabled proxy with rewrite to subpath",
+ deployment: &PagesDeployment{
+ APIProxyEnabled: true,
+ APIProxyPath: "/api",
+ APIProxyPass: "http://127.0.0.1:8080",
+ APIProxyRewrite: "/v2",
+ },
+ expected: []string{
+ "location /api {",
+ "rewrite ^/api/(.*)$ /v2/$1 break;",
+ "rewrite ^/api$ /v2 break;",
+ "proxy_pass http://127.0.0.1:8080;",
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := renderPagesAPIProxyLocationBlock(tt.deployment)
+ if len(tt.expected) == 1 && tt.expected[0] == "" {
+ if got != "" {
+ t.Fatalf("expected empty output, got: %q", got)
+ }
+ return
+ }
+ for _, exp := range tt.expected {
+ if !strings.Contains(got, exp) {
+ t.Errorf("expected output to contain %q, but got:\n%s", exp, got)
+ }
+ }
+ for _, unexp := range tt.unexpected {
+ if strings.Contains(got, unexp) {
+ t.Errorf("expected output NOT to contain %q, but got:\n%s", unexp, got)
+ }
+ }
+ })
+ }
+}
diff --git a/openflare_server/utils/render/openresty/types.go b/openflare_server/utils/render/openresty/types.go
index b803fff5..9beb4734 100644
--- a/openflare_server/utils/render/openresty/types.go
+++ b/openflare_server/utils/render/openresty/types.go
@@ -130,6 +130,10 @@ type PagesDeployment struct {
EntryFile string `json:"entry_file"`
SPAFallbackEnabled bool `json:"spa_fallback_enabled"`
SPAFallbackPath string `json:"spa_fallback_path"`
+ APIProxyEnabled bool `json:"api_proxy_enabled"`
+ APIProxyPath string `json:"api_proxy_path"`
+ APIProxyPass string `json:"api_proxy_pass"`
+ APIProxyRewrite string `json:"api_proxy_rewrite"`
LocalRoot string `json:"local_root"`
}
diff --git a/openflare_server/web/features/pages/components/pages-page.tsx b/openflare_server/web/features/pages/components/pages-page.tsx
index 702dcfe5..e0fd4a5c 100644
--- a/openflare_server/web/features/pages/components/pages-page.tsx
+++ b/openflare_server/web/features/pages/components/pages-page.tsx
@@ -431,6 +431,10 @@ function PagesProjectEditModal({
const [description, setDescription] = useState(project.description || '');
const [spaFallbackEnabled, setSpaFallbackEnabled] = useState(project.spa_fallback_enabled);
const [spaFallbackPath, setSpaFallbackPath] = useState(project.spa_fallback_path);
+ const [apiProxyEnabled, setApiProxyEnabled] = useState(project.api_proxy_enabled || false);
+ const [apiProxyPath, setApiProxyPath] = useState(project.api_proxy_path || '');
+ const [apiProxyPass, setApiProxyPass] = useState(project.api_proxy_pass || '');
+ const [apiProxyRewrite, setApiProxyRewrite] = useState(project.api_proxy_rewrite || '');
useEffect(() => {
setName(project.name);
@@ -438,6 +442,10 @@ function PagesProjectEditModal({
setDescription(project.description || '');
setSpaFallbackEnabled(project.spa_fallback_enabled);
setSpaFallbackPath(project.spa_fallback_path);
+ setApiProxyEnabled(project.api_proxy_enabled || false);
+ setApiProxyPath(project.api_proxy_path || '');
+ setApiProxyPass(project.api_proxy_pass || '');
+ setApiProxyRewrite(project.api_proxy_rewrite || '');
}, [project]);
const updateMutation = useMutation({
@@ -449,6 +457,10 @@ function PagesProjectEditModal({
enabled: project.enabled,
spa_fallback_enabled: spaFallbackEnabled,
spa_fallback_path: spaFallbackPath,
+ api_proxy_enabled: apiProxyEnabled,
+ api_proxy_path: apiProxyPath,
+ api_proxy_pass: apiProxyPass,
+ api_proxy_rewrite: apiProxyRewrite,
}),
onSuccess: () => {
onClose();
@@ -527,6 +539,48 @@ function PagesProjectEditModal({
onChange={(event) => setSpaFallbackPath(event.target.value)}
/>
+
{updateMutation.error.message} @@ -573,6 +627,10 @@ function PagesProjectCreateModal({ enabled: true, spa_fallback_enabled: spaFallbackEnabled, spa_fallback_path: spaFallbackPath, + api_proxy_enabled: false, + api_proxy_path: '', + api_proxy_pass: '', + api_proxy_rewrite: '', }), onSuccess: () => { resetForm(); diff --git a/openflare_server/web/features/pages/types.ts b/openflare_server/web/features/pages/types.ts index 4e324b33..4ed08135 100644 --- a/openflare_server/web/features/pages/types.ts +++ b/openflare_server/web/features/pages/types.ts @@ -20,6 +20,10 @@ export interface PagesProject { enabled: boolean; spa_fallback_enabled: boolean; spa_fallback_path: string; + api_proxy_enabled: boolean; + api_proxy_path: string; + api_proxy_pass: string; + api_proxy_rewrite: string; active_deployment_id?: number | null; active_deployment?: PagesDeployment | null; deployment_count: number; @@ -34,4 +38,8 @@ export interface PagesProjectPayload { enabled: boolean; spa_fallback_enabled: boolean; spa_fallback_path: string; + api_proxy_enabled: boolean; + api_proxy_path: string; + api_proxy_pass: string; + api_proxy_rewrite: string; }