diff --git a/messages/en-US.json b/messages/en-US.json
index f931ea776..58552e197 100644
--- a/messages/en-US.json
+++ b/messages/en-US.json
@@ -4526,7 +4526,7 @@
"redirectRewritePathRequired": "Enter a rewrite path, or choose Strip Prefix",
"redirectMatchPathInvalidRegex": "Match path must be a valid regular expression",
"redirectPriorityInvalid": "Enter a whole number between 1 and 1000",
- "redirectPriorityDescription": "Higher priority routes are evaluated first. Redirects are always evaluated before targets.",
+ "redirectPriorityDescription": "Higher priority routes are evaluated first.",
"redirectCreate": "Create Redirect",
"redirectCreateDescription": "Forward requests matching a path to another URL.",
"redirectEditDescription": "Update how this redirect forwards incoming requests.",
diff --git a/server/lib/traefik/redirect.ts b/server/lib/traefik/redirect.ts
index 787b95509..05f6eae00 100644
--- a/server/lib/traefik/redirect.ts
+++ b/server/lib/traefik/redirect.ts
@@ -57,10 +57,6 @@ export function buildRedirectConfig(params: {
for (const redirect of redirects) {
const routerName = `${redirect.redirectId}-redirect-${redirect.name}-router`;
- logger.debug(
- `Processing redirect ${redirect.name} with domain ${redirect.fullDomain}`
- );
-
if (!redirect.enabled) {
logger.debug(
`Redirect ${redirect.name} is disabled, skipping Traefik config`
diff --git a/src/components/RedirectForm.tsx b/src/components/RedirectForm.tsx
index 9f14d61f2..56846d3bc 100644
--- a/src/components/RedirectForm.tsx
+++ b/src/components/RedirectForm.tsx
@@ -15,6 +15,7 @@ import {
SettingsSectionBody,
SettingsSectionDescription,
SettingsSectionForm,
+ SettingsSectionGrid,
SettingsSectionHeader,
SettingsSectionTitle
} from "@app/components/Settings";
@@ -337,7 +338,7 @@ export default function RedirectForm({
-
+
-
-
-
-
-
-
-
-
- {t("redirectSource")}
-
-
- {t("redirectSourceSectionDescription")}
-
-
-
-
-
-
- {resourceMissingDomain && (
-
-
-
-
- {t(
- "redirectDomainSelectedDomainNotFound"
- )}
-
-
-
- )}
-
-
- (
-
-
- {t(
- "redirectAttachedTo"
- )}
-
-
-
-
- )}
- />
-
- {attachTo === "domain" ? (
-
- (
-
- {
- form.setValue(
- "domainId",
- res?.domainId ??
- null,
- {
- shouldValidate: true
- }
- );
- form.setValue(
- "subdomain",
- res?.subdomain ||
- null
- );
- setDomainFullDomain(
- res?.fullDomain ??
- null
- );
- }}
- />
-
-
- )}
- />
-
- ) : (
-
- (
-
-
- {t(
- "selectedRedirectResource"
- )}
-
-
-
-
-
-
-
-
- {
- setSelectedResource(
- resource
- );
- field.onChange(
- resource.resourceId
- );
- }}
- />
-
-
-
-
- )}
- />
-
- )}
-
-
- (
-
-
- {t("matchPath")}
-
- {
- // No match path
- // means the
- // redirect applies
- // to every path;
- // pathMatchType is
- // NOT NULL so it
- // keeps a default.
- field.onChange(
- config.path ||
- null
- );
- form.setValue(
- "pathMatchType",
- (config.pathMatchType as
- | "exact"
- | "prefix"
- | "regex") ||
- DEFAULT_PATH_MATCH_TYPE
- );
- }}
- trigger={
-
- }
- />
-
- {t(
- "redirectMatchPathDescription"
- )}
-
-
-
- )}
- />
-
@@ -751,172 +484,443 @@ export default function RedirectForm({
-
-
-
- {t("redirectDestination")}
-
-
- {t("redirectDestinationSectionDescription")}
-
-
+
+
+
+
+ {t("redirectSource")}
+
+
+ {t("redirectSourceSectionDescription")}
+
+
-
-
-
-
-
-
-
-
- (
-
-
+
+
+
+ {resourceMissingDomain && (
+
+
+
+
{t(
- "redirectDestinationHost"
+ "redirectDomainSelectedDomainNotFound"
)}
-
-
-
+
+
+ )}
+
+
+ (
+
+
+ {t(
+ "redirectAttachedTo"
+ )}
+
+
-
-
- {t(
- "redirectDestinationHostDescription"
- )}
-
-
-
- )}
- />
-
+ >
+
+
+
+
+
+
+
+ {t(
+ "redirectAttachDomain"
+ )}
+
+
+ {t(
+ "redirectAttachResource"
+ )}
+
+
+
+
+
+ )}
+ />
+
+ {attachTo === "domain" ? (
+
+ (
+
+ {
+ form.setValue(
+ "domainId",
+ res?.domainId ??
+ null,
+ {
+ shouldValidate: true
+ }
+ );
+ form.setValue(
+ "subdomain",
+ res?.subdomain ||
+ null
+ );
+ setDomainFullDomain(
+ res?.fullDomain ??
+ null
+ );
+ }}
+ />
+
+
+ )}
+ />
+
+ ) : (
+
+ (
+
+
+ {t(
+ "selectedRedirectResource"
+ )}
+
+
+
+
+
+
+
+
+ {
+ setSelectedResource(
+ resource
+ );
+ field.onChange(
+ resource.resourceId
+ );
+ }}
+ />
+
+
+
+
+ )}
+ />
+
+ )}
-
- (
-
-
- {t("rewritePath")}
-
- {
- field.onChange(
- config.rewritePath ||
- null
- );
- form.setValue(
- "rewritePathType",
- (config.rewritePathType as
- | "exact"
- | "prefix"
- | "regex"
- | "stripPrefix"
- | null) ??
- null
- );
- }}
- trigger={
- hasRewrite ? (
+ {/* The cloud only serves HTTPS, and resource-attached redirects inherit TLS, so there is nothing to toggle in those cases. */}
+ {build !== "saas" &&
+ attachTo === "domain" && (
+
+ (
+
+
+
+
+
+
+ )}
+ />
+
+ )}
+
+
+ (
+
+
+ {t("matchPath")}
+
+ {
+ // No match path
+ // means the
+ // redirect applies
+ // to every path;
+ // pathMatchType is
+ // NOT NULL so it
+ // keeps a default.
+ field.onChange(
+ config.path ||
+ null
+ );
+ form.setValue(
+ "pathMatchType",
+ (config.pathMatchType as
+ | "exact"
+ | "prefix"
+ | "regex") ||
+ DEFAULT_PATH_MATCH_TYPE
+ );
+ }}
+ trigger={
- ) : (
-
- )
- }
- />
-
- {t(
- "redirectRewritePathDescription"
- )}
-
-
-
- )}
- />
-
-
-
- (
-
-
-
-
-
-
- )}
- />
-
-
-
-
-
+
+ {t(
+ "redirectMatchPathDescription"
+ )}
+
+
+
+ )}
+ />
+
+
+
+
+
+
+
+
+
+ {t("redirectDestination")}
+
+
+ {t("redirectDestinationSectionDescription")}
+
+
+
+
+
+
+
+
+
+
+
+ (
+
+
+ {t(
+ "redirectDestinationHost"
+ )}
+
+
+
+
+
+ {t(
+ "redirectDestinationHostDescription"
+ )}
+
+
+
+ )}
+ />
+
+
+
+ (
+
+
+ {t("rewritePath")}
+
+ {
+ field.onChange(
+ config.rewritePath ||
+ null
+ );
+ form.setValue(
+ "rewritePathType",
+ (config.rewritePathType as
+ | "exact"
+ | "prefix"
+ | "regex"
+ | "stripPrefix"
+ | null) ??
+ null
+ );
+ }}
+ trigger={
+ hasRewrite ? (
+
+ ) : (
+
+ )
+ }
+ />
+
+ {t(
+ "redirectRewritePathDescription"
+ )}
+
+
+
+ )}
+ />
+
+
+
+
+
+