본문으로 건너뛰기

셀프 호스팅 웹 앱sha-a14f8a5

Corkboard

HTML이나 동영상 하나를 올리고, 정한 주소로 다시 엽니다.

Corkboard는 자기 완결형 HTML 파일이나 동영상 하나를 올리면 /a/{slug} 주소로 열어 주는 셀프 호스팅 웹 앱입니다. 사람은 웹 폼으로 올리고, Claude Code나 Codex 같은 에이전트는 MCP 도구로 HTML 아티팩트를 만들고 고칩니다.

메타데이터는 MongoDB에, 파일은 S3 호환 스토리지의 비공개 버킷에 둡니다. 로그인 기능이 없어서 이 앱에 접속할 수 있는 사람은 누구나 아티팩트를 만들고 고치고 지울 수 있습니다. 그래서 루프백이나 신뢰할 수 있는 네트워크에서만 띄우거나, 인증을 거는 리버스 프록시 뒤에 두어야 합니다.

  • linux/arm64
  • MongoDB
  • S3 호환 스토리지
  • 출시
새 아티팩트 화면에서 HTML 파일을 고르고 제목, 설명, 주소를 입력해 올리자 상세 화면에서 바로 렌더되는 장면입니다. 데모용 로컬 인스턴스와 가상 데이터로 찍었습니다.

에이전트가 만든 HTML 리포트나 설명 페이지를 저마다의 링크로 모아 두고 다시 열어 보려는 개발자 가운데, MongoDB와 S3 호환 스토리지를 직접 준비할 수 있는 사람에게 맞습니다.

주요 기능

카드로 쌓이는 아티팩트 목록

올린 아티팩트는 최신순으로 한 페이지에 50개씩 카드로 쌓입니다. 카드마다 제목, 설명, 주소, 등록 시각, 파일 크기, 공개 구분 배지와 함께 열기, 수정 링크가 있습니다.

핀으로 꽂힌 카드 5장에 제목, 설명, /a/ 주소, 등록 시각, 파일 크기가 보이는 Corkboard 라이브러리 화면

파일 하나만 올리는 업로드

HTML(.html, .htm)이나 동영상(.mp4, .webm, .ogv) 파일 하나를 끌어다 놓거나 골라서 올리며, 기본 상한은 HTML 5.0MB, 동영상 50.0MB입니다. 제목을 입력하면 영문과 숫자에 무작위 접미사를 붙인 주소가 채워지고(한글만 있는 제목은 artifact-로 시작), 한 번 직접 고친 주소는 제목을 바꿔도 그대로 남습니다.

선택한 weekly-report.html 파일 카드 아래에 제목, 설명, 주소 weekly-report를 입력한 새 아티팩트 폼

격리해서 렌더하는 상세 화면

HTML은 allow-same-origin을 뺀 sandbox iframe 안에서 렌더하므로, 올린 HTML이 앱의 쿠키나 저장소에 접근하지 못합니다. 동영상은 브라우저 기본 플레이어로 재생하고, 헤더에서 새 탭으로 열거나 원본을 내려받습니다.

주간 배포 리포트 HTML이 헤더 아래에 렌더되고 새 탭에서 열기, 다운로드, 수정 버튼이 보이는 상세 화면

MCP로 붙는 에이전트

/mcp에서 list_artifacts, get_artifact, create_artifact, update_artifact, delete_artifact 도구 5종을 제공하며, MCP로는 HTML만 올릴 수 있습니다. MCP 연결 화면은 PUBLIC_BASE_URL로 만든 Claude Code와 Codex 등록 명령을 복사 버튼과 함께 보여 줍니다.

Claude Code와 Codex가 /mcp를 거쳐 corkboard, MongoDB, S3로 이어지는 연결도와 두 클라이언트의 등록 명령이 보이는 MCP 연결 화면
데모 인스턴스를 3300번 포트로 띄워 찍었습니다. 명령의 주소는 PUBLIC_BASE_URL을 따릅니다.

그 밖의 기능

  • REST API/api/artifacts에서 목록을 보고 multipart 요청으로 아티팩트를 만들며, /api/artifacts/{slug}에서 조회, multipart 수정, 삭제를 합니다. 오류 응답 본문은 { error: "slug_conflict" }처럼 error 필드 하나만 담습니다.
  • 파일 교체와 주소 변경수정 화면에서 파일을 HTML이나 동영상으로 바꿔 올리거나, 파일은 두고 제목, 설명, 주소, 공개 구분만 고칠 수 있습니다. 주소를 바꾸면 이전 주소는 404가 됩니다.
  • 내용까지 확인하는 업로드확장자만 믿지 않고 내용을 다시 확인합니다. HTML은 올바른 UTF-8인지와 앞부분의 HTML 태그를, 동영상은 앞부분 바이트의 컨테이너 형식을 보고 맞지 않으면 저장하지 않습니다.
  • 공개 구분 배지아티팩트마다 공개나 비공개 표시를 고르지만, 비공개 표시는 접근을 막지 않는 분류용 배지라서 비공개로 표시한 아티팩트도 목록에 나오고 주소로 열립니다.
  • 원본 내려받기상세 화면의 다운로드는 {slug}.html이나 {slug}.mp4처럼 저장된 형식의 확장자로 원본을 저장합니다.
  • 재생 위치를 옮길 수 있는 동영상서버가 Range 요청에 206으로 답하므로 브라우저는 필요한 구간만 받아 재생하고, 재생하지 못하는 형식이면 상세 화면이 안내 문구와 원본 내려받기 링크를 보여 줍니다.
  • 핀과 파쇄 연출업로드하면 파일 카드에 핀이 꽂히고 삭제하면 종이가 잘려 떨어지며, OS에서 동작 줄이기를 켜면 이 연출을 모두 생략합니다.
  • 되돌릴 수 없는 삭제웹 화면의 삭제는 확인 버튼을 한 번 더 눌러야 실행되지만, REST API와 MCP의 삭제는 확인 없이 바로 실행되며 어느 쪽이든 되돌릴 수 없습니다.

이미지 받기와 실행

Docker로 실행

docker run -d --name corkboard --network corkboard -p 127.0.0.1:3000:3000 \
-e MONGODB_URI=mongodb://mongo:27017/corkboard \
-e S3_ENDPOINT=http://minio:9000 \
-e S3_BUCKET=corkboard \
-e S3_ACCESS_KEY_ID=<access-key> \
-e S3_SECRET_ACCESS_KEY=<secret-key> \
-e PUBLIC_BASE_URL=http://127.0.0.1:3000 \
cludseo/corkboard:sha-a14f8a5
  1. MongoDB와 S3 호환 스토리지를 사용자 정의 네트워크(예: docker network create corkboard)에 띄우고, 스토리지에 비공개 버킷을 만듭니다. 앱은 버킷을 만들지 않습니다.
  2. 위 명령의 네트워크와 환경변수를 바꿔 컨테이너를 실행합니다. MongoDB와 스토리지 주소는 같은 네트워크의 컨테이너 이름처럼 컨테이너 안에서 닿는 주소여야 하며, 127.0.0.1 같은 호스트 루프백 주소를 넣으면 컨테이너는 뜨지만 요청이 실패합니다.
  3. http://127.0.0.1:3000에서 목록 화면이 뜨는지 확인하고, /new에서 파일 하나를 올려 상세 화면이 렌더되는지 확인합니다.
  4. (선택) 에이전트를 연결하려면 앱의 MCP 연결 화면에 나온 명령으로 /mcp를 등록합니다.

새 이미지를 받은 뒤 같은 환경변수로 컨테이너를 다시 만듭니다. latest는 main 브랜치의 최신 빌드이고, 버전을 고정하려면 sha-<commit> 태그를 씁니다.

다른 앱