updated favicons, fix domain rerouting, fix deploy provisioning
@@ -256,6 +256,11 @@ func cmdProvision(token, zone, plan, sshKeyPath, s3Secret string) error {
|
||||
saveState(state)
|
||||
}
|
||||
|
||||
// Always reconcile forwarded headers rule (handles existing LBs)
|
||||
if err := ensureLBForwardedHeaders(ctx, svc, state.LB.UUID); err != nil {
|
||||
return fmt.Errorf("LB forwarded headers: %w", err)
|
||||
}
|
||||
|
||||
// Always reconcile TLS certs (handles partial failures and re-runs)
|
||||
tlsDomains := []string{cfg.BaseDomain}
|
||||
tlsDomains = append(tlsDomains, cfg.RegistryDomains...)
|
||||
@@ -566,6 +571,14 @@ func createLoadBalancer(ctx context.Context, svc *service.Service, cfg *InfraCon
|
||||
{Name: "public"},
|
||||
},
|
||||
Rules: []request.LoadBalancerFrontendRule{
|
||||
{
|
||||
Name: "set-forwarded-headers",
|
||||
Priority: 1,
|
||||
Matchers: []upcloud.LoadBalancerMatcher{},
|
||||
Actions: []upcloud.LoadBalancerAction{
|
||||
request.NewLoadBalancerSetForwardedHeadersAction(),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "route-hold",
|
||||
Priority: 10,
|
||||
@@ -720,6 +733,45 @@ func ensureLBCertificates(ctx context.Context, svc *service.Service, lbUUID stri
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureLBForwardedHeaders ensures the "https" frontend has a set_forwarded_headers rule.
|
||||
// This makes the LB set X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Port headers,
|
||||
// overwriting any pre-existing values (prevents spoofing).
|
||||
func ensureLBForwardedHeaders(ctx context.Context, svc *service.Service, lbUUID string) error {
|
||||
rules, err := svc.GetLoadBalancerFrontendRules(ctx, &request.GetLoadBalancerFrontendRulesRequest{
|
||||
ServiceUUID: lbUUID,
|
||||
FrontendName: "https",
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("get frontend rules: %w", err)
|
||||
}
|
||||
|
||||
for _, r := range rules {
|
||||
if r.Name == "set-forwarded-headers" {
|
||||
fmt.Println(" Forwarded headers rule: exists")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
_, err = svc.CreateLoadBalancerFrontendRule(ctx, &request.CreateLoadBalancerFrontendRuleRequest{
|
||||
ServiceUUID: lbUUID,
|
||||
FrontendName: "https",
|
||||
Rule: request.LoadBalancerFrontendRule{
|
||||
Name: "set-forwarded-headers",
|
||||
Priority: 1,
|
||||
Matchers: []upcloud.LoadBalancerMatcher{},
|
||||
Actions: []upcloud.LoadBalancerAction{
|
||||
request.NewLoadBalancerSetForwardedHeadersAction(),
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("create forwarded headers rule: %w", err)
|
||||
}
|
||||
fmt.Println(" Forwarded headers rule: created")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// lookupObjectStorage discovers details of an existing Managed Object Storage.
|
||||
func lookupObjectStorage(ctx context.Context, svc *service.Service, uuid string) (ObjectStorageState, error) {
|
||||
storage, err := svc.GetManagedObjectStorage(ctx, &request.GetManagedObjectStorageRequest{
|
||||
|
||||
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.0 KiB |
BIN
pkg/appview/public/atcr.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -1,17 +1,78 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512"><svg version="1.1" id="svg1" width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs id="defs1">
|
||||
<rect x="264" y="264" width="203.43417" height="218.82669" id="rect63"></rect>
|
||||
</defs>
|
||||
<g id="g1">
|
||||
<rect style="fill:#5ecac1;fill-opacity:1;stroke:#000000;stroke-width:18.0441;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" id="rect16" width="246.95587" height="246.95584" x="9.0220766" y="9.0220766"></rect>
|
||||
<rect style="fill:#254365;fill-opacity:1;stroke:#000000;stroke-width:18.0441;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" id="rect17" width="246.95587" height="246.95584" x="9.0220766" y="256.02206"></rect>
|
||||
<rect style="fill:#f29b54;fill-opacity:1;stroke:#000000;stroke-width:18.0012;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" id="rect18" width="246.99879" height="246.99883" x="256.00061" y="9.0005999"></rect>
|
||||
<rect style="display:inline;fill:#47a5d8;fill-opacity:1;stroke:#000000;stroke-width:18.0441;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke" id="rect19" width="246.95586" height="246.95587" x="256.02206" y="256.02206"></rect>
|
||||
<path id="use60" style="fill:#193045;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0;paint-order:normal" d="m 309,42 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 52 c 0,-5.54 -4.014,-10 -9,-10 z m 48,0 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 52 c 0,-5.54 -4.014,-10 -9,-10 z m 48,0 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 52 c 0,-5.54 -4.014,-10 -9,-10 z m 48,0 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 52 c 0,-5.54 -4.014,-10 -9,-10 z"></path>
|
||||
<path id="use60-1" style="fill:#193045;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0;paint-order:normal" d="m 57,42 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 52 C 66,46.46 61.986,42 57,42 Z m 48,0 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 52 c 0,-5.54 -4.014,-10 -9,-10 z m 48,0 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 52 c 0,-5.54 -4.014,-10 -9,-10 z m 48,0 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 52 c 0,-5.54 -4.014,-10 -9,-10 z"></path>
|
||||
<path id="use60-3" style="fill:#193045;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0;paint-order:normal" d="m 57,288 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 298 c 0,-5.54 -4.014,-10 -9,-10 z m 48,0 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 298 c 0,-5.54 -4.014,-10 -9,-10 z m 48,0 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 298 c 0,-5.54 -4.014,-10 -9,-10 z m 48,0 c -4.986,0 -9,4.46 -9,10 v 160 c 0,5.54 4.014,10 9,10 4.986,0 9,-4.46 9,-10 V 298 c 0,-5.54 -4.014,-10 -9,-10 z"></path>
|
||||
<text xml:space="preserve" id="text63" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:151.33px;font-family:'Noto Sans Telugu';-inkscape-font-specification:'Noto Sans Telugu';text-align:center;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect63);shape-padding:0;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:18;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0;paint-order:normal" x="126" y="0" transform="matrix(1.4849596,0,0,1.4775815,-169.00723,-145.87951)"><tspan x="300.94749" y="401.69141" id="tspan2"><tspan style="font-style:italic;font-weight:bold;font-family:'Droid Sans Thai';-inkscape-font-specification:'Droid Sans Thai Bold Italic'" id="tspan1">@</tspan></tspan></text>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
width="511.99997"
|
||||
height="512"
|
||||
id="svg5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs5" />
|
||||
<g
|
||||
id="g1">
|
||||
<rect
|
||||
style="fill:#5ecac1;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="teal"
|
||||
width="256"
|
||||
height="256"
|
||||
x="0"
|
||||
y="0" />
|
||||
<rect
|
||||
style="fill:#254365;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="blue-dark"
|
||||
width="256"
|
||||
height="256"
|
||||
x="0"
|
||||
y="256" />
|
||||
<rect
|
||||
style="fill:#f29b54;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
id="orange"
|
||||
width="256"
|
||||
height="256"
|
||||
x="256"
|
||||
y="0"
|
||||
ry="0" />
|
||||
<rect
|
||||
style="display:inline;fill:#47a5d8;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"
|
||||
id="blue-light"
|
||||
width="256"
|
||||
height="256"
|
||||
x="256"
|
||||
y="256" />
|
||||
<path
|
||||
id="use60"
|
||||
style="fill:#193045;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0;paint-order:normal"
|
||||
d="M 313.33334,40 C 308.16267,40 304,44.162668 304,49.333334 V 198.66665 c 0,5.17067 4.16267,9.33335 9.33334,9.33335 5.17065,0 9.33332,-4.16268 9.33332,-9.33335 V 49.333334 C 322.66666,44.162668 318.50399,40 313.33334,40 Z m 49.77777,0 c -5.17066,0 -9.33333,4.162668 -9.33333,9.333334 V 198.66665 c 0,5.17067 4.16267,9.33335 9.33333,9.33335 5.17066,0 9.33333,-4.16268 9.33333,-9.33335 V 49.333334 C 372.44444,44.162668 368.28177,40 363.11111,40 Z m 49.77778,0 c -5.17066,0 -9.33333,4.162668 -9.33333,9.333334 V 198.66665 c 0,5.17067 4.16267,9.33335 9.33333,9.33335 5.17066,0 9.33333,-4.16268 9.33333,-9.33335 V 49.333334 C 422.22222,44.162668 418.05955,40 412.88889,40 Z m 49.77777,0 c -5.17065,0 -9.33332,4.162668 -9.33332,9.333334 V 198.66665 c 0,5.17067 4.16267,9.33335 9.33332,9.33335 C 467.83733,208 472,203.83732 472,198.66665 V 49.333334 C 472,44.162668 467.83733,40 462.66666,40 Z" />
|
||||
<path
|
||||
id="use60-1"
|
||||
style="fill:#193045;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0;paint-order:normal"
|
||||
d="M 49.333334,40 C 44.162667,40 40,44.162668 40,49.333333 V 198.66664 C 40,203.83732 44.162667,208 49.333334,208 c 5.170665,0 9.333333,-4.16268 9.333333,-9.33336 V 49.333333 C 58.666667,44.162668 54.503999,40 49.333334,40 Z m 49.777781,0 c -5.170672,0 -9.333336,4.162668 -9.333336,9.333333 V 198.66664 c 0,5.17068 4.162664,9.33336 9.333336,9.33336 5.170645,0 9.333325,-4.16268 9.333325,-9.33336 V 49.333333 C 108.44444,44.162668 104.28176,40 99.111115,40 Z m 49.777765,0 c -5.17064,0 -9.33332,4.162668 -9.33332,9.333333 V 198.66664 c 0,5.17068 4.16268,9.33336 9.33332,9.33336 5.17066,0 9.33334,-4.16268 9.33334,-9.33336 V 49.333333 C 158.22222,44.162668 154.05954,40 148.88888,40 Z m 49.77777,0 c -5.17064,0 -9.33332,4.162668 -9.33332,9.333333 V 198.66664 c 0,5.17068 4.16268,9.33336 9.33332,9.33336 C 203.83733,208 208,203.83732 208,198.66664 V 49.333333 C 208,44.162668 203.83733,40 198.66665,40 Z" />
|
||||
<path
|
||||
id="use60-3"
|
||||
style="fill:#193045;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0;paint-order:normal"
|
||||
d="M 49.333334,304 C 44.162667,304 40,308.16267 40,313.33334 V 462.66666 C 40,467.83733 44.162667,472 49.333334,472 c 5.170665,0 9.333333,-4.16267 9.333333,-9.33334 V 313.33334 C 58.666667,308.16267 54.503999,304 49.333334,304 Z m 49.777777,0 c -5.170668,0 -9.333332,4.16267 -9.333332,9.33334 v 149.33332 c 0,5.17067 4.162664,9.33334 9.333332,9.33334 5.170659,0 9.333329,-4.16267 9.333329,-9.33334 V 313.33334 c 0,-5.17067 -4.16267,-9.33334 -9.333329,-9.33334 z m 49.777779,0 c -5.17065,0 -9.33333,4.16267 -9.33333,9.33334 v 149.33332 c 0,5.17067 4.16268,9.33334 9.33333,9.33334 5.17065,0 9.33333,-4.16267 9.33333,-9.33334 V 313.33334 c 0,-5.17067 -4.16268,-9.33334 -9.33333,-9.33334 z m 49.77777,0 c -5.17065,0 -9.33333,4.16267 -9.33333,9.33334 v 149.33332 c 0,5.17067 4.16268,9.33334 9.33333,9.33334 C 203.83733,472 208,467.83733 208,462.66666 V 313.33334 C 208,308.16267 203.83733,304 198.66666,304 Z" />
|
||||
<path
|
||||
style="font-style:italic;font-weight:bold;font-size:151.33px;font-family:'Droid Sans Thai';-inkscape-font-specification:'Droid Sans Thai Bold Italic';text-align:center;white-space:pre;fill:#ffffff;stroke-width:24.8853;stroke-linejoin:round;stroke-opacity:0"
|
||||
d="m 376.56929,472 q -17.82771,0 -31.46068,-5.42608 -13.63295,-5.21741 -22.86141,-14.8174 -9.01873,-9.59999 -13.63297,-22.33043 Q 304,416.69565 304,402.08695 q 0,-18.9913 5.03371,-34.43478 5.24343,-15.44346 14.4719,-27.33912 9.4382,-11.89566 21.81274,-20.03479 12.37453,-8.13914 26.84645,-12.10436 Q 386.84643,304 402.36705,304 q 21.81272,0 37.33333,7.51305 15.52059,7.51302 23.9101,21.70435 Q 472,347.40869 472,367.44346 q 0,9.8087 -2.30712,19.40873 -2.09736,9.39129 -6.29212,17.73913 -4.19476,8.13911 -10.48691,14.39998 -6.0824,6.05217 -14.05242,9.59999 -7.97004,3.54785 -17.61797,3.54785 -8.1798,0 -14.26219,-3.54785 -6.08238,-3.75651 -7.97003,-11.47826 h -1.04869 q -4.40451,6.88696 -10.48689,11.06088 -5.87266,3.96523 -15.73035,3.96523 -11.53557,0 -19.50563,-7.30436 -7.97002,-7.51304 -7.97002,-24.20868 0,-8.34785 2.30711,-16.48698 2.51685,-8.34781 6.92136,-15.65217 4.61422,-7.30433 11.11611,-12.73044 6.50186,-5.63477 14.89137,-8.76521 8.38952,-3.13044 18.24719,-3.13044 11.32584,0 19.2959,1.66957 7.97003,1.66957 14.26218,3.96521 l -10.90637,42.78261 q -1.0487,4.59131 -1.88765,7.93044 -0.83895,3.13044 -0.83895,6.46958 0,3.75651 1.6779,5.42607 1.6779,1.46088 4.19476,1.46088 4.4045,0 8.38951,-2.50436 3.98501,-2.71303 7.13108,-7.30434 3.14607,-4.59131 5.45317,-10.43479 2.30712,-6.05217 3.56556,-12.52173 1.25841,-6.46958 1.25841,-12.93913 0,-13.77391 -5.45317,-23.7913 -5.24345,-10.01741 -16.1498,-15.44348 -10.90638,-5.4261 -27.89514,-5.4261 -12.37453,0 -23.49064,3.54783 -11.11609,3.33913 -20.13482,10.01738 -9.01876,6.46959 -15.73036,15.86088 -6.50185,9.39131 -10.06741,21.28697 -3.56554,11.89566 -3.56554,25.87826 0,14.1913 5.24344,26.29565 5.24346,12.10436 16.77902,19.40868 11.53561,7.09566 30.20227,7.09566 13.00373,0 23.49064,-2.29565 Q 413.2734,448 424.17977,443.82608 v 18.99132 q -9.85767,3.96521 -21.81272,6.46955 Q 390.62173,472 376.56929,472 Z m 0.62921,-58.43478 q 8.17977,0 13.21348,-7.51305 5.24346,-7.72174 8.59926,-20.03478 l 5.87265,-22.53914 q -1.88764,-0.41737 -3.77528,-0.62607 -1.88762,-0.41741 -4.61422,-0.41741 -7.34082,0 -12.79402,3.75653 -5.45317,3.54783 -9.01872,9.3913 -3.56555,5.63477 -5.45319,12.10436 -1.6779,6.26086 -1.6779,11.68695 0,7.93045 2.93634,11.06087 2.93631,3.13044 6.7116,3.13044 z"
|
||||
id="text63"
|
||||
aria-label="@" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0;stroke-linejoin:round;stroke-opacity:0;paint-order:markers fill stroke"
|
||||
id="rect1"
|
||||
width="512"
|
||||
height="16"
|
||||
x="0"
|
||||
y="248" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0;stroke-linejoin:round;stroke-opacity:0;paint-order:markers fill stroke"
|
||||
id="rect2"
|
||||
width="16"
|
||||
height="512"
|
||||
x="248"
|
||||
y="0" />
|
||||
</g>
|
||||
</svg></svg><style>@media (prefers-color-scheme: light) { :root { filter: none; } }
|
||||
<style
|
||||
id="style4">@media (prefers-color-scheme: light) { :root { filter: none; } }
|
||||
@media (prefers-color-scheme: dark) { :root { filter: none; } }
|
||||
</style></svg>
|
||||
</style>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 14 KiB |
@@ -9,12 +9,14 @@ import (
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/distribution/distribution/v3/registry/api/errcode"
|
||||
"github.com/distribution/distribution/v3/registry/handlers"
|
||||
"github.com/go-chi/chi/v5"
|
||||
chimiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
@@ -239,10 +241,10 @@ func NewAppViewServer(cfg *Config, branding *BrandingOverrides) (*AppViewServer,
|
||||
mainRouter.Use(chimiddleware.GetHead)
|
||||
mainRouter.Use(routes.CORSMiddleware())
|
||||
|
||||
// Registry domain redirect middleware
|
||||
// Domain routing middleware
|
||||
if len(cfg.Server.RegistryDomains) > 0 {
|
||||
mainRouter.Use(RegistryDomainRedirect(cfg.Server.RegistryDomains, cfg.Server.BaseURL))
|
||||
slog.Info("Registry domain redirect enabled",
|
||||
mainRouter.Use(DomainRoutingMiddleware(cfg.Server.RegistryDomains, cfg.Server.BaseURL))
|
||||
slog.Info("Domain routing middleware enabled",
|
||||
"registry_domains", cfg.Server.RegistryDomains,
|
||||
"ui_base_url", cfg.Server.BaseURL)
|
||||
}
|
||||
@@ -580,15 +582,29 @@ func (s *AppViewServer) createTokenIssuer() (*token.Issuer, error) {
|
||||
)
|
||||
}
|
||||
|
||||
// RegistryDomainRedirect redirects all non-registry requests from registry
|
||||
// domains to the UI domain. Only /v2 and /v2/* pass through for Docker clients.
|
||||
// Uses 307 (Temporary Redirect) to preserve POST method/body.
|
||||
func RegistryDomainRedirect(registryDomains []string, uiBaseURL string) func(http.Handler) http.Handler {
|
||||
domains := make(map[string]bool, len(registryDomains))
|
||||
// DomainRoutingMiddleware enforces three-tier domain routing:
|
||||
//
|
||||
// 1. UI domain (BaseURL hostname): serves web UI, auth, and static assets.
|
||||
// Blocks /v2/* with an OCI UNSUPPORTED error — registry API lives on
|
||||
// the dedicated registry domain(s).
|
||||
// 2. Registry domains: allows /v2/* for Docker clients. Redirects everything
|
||||
// else to the UI domain with 307 Temporary Redirect.
|
||||
// 3. Unknown domains (CDN origins, IPs, etc.): redirects all requests to the
|
||||
// UI domain with 307, except /health for load balancer probes.
|
||||
func DomainRoutingMiddleware(registryDomains []string, uiBaseURL string) func(http.Handler) http.Handler {
|
||||
regDomains := make(map[string]bool, len(registryDomains))
|
||||
for _, d := range registryDomains {
|
||||
domains[d] = true
|
||||
regDomains[d] = true
|
||||
}
|
||||
|
||||
// Extract UI hostname from BaseURL (e.g., "https://seamark.dev" -> "seamark.dev")
|
||||
var uiHost string
|
||||
if parsed, err := url.Parse(uiBaseURL); err == nil {
|
||||
uiHost = parsed.Hostname()
|
||||
}
|
||||
|
||||
primaryReg := primaryRegistryDomain(registryDomains)
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
host := r.Host
|
||||
@@ -596,19 +612,38 @@ func RegistryDomainRedirect(registryDomains []string, uiBaseURL string) func(htt
|
||||
host = host[:idx]
|
||||
}
|
||||
|
||||
if domains[host] {
|
||||
path := r.URL.Path
|
||||
if path == "/v2" || path == "/v2/" || strings.HasPrefix(path, "/v2/") {
|
||||
path := r.URL.Path
|
||||
isV2 := path == "/v2" || path == "/v2/" || strings.HasPrefix(path, "/v2/")
|
||||
|
||||
switch {
|
||||
case host == uiHost:
|
||||
// UI domain: block /v2/*, serve everything else
|
||||
if isV2 {
|
||||
if err := errcode.ServeJSON(w, errcode.ErrorCodeUnsupported.WithMessage(
|
||||
fmt.Sprintf("registry API is not available on this domain, use %s", primaryReg),
|
||||
)); err != nil {
|
||||
slog.Error("failed to write OCI error response", "error", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
|
||||
case regDomains[host]:
|
||||
// Registry domain: allow /v2/*, redirect everything else
|
||||
if isV2 {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, uiBaseURL+r.URL.RequestURI(), http.StatusTemporaryRedirect)
|
||||
|
||||
target := uiBaseURL + r.URL.RequestURI()
|
||||
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
|
||||
return
|
||||
default:
|
||||
// Unknown domain: allow /health, redirect everything else
|
||||
if path == "/health" {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, uiBaseURL+r.URL.RequestURI(), http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||