테마 전환

Workers + KV 스토리지로 자체 단축 URL 서비스 구축하기: 입문부터 실전까지

Easton editorial illustration: lifecycle journey rail

왜 자체 단축 URL 서비스를 구축했을까요?

한 서드파티 단축 URL 서비스를 거의 2년 동안 사용했습니다. 그런데 어느 날 아침 모든 단축 URL이 작동하지 않는다는 사실을 발견했습니다. 서비스 제공자가 갑자기 종료를 발표하면서 소셜 미디어에 공유했던 수백 개의 링크가 404로 바뀐 것입니다.

그때 데이터는 직접 관리하고 원하는 대로 기능을 바꿀 수 있으며 서드파티 서비스 종료도 걱정하지 않아도 되는, 완전히 제 소유인 단축 URL 서비스를 만들 수 없을까 생각했습니다.

그러다 Cloudflare Workers + KV 스토리지가 이 요구에 아주 잘 맞는다는 사실을 알게 되었습니다.

  • 무료 한도가 매우 넉넉합니다(하루 10만 건 요청).
  • 전 세계 200개 이상의 노드 덕분에 접속 속도가 매우 빠릅니다.
  • 배포가 간단해 코드 몇 줄이면 실행할 수 있습니다.
  • 데이터를 완전히 통제하고 원하는 만큼 오래 보관할 수 있습니다.

이 글에서는 사용자 지정 단축 코드와 방문 통계 등의 기능을 포함해 Workers + KV로 자체 단축 URL 서비스를 구축한 과정을 공유합니다. 코드도 모두 제공하므로 그대로 따라 하면 30분 정도면 서비스를 공개할 수 있습니다.

왜 Workers + KV를 선택했을까요?

Cloudflare Workers란?

간단히 말하면 Workers는 Cloudflare 엣지 네트워크에서 실행되는 Serverless 함수입니다. 코드를 작성하면 전 세계 200개 이상의 노드에 자동으로 배포되고, 사용자가 접속할 때 가장 가까운 노드로 자동 라우팅되어 지연 시간이 매우 짧습니다.

특히 무료 한도가 매우 넉넉합니다.

  • 하루 10만 건 요청
  • 요청당 CPU 시간 10ms
  • 개인이나 소규모 팀이 사용하기에는 대부분 충분함

KV 스토리지의 장점

KV(Key-Value) 스토리지는 엣지 컴퓨팅에 최적화된 Cloudflare의 분산 키-값 데이터베이스입니다.

  • 매우 빠른 읽기: 데이터가 엣지 노드에 캐시되어 중앙값이 12ms입니다.
  • 글로벌 동기화: 쓰기 후 60초 안에 전 세계 모든 노드로 동기화됩니다.
  • 무료 한도: 하루 10만 건 읽기와 1,000건 쓰기를 제공합니다.

KV는 단축 URL 서비스에 특히 잘 맞습니다.

  • 단축 코드를 key로, 원본 URL을 value로 사용합니다.
  • 쓰기보다 읽기가 훨씬 많은 구조입니다(단축 URL 생성은 적고 방문은 많음).
  • 전 세계에 분산되어 어디서 접속해도 빠릅니다.
하루 10만 건
무료 한도
하루 10만 건 요청
12ms
KV 읽기 속도
중앙값, 데이터는 엣지 노드에 캐시됨
200+
글로벌 노드
매우 빠른 접속 속도

서드파티 단축 URL 서비스와 비교

특성서드파티 단축 URL자체 Workers + KV
데이터 통제데이터가 서드파티에 있음완전히 통제 가능
사용자 지정기능이 고정됨자유롭게 변경 가능
안정성서비스가 종료될 수 있음Cloudflare 인프라 사용
광고중간 페이지가 있을 수 있음광고 없음
비용유료일 수 있음기본적으로 무료
접속 속도서비스 제공자에 따라 다름글로벌 엣지 네트워크

처음부터 단축 URL 서비스 구축하기

이론은 이 정도로 마치고 직접 만들어 보겠습니다.

사전 준비

1. Cloudflare 계정 등록

cloudflare.com에서 계정을 등록합니다. 무료 계정이면 충분합니다.

2. Wrangler CLI 설치

Wrangler는 Workers 프로젝트를 관리하는 Cloudflare 공식 명령줄 도구입니다.

npm install -g wrangler
# 또는 yarn 사용
yarn global add wrangler

설치가 끝나면 Cloudflare 계정에 로그인합니다.

wrangler login

브라우저가 열리면 권한을 승인합니다.

3. 프로젝트 생성

mkdir my-shortlink
cd my-shortlink
wrangler init

안내에 따라 JavaScript 프로젝트를 생성합니다. 물론 TypeScript를 선택해도 됩니다.

Step 1: KV 네임스페이스 생성

KV 스토리지를 사용하려면 먼저 ‘네임스페이스’(Namespace)를 만들어야 합니다. 데이터베이스의 테이블 하나라고 생각하면 됩니다.

다음 명령을 실행합니다.

# 프로덕션 환경용 KV 네임스페이스 생성
wrangler kv namespace create SHORTLINKS
# 프리뷰 환경용 KV 네임스페이스 생성(로컬 테스트용)
wrangler kv namespace create SHORTLINKS --preview

명령을 실행하면 다음과 비슷한 두 개의 ID가 반환됩니다.

{ binding = "SHORTLINKS", id = "abc123..." }
{ binding = "SHORTLINKS", preview_id = "def456..." }

중요: 이 두 ID를 기록해 두어야 합니다. 곧 설정에 사용합니다.

이제 wrangler.toml 파일을 편집하고 KV 바인딩을 추가합니다.

name = "my-shortlink"
main = "src/index.js"
compatibility_date = "2025-12-01"
# KV 네임스페이스 바인딩
kv_namespaces = [
  { binding = "SHORTLINKS", id = "你的 production ID", preview_id = "你的 preview ID" }
]

여기서 binding = "SHORTLINKS"는 코드에서 env.SHORTLINKS를 통해 이 KV 스토리지에 접근한다는 의미입니다.

Step 2: 기본 단축 URL 기능 구현

이제 핵심 코드를 작성합니다. src/index.js를 열고 다음 내용을 입력합니다.

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const path = url.pathname.slice(1); // 去掉开头的 /
    // 处理根路径
    if (path === '') {
      return new Response('欢迎使用短链服务!', { status: 200 });
    }
    // GET 请求:短链重定向
    if (request.method === 'GET') {
      // 从 KV 中查询短码对应的原始 URL
      const targetUrl = await env.SHORTLINKS.get(path);
      if (targetUrl) {
        // 找到了,301 重定向
        return Response.redirect(targetUrl, 301);
      } else {
        // 没找到,返回 404
        return new Response('短链不存在', { status: 404 });
      }
    }
    // POST 请求:创建短链
    if (request.method === 'POST') {
      try {
        const body = await request.json();
        const { url: targetUrl, code } = body;
        // 基本校验
        if (!targetUrl) {
          return new Response('缺少 url 参数', { status: 400 });
        }
        // 生成短码
        const shortCode = code || generateRandomCode();
        // 检查短码是否已存在
        const existing = await env.SHORTLINKS.get(shortCode);
        if (existing) {
          return new Response('短码已存在', { status: 409 });
        }
        // 存入 KV
        await env.SHORTLINKS.put(shortCode, targetUrl);
        // 返回结果
        return new Response(JSON.stringify({
          shortCode,
          shortUrl: `${url.origin}/${shortCode}`,
          targetUrl
        }), {
          status: 201,
          headers: { 'Content-Type': 'application/json' }
        });
      } catch (error) {
        return new Response('请求格式错误', { status: 400 });
      }
    }
    // 其他请求方法不支持
    return new Response('方法不允许', { status: 405 });
  }
};
// 生成随机短码(6位字母数字组合)
function generateRandomCode(length = 6) {
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  let code = '';
  for (let i = 0; i < length; i++) {
    code += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return code;
}

코드 설명:

  1. GET 요청: 사용자가 yourdomain.com/abc123에 접속하면 KV에서 abc123에 대응하는 원본 URL을 조회한 뒤 301로 리디렉션합니다.
  2. POST 요청: url과 선택 사항인 code 매개변수를 받습니다. code가 없으면 무작위로 생성한 뒤 KV에 저장합니다.
  3. generateRandomCode: 영문 대소문자와 숫자를 조합한 6자리 무작위 코드를 생성합니다.

Step 3: 로컬 테스트

코드를 작성했으면 먼저 로컬에서 테스트합니다.

wrangler dev

로컬 서버가 시작되며, 일반적으로 주소는 http://localhost:8787입니다.

단축 URL 생성 테스트:

curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

반환값:

{
  "shortCode": "aBc123",
  "shortUrl": "http://localhost:8787/aBc123",
  "targetUrl": "https://example.com"
}

단축 URL 방문 테스트:

브라우저에서 http://localhost:8787/aBc123를 열면 https://example.com으로 리디렉션되어야 합니다.

정상적으로 작동한다면 기본 기능 구현이 완료된 것입니다.

Step 4: 사용자 지정 단축 코드 지원

위 코드는 이미 사용자 지정 단축 코드를 지원합니다. POST 요청에 code 매개변수를 추가하면 됩니다.

curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "code": "my-link"}'

더 견고하게 만들려면 몇 가지 검증을 추가할 수 있습니다.

// 在 POST 请求处理部分,生成短码之前加上这段
// 如果用户提供了自定义短码,校验格式
if (code) {
  // 只允许字母、数字、连字符
  if (!/^[a-zA-Z0-9-]+$/.test(code)) {
    return new Response('短码格式不正确(仅支持字母、数字、连字符)', { status: 400 });
  }
  // 长度限制
  if (code.length < 3 || code.length > 20) {
    return new Response('短码长度必须在 3-20 之间', { status: 400 });
  }
}

이제 특수 문자가 포함되거나 지나치게 긴 단축 코드를 만들지 못하도록 막을 수 있습니다.

Step 5: 방문 통계 구현

단축 URL 기능만 필요한 것이 아니라 각 링크가 몇 번 방문되었는지도 알고 싶을 때가 많습니다.

구현 방식:

  • 단축 URL을 방문할 때 리디렉션만 하지 않고 방문 횟수도 1 증가시킵니다.
  • 통계 데이터도 KV에 저장하며 key 형식은 stats:{shortCode}로 정합니다.

GET 요청 처리 코드를 다음과 같이 수정합니다.

// GET 请求:短链重定向
if (request.method === 'GET') {
  const targetUrl = await env.SHORTLINKS.get(path);
  if (targetUrl) {
    // 异步更新访问统计(不阻塞重定向)
    const statsKey = `stats:${path}`;
    // 后台更新统计,不影响重定向速度
    env.SHORTLINKS.get(statsKey).then(count => {
      const newCount = (parseInt(count) || 0) + 1;
      env.SHORTLINKS.put(statsKey, newCount.toString());
    });
    return Response.redirect(targetUrl, 301);
  } else {
    return new Response('短链不存在', { status: 404 });
  }
}

통계 조회 API 추가:

// 在 GET 请求处理前,加上这个判断
if (path.startsWith('stats/')) {
  const shortCode = path.slice(6); // 去掉 stats/ 前缀
  const statsKey = `stats:${shortCode}`;
  const count = await env.SHORTLINKS.get(statsKey);
  return new Response(JSON.stringify({
    shortCode,
    visits: parseInt(count) || 0
  }), {
    headers: { 'Content-Type': 'application/json' }
  });
}

이제 http://localhost:8787/stats/abc123에 접속해 특정 단축 URL의 방문 횟수를 조회할 수 있습니다.

주의: KV는 원자적 연산을 지원하지 않으므로 동시 요청이 많으면 방문 통계가 정확하지 않을 수 있습니다. 정확한 통계가 필요하다면 Durable Objects를 사용해야 합니다. 하지만 대부분의 개인 용도에는 이 방식으로 충분합니다.

Step 6: 프로덕션 환경에 배포

테스트에 문제가 없다면 Cloudflare의 글로벌 네트워크에 배포할 수 있습니다.

wrangler deploy

배포에 성공하면 Wrangler가 https://my-shortlink.your-subdomain.workers.dev와 비슷한 URL을 알려 줍니다.

이 URL이 전 세계에서 빠르게 접속할 수 있는 단축 URL 서비스 주소입니다.

사용자 지정 도메인 연결(선택 사항):

자체 도메인(예: short.example.com)이 있다면 Cloudflare Dashboard에서 연결할 수 있습니다.

  1. Workers & Pages 페이지로 이동합니다.
  2. 해당 Worker를 선택합니다.
  3. Settings > Triggers를 클릭합니다.
  4. Custom Domain을 추가합니다.

연결한 뒤에는 https://short.example.com/abc123처럼 자체 도메인으로 단축 URL에 접속할 수 있습니다.

고급 기능

기본 기능을 완성한 뒤에는 다음과 같은 기능도 추가할 수 있습니다.

1. 단축 URL 일괄 생성

한 번에 여러 단축 URL을 만들어야 할 때는 일괄 처리 API를 추가할 수 있습니다.

// 在 POST 请求处理部分,添加批量创建逻辑
if (request.method === 'POST' && url.pathname === '/batch') {
  try {
    const body = await request.json();
    const links = body.links; // 格式:[{url, code?}, ...]
    if (!Array.isArray(links)) {
      return new Response('links 必须是数组', { status: 400 });
    }
    const results = [];
    for (const link of links) {
      const { url: targetUrl, code } = link;
      const shortCode = code || generateRandomCode();
      // 检查是否已存在
      const existing = await env.SHORTLINKS.get(shortCode);
      if (!existing) {
        await env.SHORTLINKS.put(shortCode, targetUrl);
        results.push({ shortCode, targetUrl, success: true });
      } else {
        results.push({ shortCode, targetUrl, success: false, error: '短码已存在' });
      }
    }
    return new Response(JSON.stringify({ results }), {
      headers: { 'Content-Type': 'application/json' }
    });
  } catch (error) {
    return new Response('请求格式错误', { status: 400 });
  }
}

호출 방법:

curl -X POST http://localhost:8787/batch \
  -H "Content-Type: application/json" \
  -d '{
    "links": [
      {"url": "https://example1.com", "code": "link1"},
      {"url": "https://example2.com"}
    ]
  }'

2. 만료 시간 설정

KV는 TTL(Time To Live)을 지원하므로 단축 URL을 자동으로 만료시킬 수 있습니다.

// 在存入 KV 时,添加 expirationTtl 参数
await env.SHORTLINKS.put(shortCode, targetUrl, {
  expirationTtl: 86400 // 24小时后自动删除,单位:秒
});

사용자가 만료 시간을 직접 지정하게 하려면 다음과 같이 작성합니다.

const { url: targetUrl, code, ttl } = body;
const options = {};
if (ttl) {
  options.expirationTtl = parseInt(ttl);
}
await env.SHORTLINKS.put(shortCode, targetUrl, options);

3. 접근 제어

누구나 단축 URL을 만들지 못하게 하려면 간단한 API Token 인증을 추가할 수 있습니다.

// 在 wrangler.toml 里添加环境变量
# [vars]
# API_TOKEN = "your-secret-token"
// 在 POST 请求处理前,添加验证
if (request.method === 'POST') {
  const token = request.headers.get('Authorization');
  if (token !== `Bearer ${env.API_TOKEN}`) {
    return new Response('未授权', { status: 401 });
  }
  // ... 后续创建短链逻辑
}

호출할 때 token을 포함합니다.

curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-secret-token" \
  -d '{"url": "https://example.com"}'

4. 악용 방지(Rate Limiting)

누군가 악의적으로 단축 URL을 대량 생성하지 못하게 하려면 간단한 요청 제한을 추가할 수 있습니다.

// 使用 IP 地址作为限流标识
const clientIp = request.headers.get('CF-Connecting-IP');
const rateLimitKey = `ratelimit:${clientIp}`;
// 获取当前计数
const count = await env.SHORTLINKS.get(rateLimitKey);
if (parseInt(count) >= 10) {
  return new Response('请求过于频繁,请稍后再试', { status: 429 });
}
// 计数 +1,设置 1 小时过期
const newCount = (parseInt(count) || 0) + 1;
await env.SHORTLINKS.put(rateLimitKey, newCount.toString(), {
  expirationTtl: 3600 // 1小时
});

이 방법은 IP 하나당 한 시간에 최대 10개의 단축 URL만 만들도록 제한합니다.

성능 최적화와 모범 사례

성능 최적화 방법

1. 캐시 전략

KV 읽기는 이미 중앙값 12ms로 빠르지만, 더 빠르게 만들고 싶다면 Worker 메모리에 캐시 계층을 하나 추가할 수 있습니다.

// 使用 Map 作为简单的内存缓存
const cache = new Map();
const targetUrl = cache.get(path) || await env.SHORTLINKS.get(path);
if (targetUrl) {
  cache.set(path, targetUrl);
  return Response.redirect(targetUrl, 301);
}

다만 Worker 메모리는 영구 저장되지 않으므로 재시작하면 데이터가 사라집니다.

2. KV 쓰기 횟수 줄이기

KV의 무료 쓰기 한도는 하루 1,000건이므로 방문 통계를 너무 자주 기록하면 한도를 초과할 수 있습니다.

해결 방법:

  • 원자적 연산을 지원하는 Durable Objects로 통계를 처리합니다.
  • N회 방문할 때마다 한 번만 KV에 기록합니다.
  • Cloudflare Analytics Engine을 사용합니다.

3. CORS 설정

프론트엔드에서 단축 URL 서비스를 호출한다면 CORS 헤더를 추가해야 합니다.

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type',
};
// OPTIONS 请求处理
if (request.method === 'OPTIONS') {
  return new Response(null, { headers: corsHeaders });
}
// 在返回响应时添加 CORS 头
return new Response(body, {
  headers: { ...headers, ...corsHeaders }
});

비용 관리

Cloudflare Workers의 무료 한도는 매우 넉넉하지만 다음 사항은 알아 두어야 합니다.

무료 한도:

  • 하루 10만 건 요청
  • KV 하루 10만 건 읽기와 1,000건 쓰기
  • 요청당 CPU 시간 10ms

무료 한도 초과 비용(월 $5부터 시작하는 Workers Paid 요금제):

  • 요청 100만 건당 $0.50
  • KV 읽기 100만 건당 $0.50
  • KV 쓰기 100만 건당 $5.00
  • KV 스토리지 월 GB당 $0.50

개인 용도로는 무료 한도를 넘는 일이 거의 없습니다. 소규모 팀도 하루 수만 건 정도의 방문이라면 충분히 사용할 수 있습니다.

요청 수를 절약하는 방법:

  • 브라우저가 캐시하는 301 리디렉션을 302 대신 사용합니다.
  • 관리 페이지 같은 정적 리소스는 Worker 요청 수를 소모하지 않는 Workers Pages에 호스팅합니다.
  • TTL을 적절히 설정해 만료 링크를 자동 정리합니다.

보안 고려 사항

1. 악성 단축 URL 방지

단축 URL 서비스를 외부에 공개하면 누군가 악성 사이트 링크를 줄이는 데 악용할 수 있습니다.

권장 사항:

  • API Token 인증을 추가합니다.
  • 블랙리스트로 알려진 악성 도메인을 필터링합니다.
  • 생성자 IP를 기록해 추적할 수 있게 합니다.

2. 단축 코드 충돌 방지

영문 대소문자와 숫자를 조합한 6자리 코드는 62^6 ≈ 568억 가지이므로 충돌 확률이 낮지만, 그래도 반드시 확인해야 합니다.

// 创建短链时,检查是否已存在
const existing = await env.SHORTLINKS.get(shortCode);
if (existing) {
  return new Response('短码已存在', { status: 409 });
}

3. 대상 URL 제한

화이트리스트를 추가해 특정 도메인으로만 리디렉션하도록 제한할 수 있습니다.

const allowedDomains = ['example.com', 'mywebsite.com'];
const targetDomain = new URL(targetUrl).hostname;
if (!allowedDomains.some(d => targetDomain.endsWith(d))) {
  return new Response('不允许的目标域名', { status: 403 });
}

실제 사용 경험

구축을 마친 뒤 몇 달 동안 사용해 보았습니다. 실제로 느낀 점은 다음과 같습니다.

장점:

  • 매우 빠름: 전 세계 접속 지연이 대부분 50ms 이내로, 이전에 쓰던 서드파티 서비스보다 훨씬 빠릅니다.
  • 안정적임: Cloudflare 네트워크가 매우 안정적이라 장애를 거의 겪지 않았습니다.
  • 관리가 편함: 배포 후 별도로 관리할 일이 거의 없고 자동으로 확장되어 트래픽 급증도 걱정할 필요가 없습니다.
  • 무료임: 하루 요청 수가 수천 건 정도라 무료 한도 안에서 충분히 사용하고 있습니다.

아쉬운 점:

  • KV 쓰기 지연: KV는 최종 일관성 모델이라 쓰기 후 전 세계 동기화까지 수십 초가 걸릴 수 있습니다. 하지만 단축 URL을 만든 직후 바로 방문하는 경우는 드물어 이 용도에는 영향이 크지 않습니다.
  • 통계가 정확하지 않음: KV는 원자적 연산을 지원하지 않아 동시 요청이 많으면 통계에 오차가 생길 수 있습니다. 정확한 통계가 필요하다면 Durable Objects를 사용해야 하지만 무료 한도를 넘으면 비용이 조금 더 듭니다.

향후 계획:

  • Workers Pages로 간단한 Dashboard를 만들어 단축 URL을 시각적으로 관리합니다.
  • Cloudflare Analytics를 연동해 유입 경로와 지역 등 상세 방문 데이터를 확인합니다.
  • 오프라인 공유에 편리하도록 QR 코드 생성 기능을 추가합니다.

마무리

Cloudflare Workers + KV로 단축 URL 서비스를 구축하면 빠르고 비용도 거의 들지 않습니다. 핵심 코드는 100줄이 채 되지 않고 명령 한 번이면 배포할 수 있으며, 무엇보다 데이터를 완전히 직접 관리하므로 서드파티 서비스 종료를 걱정할 필요가 없습니다.

비슷한 요구가 있다면 직접 시도해 보기를 권합니다. 코드를 모두 제공했으니 그대로 작성해 보면 30분 안에 공개할 수 있습니다.

핵심 단계 요약:

  1. Cloudflare 계정을 등록하고 Wrangler를 설치합니다.
  2. KV 네임스페이스를 만들고 wrangler.toml을 설정합니다.
  3. GET(리디렉션)과 POST(단축 URL 생성) 요청을 처리하는 코드를 작성합니다.
  4. 로컬에서 테스트한 뒤 프로덕션에 배포합니다.

그다음 통계, 일괄 생성, 만료 시간 같은 기능을 하나씩 추가할 수 있습니다. 코드가 직접 관리하는 영역에 있으므로 원하는 대로 바꿀 수 있다는 점이 가장 큰 장점입니다.

궁금한 점은 댓글로 남겨 주세요. 여러분도 자신만의 단축 URL 서비스를 성공적으로 구축하기 바랍니다!

Cloudflare Workers + KV로 자체 단축 URL 서비스를 구축하는 전체 과정

단축 URL 생성, 리디렉션, 방문 통계 기능을 갖춘 서비스를 처음부터 구축해 30분 안에 공개합니다

⏱️ Estimated time: 30 min

  1. 1

    Step 1: 사전 준비: Cloudflare 계정 등록 및 Wrangler CLI 설치

    1단계: Cloudflare 계정 등록
    • cloudflare.com에서 계정을 등록합니다. 무료 계정이면 충분합니다

    2단계: Wrangler CLI 설치
    • Wrangler는 Workers 프로젝트를 관리하는 Cloudflare 공식 명령줄 도구입니다
    • 실행: npm install -g wrangler
    • 또는 실행: yarn global add wrangler
    • 설치가 끝나면 Cloudflare 계정에 로그인합니다: wrangler login
    • 브라우저가 열리면 권한을 승인합니다

    3단계: 프로젝트 생성
    • mkdir my-shortlink
    • cd my-shortlink
    • wrangler init
    • 안내에 따라 JavaScript 프로젝트를 생성합니다. 물론 TypeScript를 선택해도 됩니다
  2. 2

    Step 2: KV 네임스페이스 생성 및 wrangler.toml 설정

    KV 네임스페이스 생성:

    방법 1: Cloudflare Dashboard에서 생성
    • Workers & Pages → KV로 이동합니다
    • Create a namespace를 클릭합니다
    • 이름(예: SHORTLINKS)을 입력하고 생성합니다

    방법 2: 명령줄에서 생성
    • wrangler kv:namespace create SHORTLINKS

    wrangler.toml 설정:
    wrangler.toml 파일을 열고 끝에 KV 바인딩 설정을 추가합니다:

    [[kv_namespaces]]
    binding = "SHORTLINKS"
    id = "네임스페이스 ID"

    이제 코드에서 env.SHORTLINKS로 KV에 접근할 수 있습니다
  3. 3

    Step 3: 핵심 코드 작성: 단축 URL 생성과 리디렉션 기능

    핵심 기능 구현:

    1. 단축 코드 생성:
    • 사용자 지정 단축 코드와 무작위 생성을 모두 지원합니다
    • 영문 대소문자와 숫자를 조합한 6자리 코드를 사용할 수 있습니다
    • 가능한 조합이 62^6≈568억 개이므로 충돌 확률이 매우 낮습니다

    2. KV에 저장:
    • 단축 코드를 key로, 원본 URL을 value로 저장합니다
    • 생성 시간과 방문 횟수 등의 metadata도 저장할 수 있습니다

    3. 리디렉션:
    • GET 요청이 오면 KV에서 원본 URL을 읽습니다
    • 원본 URL로 302 리디렉션을 반환합니다

    4. 방문 통계:
    • 방문 횟수와 시간을 기록합니다
    • KV의 metadata에 저장할 수 있습니다

    코드 예시:
    • GET 요청 처리(리디렉션): URL 경로에서 단축 코드를 가져와 KV에서 원본 URL을 읽고, 값이 있으면 302 리디렉션을, 없으면 404를 반환합니다
    • POST 요청 처리(단축 URL 생성): 원본 URL과 선택 사항인 사용자 지정 단축 코드를 받아 코드를 생성하고, 기존 코드와 충돌하는지 확인한 뒤 KV에 저장하고 단축 URL을 반환합니다
  4. 4

    Step 4: 로컬 테스트 및 프로덕션 배포

    로컬 테스트:

    1. wrangler dev를 실행해 로컬 개발 서버를 시작합니다
    2. 단축 URL 생성과 리디렉션 기능을 테스트합니다

    curl로 테스트할 수 있습니다:
    • 단축 URL 생성:
    curl -X POST http://localhost:8787/create -H "Content-Type: application/json" -d '{"url":"https://example.com"}'

    • 단축 URL 방문:
    curl -L http://localhost:8787/abc123
    (원본 URL로 리디렉션됩니다)

    프로덕션 배포:
    • 실행: wrangler deploy
    • Wrangler가 Worker를 Cloudflare에 자동으로 배포합니다
    • 배포에 성공하면 다음 형식의 URL이 표시됩니다:
    your-worker-name.your-subdomain.workers.dev
    • 이제 단축 URL 서비스가 공개되었습니다!
  5. 5

    Step 5: 고급 기능과 보안 고려 사항

    고급 기능: 1) 방문 통계(방문 횟수와 시간을 기록하고 KV의 metadata에 저장하며 방문할 때마다 수치를 갱신); 2) 만료 시간(단축 URL에 만료 시간을 설정해 자동으로 비활성화); 3) 일괄 생성(한 번에 여러 단축 URL 생성); 4) 관리 화면(Workers Pages로 간단한 Dashboard를 구축해 단축 URL을 시각적으로 관리). 보안 고려 사항: 1) 악성 단축 URL 방지(API Token 인증 추가, 알려진 악성 도메인을 블랙리스트로 필터링, 생성자 IP를 기록해 추적 가능하게 함); 2) 단축 코드 충돌 방지(영문 대소문자와 숫자를 조합한 6자리 코드는 62^6≈568억 가지로 충돌 확률이 낮지만, 생성할 때 기존 코드인지 반드시 확인); 3) 대상 URL 제한(화이트리스트를 두어 특정 도메인으로만 리디렉션 허용). 요청 수를 절약하는 방법: 브라우저가 캐시하는 301 리디렉션을 302 대신 사용하고, 관리 페이지 같은 정적 리소스는 Worker 요청 수를 소모하지 않는 Workers Pages에 호스팅하며, TTL을 적절히 설정해 만료 링크를 자동 정리합니다.

FAQ

왜 자체 단축 URL 서비스를 구축해야 하나요? Workers + KV 조합의 장점은 무엇인가요?
서드파티 단축 URL 서비스가 갑자기 종료되면 수백 개의 링크가 한꺼번에 무효화될 수 있습니다. 자체 서비스를 구축하면 데이터를 완전히 통제하고 원하는 대로 기능을 바꿀 수 있으며, 서드파티 서비스 종료를 걱정할 필요가 없습니다.

Workers + KV 조합의 장점:
• 하루 10만 건의 넉넉한 무료 요청 한도
• 전 세계 200개 이상의 노드로 매우 빠른 접속 속도
• 코드 몇 줄이면 실행할 수 있는 간단한 배포
• 보관 기간까지 직접 정하는 완전한 데이터 통제

서드파티 단축 URL 서비스와 비교:
• 데이터 통제(서드파티는 데이터가 서비스 제공자에게 있고, 자체 구축은 완전히 통제 가능)
• 사용자 지정(서드파티는 기능이 고정되지만 자체 구축은 자유롭게 변경 가능)
• 안정성(서드파티는 종료될 수 있지만 자체 구축은 Cloudflare 인프라 사용)
• 광고(서드파티는 중간 페이지가 있을 수 있지만 자체 구축은 광고 없음)
• 비용(서드파티는 유료일 수 있지만 자체 구축은 기본적으로 무료)
• 접속 속도(서드파티는 제공자에 따라 다르지만 자체 구축은 글로벌 엣지 네트워크 사용)
KV 스토리지에는 어떤 장점이 있으며 왜 단축 URL 서비스에 적합한가요?
KV(Key-Value) 스토리지는 엣지 컴퓨팅에 최적화된 Cloudflare의 분산 키-값 데이터베이스입니다.

KV 스토리지의 장점:
• 데이터가 엣지 노드에 캐시되어 읽기 중앙값이 12ms로 매우 빠름
• 쓰기 후 60초 안에 전 세계 모든 노드로 동기화
• 하루 10만 건 읽기와 1,000건 쓰기의 무료 한도

단축 URL 서비스와 KV는 특히 잘 맞습니다:
• 단축 코드를 key로, 원본 URL을 value로 사용
• 쓰기보다 읽기가 많은 구조(생성 횟수는 적고 방문 횟수는 많음)
• 전 세계에 분산되어 어디서 접속해도 빠름

무료 한도:
• Workers 하루 10만 건 요청
• KV 하루 10만 건 읽기와 1,000건 쓰기
• 개인 용도로는 대부분 충분하며, 소규모 팀도 하루 수만 건의 방문을 처리할 수 있음

무료 한도 초과 비용(월 $5부터 시작하는 Workers Paid 요금제):
• 요청 100만 건당 $0.50
• KV 읽기 100만 건당 $0.50
• KV 쓰기 100만 건당 $5.00
• KV 스토리지 월 GB당 $0.50
처음부터 단축 URL 서비스를 구축하려면 어떤 단계를 거쳐야 하나요?
사전 준비:

1단계: Cloudflare 계정 등록(cloudflare.com에서 무료 계정 등록)
2단계: Wrangler CLI 설치(npm install -g wrangler 실행 후 wrangler login으로 로그인)
3단계: 프로젝트 생성(mkdir my-shortlink, cd my-shortlink, wrangler init)

KV 네임스페이스 생성 및 설정:
• Cloudflare Dashboard에서 Workers & Pages → KV로 이동하고 Create a namespace를 클릭한 뒤 이름(예: SHORTLINKS)을 입력해 생성합니다
• 또는 명령줄에서 wrangler kv:namespace create SHORTLINKS를 실행합니다

wrangler.toml 설정:
• wrangler.toml 파일을 열고 끝에 KV 바인딩 설정을 추가합니다
• 그러면 코드에서 env.SHORTLINKS로 KV에 접근할 수 있습니다

핵심 코드 작성:

GET 요청 처리(리디렉션):
• URL 경로에서 단축 코드를 가져옵니다
• KV에서 원본 URL을 읽습니다
• 값이 있으면 302 리디렉션을, 없으면 404를 반환합니다

POST 요청 처리(단축 URL 생성):
• 원본 URL과 선택 사항인 사용자 지정 단축 코드를 받습니다
• 사용자 지정 코드가 없으면 무작위로 생성합니다
• 단축 코드가 이미 존재하는지 확인해 충돌을 방지합니다
• KV에 저장하고 단축 URL을 반환합니다

로컬 테스트 및 배포:
• wrangler dev를 실행해 로컬 개발 서버를 시작하고 단축 URL 생성과 리디렉션을 테스트합니다
• wrangler deploy를 실행해 프로덕션에 배포합니다
단축 URL 서비스의 핵심 기능은 어떻게 구현하나요?
핵심 기능 구현:

1) 단축 코드 생성:
• 사용자 지정 단축 코드와 무작위 생성을 모두 지원합니다
• 영문 대소문자와 숫자를 조합한 6자리 코드는 62^6≈568억 가지이므로 충돌 확률이 매우 낮습니다

2) KV에 저장:
• 단축 코드를 key로, 원본 URL을 value로 저장합니다
• 생성 시간과 방문 횟수 같은 metadata도 저장할 수 있습니다

3) 리디렉션:
• GET 요청이 오면 KV에서 원본 URL을 읽습니다
• 원본 URL로 302 리디렉션을 반환합니다

4) 방문 통계:
• 방문 횟수와 시간을 기록합니다
• KV의 metadata에 저장하고 방문할 때마다 수치를 갱신할 수 있습니다

코드 예시:

GET 요청 처리(리디렉션):
• URL 경로에서 단축 코드를 가져옵니다
• KV에서 원본 URL을 읽습니다
• 값이 있으면 302 리디렉션을, 없으면 404를 반환합니다

POST 요청 처리(단축 URL 생성):
• 원본 URL과 선택 사항인 사용자 지정 단축 코드를 받습니다
• 사용자 지정 코드가 없으면 무작위로 생성합니다
• 기존 단축 코드인지 확인해 충돌을 방지합니다
• 단축 코드를 key로, 원본 URL을 value로 KV에 저장합니다
• 단축 URL을 반환합니다

고급 기능:
• 방문 통계(방문 횟수와 시간 기록)
• 만료 시간(단축 URL에 만료 시간을 설정해 자동 비활성화)
• 일괄 생성(한 번에 여러 단축 URL 생성)
• 관리 화면(Workers Pages로 Dashboard를 만들어 단축 URL을 시각적으로 관리)
단축 URL 서비스를 사용할 때 어떤 보안 사항을 고려해야 하나요?
보안 고려 사항:

1) 악성 단축 URL 방지:
• 서비스를 외부에 공개하면 악성 사이트 링크를 줄이는 데 악용될 수 있습니다
• 권장 사항:
- API Token 인증 추가
- 블랙리스트로 알려진 악성 도메인 필터링
- 생성자 IP를 기록해 추적 가능하게 함

2) 단축 코드 충돌 방지:
• 영문 대소문자와 숫자를 조합한 6자리 코드는 62^6≈568억 가지로 충돌 확률이 낮지만 반드시 확인해야 합니다
• 단축 URL을 만들 때 기존 코드인지 확인합니다:
const existing = await env.SHORTLINKS.get(shortCode);
if (existing) {
return new Response('短码已存在', { status: 409 });
}

3) 대상 URL 제한:
• 화이트리스트를 추가해 특정 도메인으로만 리디렉션하도록 제한할 수 있습니다:
const allowedDomains = ['example.com', 'mywebsite.com'];
const targetDomain = new URL(targetUrl).hostname;
if (!allowedDomains.some(d => targetDomain.endsWith(d))) {
return new Response('不允许的目标域名', { status: 403 });
}

요청 수를 절약하는 방법:
• 브라우저가 캐시하는 301 리디렉션을 302 대신 사용합니다
• 관리 페이지 같은 정적 리소스는 Worker 요청 수를 소모하지 않는 Workers Pages에 호스팅합니다
• TTL을 적절히 설정해 만료 링크를 자동 정리합니다
실제로 사용해 보면 어떤가요? 장단점은 무엇인가요?
실제 사용 경험:

장점:
• 매우 빠름(전 세계 접속 지연이 대부분 50ms 이내로, 이전에 쓰던 서드파티 서비스보다 훨씬 빠름)
• 안정적임(Cloudflare 네트워크가 매우 안정적이라 장애를 거의 겪지 않음)
• 관리가 편함(배포 후 별도 관리가 거의 필요 없고 자동으로 확장되어 트래픽 급증을 걱정할 필요가 없음)
• 무료임(하루 요청 수가 수천 건 정도라 무료 한도 안에서 충분히 사용 가능)

아쉬운 점:
• KV 쓰기 지연(KV는 최종 일관성 모델이라 쓰기 후 전 세계 동기화까지 수십 초가 걸릴 수 있지만, 생성 직후 바로 방문하는 경우가 드문 단축 URL 서비스에는 영향이 크지 않음)
• 통계가 정확하지 않음(KV는 원자적 연산을 지원하지 않아 동시 요청이 많으면 통계에 오차가 생길 수 있음. 정확한 통계에는 Durable Objects가 필요하지만 무료 한도를 넘으면 비용이 더 듦)

향후 계획:
• Workers Pages로 간단한 Dashboard를 만들어 단축 URL을 시각적으로 관리
• Cloudflare Analytics를 연동해 유입 경로와 지역 등 상세 방문 데이터 확인
• 오프라인 공유에 편리하도록 QR 코드 생성 기능 추가

6분 읽기 · 게시일: 2025년 12월 1일 · 수정일: 2026년 9월 4일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog