diff --git a/.gitignore b/.gitignore
index 879cb66..bf77846 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules
.direnv
+.wrangler
CLAUDE.local.md
diff --git a/client/.env.preview b/client/.env.preview
index 831fe4f..3d69f54 100644
--- a/client/.env.preview
+++ b/client/.env.preview
@@ -1,2 +1,2 @@
-VITE_API_ENDPOINT=https://api.itsuhima-staging.utcode.net
+VITE_API_ENDPOINT=/api
VITE_FRONTEND_ORIGIN=https://itsuhima-staging.utcode.net
diff --git a/client/.env.production b/client/.env.production
index 3fdbb58..ae35cf5 100644
--- a/client/.env.production
+++ b/client/.env.production
@@ -1,2 +1,2 @@
-VITE_API_ENDPOINT=https://api.itsuhima.utcode.net
+VITE_API_ENDPOINT=/api
VITE_FRONTEND_ORIGIN=https://itsuhima.utcode.net
diff --git a/client/.gitignore b/client/.gitignore
index 438657a..fdc0972 100644
--- a/client/.gitignore
+++ b/client/.gitignore
@@ -13,6 +13,8 @@ dist-ssr
*.local
.env
+.wrangler
+
# Editor directories and files
.vscode/*
!.vscode/extensions.json
diff --git a/client/functions/api/[[path]].ts b/client/functions/api/[[path]].ts
new file mode 100644
index 0000000..db356f3
--- /dev/null
+++ b/client/functions/api/[[path]].ts
@@ -0,0 +1,26 @@
+///
+
+interface Env {
+ API_ENDPOINT: string;
+}
+
+// biome-ignore lint/suspicious/noExplicitAny: This is a Cloudflare Worker context
+export async function onRequest(context: EventContext): Promise {
+ const { request, env } = context;
+ const url = new URL(request.url);
+ const backendUrl = env.API_ENDPOINT + url.pathname.replace(/^\/api/, "") + url.search;
+
+ const proxied = new Request(backendUrl, {
+ method: request.method,
+ headers: request.headers,
+ body: request.method !== "GET" && request.method !== "HEAD" ? request.body : undefined,
+ redirect: "manual",
+ });
+
+ const response = await fetch(proxied);
+ return new Response(response.body, {
+ status: response.status,
+ statusText: response.statusText,
+ headers: response.headers,
+ });
+}