diff --git a/src/pages/forwarding/Edit.tsx b/src/pages/forwarding/Edit.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..68ae69e7ad4f8958acd706d55774d4861ec20523
--- /dev/null
+++ b/src/pages/forwarding/Edit.tsx
@@ -0,0 +1,182 @@
+import { z } from 'zod';
+import { useEffect, useState, useRef } from 'react';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { Link, useNavigate, useParams } from 'react-router';
+import { useForm } from 'react-hook-form';
+import { toast } from 'sonner';
+import { Skeleton } from '@/components/ui/skeleton';
+import { Button } from '@/components/ui/button';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
+import { Input } from '@/components/ui/input';
+import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
+import { useAuthStore } from '@/stores/authStore';
+
+const formSchema = z.object({
+  name: z.string({ required_error: '서버 이름을 입력해주세요' }).min(1, { message: '서버 이름을 입력해주세요' }),
+  serverPort: z
+    .number({ required_error: '도메인 주소를 입력해주세요' })
+    .min(20000, { message: '포트 번호는 20000 이상이어야 합니다' })
+    .max(29999, { message: '포트 번호는 29999 이하여야 합니다' }),
+  instanceIp: z
+    .string({ required_error: '인스턴스 IP를 입력해주세요' })
+    .regex(/^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/, {
+      message: '올바른 IP 주소를 입력해주세요',
+    })
+    .startsWith('10.16.', { message: '인스턴스 IP는 10.16.0.0/16 대역을 사용해야 합니다' }),
+});
+
+export default function ForwardingEdit() {
+  const navigate = useNavigate();
+  const { id } = useParams();
+  const { authFetch } = useAuthStore();
+  const form = useForm<z.infer<typeof formSchema>>({
+    resolver: zodResolver(formSchema),
+  });
+  const initialData = useRef<z.infer<typeof formSchema> | null>(null);
+  const [isLoading, setIsLoading] = useState(true);
+
+  useEffect(() => {
+    authFetch(`/api/forwarding?forwardingId=${id}`)
+      .then((response) => {
+        if (!response.ok) {
+          console.error(response);
+          throw Error();
+        }
+        return response.json();
+      })
+      .then(({ name, serverPort, instanceIp }) => {
+        initialData.current = { name, serverPort: parseInt(serverPort), instanceIp };
+        form.setValue('name', name);
+        form.setValue('serverPort', parseInt(serverPort));
+        form.setValue('instanceIp', instanceIp);
+        setIsLoading(false);
+      })
+      .catch((error) => {
+        console.error(error);
+        toast.error('포트포워딩 정보를 조회할 수 없습니다.');
+      });
+  });
+
+  async function onSubmit(values: z.infer<typeof formSchema>) {
+    if (!initialData.current) return;
+
+    const payload: Partial<z.infer<typeof formSchema>> = {};
+    if (values.name !== initialData.current.name) payload.name = values.name;
+    if (values.serverPort !== initialData.current.serverPort) payload.serverPort = values.serverPort;
+    if (values.instanceIp !== initialData.current.instanceIp) payload.instanceIp = values.instanceIp;
+
+    const response = await authFetch(`/api/forwarding?forwardingId=${id}`, {
+      method: 'PATCH',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify(payload),
+    });
+
+    if (!response.ok) {
+      console.error(response);
+
+      const { code } = await response.json();
+      if (code == 'DUPLICATED_INSTANCE_INFO') {
+        form.setError('instanceIp', { type: 'custom' });
+        toast.error('이미 존재하는 포트포워딩 설정입니다');
+      } else if (code == 'DUPLICATED_SERVER_PORT') {
+        form.setError('serverPort', { type: 'custom' });
+        toast.error('이미 사용 중인 포트 번호입니다');
+      } else {
+        toast.error('포트포워딩 설정 수정에 실패했습니다');
+      }
+    } else {
+      toast.success('포트포워딩 설정이 수정되었습니다');
+      navigate('/forwarding');
+    }
+  }
+
+  return (
+    <div className="flex flex-1 flex-col gap-4 p-6">
+      <div className="mb-2">
+        <h1 className="scroll-m-20 text-3xl font-semibold first:mt-0">포트포워딩 설정 수정</h1>
+        <p className="mt-1 text-base text-gray-500">기존 포트포워딩 설정을 수정합니다.</p>
+      </div>
+
+      <Form {...form}>
+        <form onSubmit={form.handleSubmit(onSubmit)}>
+          <Card className="mb-4">
+            <CardHeader>
+              {isLoading ? (
+                <Skeleton className="h-[1.75rem] w-[16rem]" />
+              ) : (
+                <CardTitle className="text-xl">SSH 포트포워딩 설정</CardTitle>
+              )}
+            </CardHeader>
+            <CardContent className="space-y-4">
+              {isLoading ? (
+                <Skeleton className="h-[16rem] w-full" />
+              ) : (
+                <div className="grid grid-cols-1 gap-4">
+                  <FormField
+                    control={form.control}
+                    name="name"
+                    render={({ field }) => (
+                      <FormItem>
+                        <FormLabel required>서버 이름</FormLabel>
+                        <FormControl>
+                          <Input placeholder="웹 서버 이름" {...field} />
+                        </FormControl>
+                        <FormMessage />
+                      </FormItem>
+                    )}
+                  />
+
+                  <FormField
+                    control={form.control}
+                    name="serverPort"
+                    render={({ field }) => (
+                      <FormItem>
+                        <FormLabel required>포트 번호</FormLabel>
+                        <FormControl>
+                          <Input
+                            type="number"
+                            min={20000}
+                            max={29999}
+                            placeholder="20000 ~ 29999"
+                            {...field}
+                            onChange={(e) => field.onChange(+e.target.value)}
+                          />
+                        </FormControl>
+                        <FormDescription>ssh.aoldacloud.com:&lt;포트번호&gt;로 접속 가능합니다</FormDescription>
+                        <FormMessage />
+                      </FormItem>
+                    )}
+                  />
+
+                  <FormField
+                    control={form.control}
+                    name="instanceIp"
+                    render={({ field }) => (
+                      <FormItem>
+                        <FormLabel required>인스턴스 IP</FormLabel>
+                        <FormControl>
+                          <Input placeholder="10.16.x.x" {...field} />
+                        </FormControl>
+                        <FormDescription>인스턴스 IP는 10.16.0.0/16 대역을 사용합니다</FormDescription>
+                        <FormMessage />
+                      </FormItem>
+                    )}
+                  />
+                </div>
+              )}
+            </CardContent>
+          </Card>
+
+          <div className="flex justify-end gap-2">
+            <Button variant="outline" asChild>
+              <Link to="..">취소</Link>
+            </Button>
+            <Button type="submit">저장</Button>
+          </div>
+        </form>
+      </Form>
+    </div>
+  );
+}
diff --git a/src/routes.tsx b/src/routes.tsx
index 1c837f082cfe76d0ad9175f703798abdba979009..22bf2419cc730017b230de187ccaf13b6e39721c 100644
--- a/src/routes.tsx
+++ b/src/routes.tsx
@@ -9,6 +9,7 @@ import CertificateList from './pages/certificate/List';
 import CertificateCreate from './pages/certificate/Create';
 import ForwardingList from '@/pages/forwarding/List';
 import ForwardingCreate from './pages/forwarding/Create';
+import ForwardingEdit from './pages/forwarding/Edit';
 
 export default function AppRoutes() {
   return (
@@ -27,6 +28,7 @@ export default function AppRoutes() {
         <Route path="forwarding">
           <Route index element={<ForwardingList />} />
           <Route path="create" element={<ForwardingCreate />} />
+          <Route path="edit/:id" element={<ForwardingEdit />} />
         </Route>
         <Route path="*" element={<NotFound />} />
       </Route>