Move admin dashboard to admin.myhoneydue.com subdomain
- Remove Next.js basePath "/admin" — admin now serves at root - Update all internal links from /admin/xxx to /xxx - Change Go proxy to host-based routing: admin subdomain requests proxy to Next.js, /admin/* redirects to main web app - Update timeout middleware skipper for admin subdomain Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"gorm.io/gorm"
|
||||
@@ -447,7 +448,10 @@ func SetupRoutes(router *echo.Echo, db *gorm.DB, cfg *config.Config, deps *Depen
|
||||
setupAdminProxy(router)
|
||||
}
|
||||
|
||||
// setupAdminProxy configures reverse proxy to the Next.js admin panel
|
||||
// setupAdminProxy configures reverse proxy to the Next.js admin panel.
|
||||
// When ADMIN_HOST is set (e.g. admin.myhoneydue.com), requests to that
|
||||
// subdomain are proxied to Next.js at the root path. Requests to /admin/*
|
||||
// on the admin subdomain redirect to the main web app.
|
||||
func setupAdminProxy(router *echo.Echo) {
|
||||
// Get admin panel URL from env, default to localhost:3001
|
||||
// Note: In production (Dokku), Next.js runs on internal port 3001
|
||||
@@ -456,19 +460,6 @@ func setupAdminProxy(router *echo.Echo) {
|
||||
adminURL = "http://127.0.0.1:3001"
|
||||
}
|
||||
|
||||
// Admin subdomain (e.g. admin.myhoneydue.com) — redirect root to /admin/
|
||||
adminHost := os.Getenv("ADMIN_HOST")
|
||||
if adminHost != "" {
|
||||
router.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
if c.Request().Host == adminHost && c.Request().URL.Path == "/" {
|
||||
return c.Redirect(http.StatusMovedPermanently, "/admin/")
|
||||
}
|
||||
return next(c)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
target, err := url.Parse(adminURL)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -476,18 +467,40 @@ func setupAdminProxy(router *echo.Echo) {
|
||||
|
||||
proxy := httputil.NewSingleHostReverseProxy(target)
|
||||
|
||||
// Handle all /admin/* requests
|
||||
router.Any("/admin/*", func(c echo.Context) error {
|
||||
proxy.ServeHTTP(c.Response(), c.Request())
|
||||
return nil
|
||||
})
|
||||
// Admin subdomain: proxy all non-API requests to Next.js
|
||||
adminHost := os.Getenv("ADMIN_HOST")
|
||||
webAppURL := os.Getenv("WEB_APP_URL")
|
||||
if webAppURL == "" {
|
||||
webAppURL = "https://myhoneydue.com"
|
||||
}
|
||||
|
||||
// Also handle /admin without trailing path
|
||||
router.Any("/admin", func(c echo.Context) error {
|
||||
return c.Redirect(http.StatusMovedPermanently, "/admin/")
|
||||
})
|
||||
if adminHost != "" {
|
||||
router.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
if c.Request().Host != adminHost {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
// Proxy Next.js static assets
|
||||
path := c.Request().URL.Path
|
||||
|
||||
// Redirect /admin/* to the main web app
|
||||
if strings.HasPrefix(path, "/admin") {
|
||||
return c.Redirect(http.StatusMovedPermanently, webAppURL)
|
||||
}
|
||||
|
||||
// Let /api/* routes pass through to the Go API
|
||||
if strings.HasPrefix(path, "/api/") {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
// Proxy everything else to Next.js admin
|
||||
proxy.ServeHTTP(c.Response(), c.Request())
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Proxy Next.js static assets (served from /_next/ regardless of host)
|
||||
router.Any("/_next/*", func(c echo.Context) error {
|
||||
proxy.ServeHTTP(c.Response(), c.Request())
|
||||
return nil
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -73,7 +74,9 @@ func SetupRouter(deps *Dependencies) *echo.Echo {
|
||||
// timeout middleware wraps the response writer in *http.timeoutWriter
|
||||
// which does not implement http.Flusher, causing a panic when
|
||||
// httputil.ReverseProxy or WebSocket upgraders try to flush.
|
||||
return strings.HasPrefix(path, "/admin") ||
|
||||
// Also skip for admin subdomain (all requests proxied to Next.js).
|
||||
adminHost := os.Getenv("ADMIN_HOST")
|
||||
return (adminHost != "" && c.Request().Host == adminHost) ||
|
||||
strings.HasPrefix(path, "/_next") ||
|
||||
strings.HasSuffix(path, "/ws")
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user