diff --git a/app/client/modules/repositories/components/repository-forms/rest-repository-form.tsx b/app/client/modules/repositories/components/repository-forms/rest-repository-form.tsx
index 401b099c..e99e44ef 100644
--- a/app/client/modules/repositories/components/repository-forms/rest-repository-form.tsx
+++ b/app/client/modules/repositories/components/repository-forms/rest-repository-form.tsx
@@ -9,6 +9,8 @@ import {
} from "../../../../components/ui/form";
import { Input } from "../../../../components/ui/input";
import { SecretInput } from "../../../../components/ui/secret-input";
+import { Textarea } from "../../../../components/ui/textarea";
+import { Checkbox } from "../../../../components/ui/checkbox";
import type { RepositoryFormValues } from "../create-repository-form";
type Props = {
@@ -74,6 +76,43 @@ export const RestRepositoryForm = ({ form }: Props) => {
)}
/>
+ (
+
+ CA Certificate (Optional)
+
+
+
+
+ Custom CA certificate for self-signed certificates (PEM format). https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html#rest-server
+
+
+
+ )}
+ />
+ (
+
+
+
+
+
+ Skip TLS Certificate Verification
+
+ Disable TLS certificate verification. This is insecure and should only be used for testing. To trust a self-signed certificate without skipping verification, paste the CA certificate in the CA Certificate field.
+
+
+
+ )}
+ />
>
);
};
diff --git a/app/client/modules/repositories/tabs/info.tsx b/app/client/modules/repositories/tabs/info.tsx
index 64d641b9..c5b6697b 100644
--- a/app/client/modules/repositories/tabs/info.tsx
+++ b/app/client/modules/repositories/tabs/info.tsx
@@ -116,6 +116,30 @@ export const RepositoryInfoTabContent = ({ repository }: Props) => {
{repository.lastChecked ? new Date(repository.lastChecked).toLocaleString() : "Never"}
+ {repository.type === "rest" && (
+ <>
+
+
CA Certificate
+
+ {repository.config.cacert ? (
+ configured
+ ) : (
+ not configured
+ )}
+
+
+
+
TLS Certificate Validation
+
+ {repository.config.insecureTls ? (
+ disabled
+ ) : (
+ enabled
+ )}
+
+
+ >
+ )}
diff --git a/app/schemas/restic.ts b/app/schemas/restic.ts
index 0ae46710..1b41a5a7 100644
--- a/app/schemas/restic.ts
+++ b/app/schemas/restic.ts
@@ -68,6 +68,8 @@ export const restRepositoryConfigSchema = type({
username: "string?",
password: "string?",
path: "string?",
+ cacert: "string?",
+ insecureTls: "boolean?",
}).and(baseRepositoryConfigSchema);
export const sftpRepositoryConfigSchema = type({
diff --git a/app/server/modules/repositories/repositories.service.ts b/app/server/modules/repositories/repositories.service.ts
index cdd8bb1d..01b1983a 100644
--- a/app/server/modules/repositories/repositories.service.ts
+++ b/app/server/modules/repositories/repositories.service.ts
@@ -53,6 +53,9 @@ const encryptConfig = async (config: RepositoryConfig): Promise {
if (config.password) {
env.RESTIC_REST_PASSWORD = await cryptoUtils.resolveSecret(config.password);
}
+ if (config.cacert) {
+ const decryptedCert = await cryptoUtils.resolveSecret(config.cacert);
+ const certPath = path.join("/tmp", `rest-server-cacert-${crypto.randomBytes(8).toString("hex")}.pem`);
+ await fs.writeFile(certPath, decryptedCert, { mode: 0o600 });
+ env.RESTIC_CACERT = certPath;
+ }
+ if (config.insecureTls) {
+ env._REST_INSECURE_TLS = "true";
+ }
break;
}
case "sftp": {
@@ -876,6 +885,10 @@ export const cleanupTemporaryKeys = async (config: RepositoryConfig, env: Record
} else if (config.backend === "gcs" && env.GOOGLE_APPLICATION_CREDENTIALS) {
await fs.unlink(env.GOOGLE_APPLICATION_CREDENTIALS).catch(() => {});
}
+
+ if (config.backend === "rest" && env.RESTIC_CACERT) {
+ await fs.unlink(env.RESTIC_CACERT).catch(() => {});
+ }
};
export const addCommonArgs = (args: string[], env: Record) => {
@@ -884,6 +897,10 @@ export const addCommonArgs = (args: string[], env: Record) => {
if (env._SFTP_SSH_ARGS) {
args.push("-o", `sftp.args=${env._SFTP_SSH_ARGS}`);
}
+
+ if (env._REST_INSECURE_TLS === "true") {
+ args.push("--insecure-tls");
+ }
};
export const restic = {