Hello, world
#notes2 min
2026-09-01
터널은 Cloudflare Tunnel이나 ngrok 같은 외부 서비스에 의존하지 않고 직접 구현했습니다. 도메인 발급과 인증서에는 Cloudflare를 사용합니다.
GitHub에서 코드 확인하기왜 필요한가
가정에 유휴 상태로 있는 컴퓨터, 사내망 안의 장비. 성능은 충분하지만 배포하려면 매번 서버 외부의 무언가를 변경해야 했습니다.
지금까지
공인 IP 구매
매달 발생하는 비용
포트포워딩
공유기 설정과 열린 포트
VPN 구축
또 하나의 운영 대상
외부 터널 서비스
외부 인프라에 대한 의존
OPTiCS
연결
사용자 서버가 외부로 먼저 연결합니다. 공유기 설정은 변경하지 않습니다.
배포
Git 저장소 URL을 입력하면 클론·빌드·기동까지 진행합니다.
주소
서비스마다 HTTPS 서브도메인이 자동으로 발급됩니다.
실행
컨테이너와 데이터는 사용자 서버에 유지됩니다.
기존의 네 가지 방식은 모두 서버 외부 설정을 변경하여 문제를 해결합니다. OPTiCS는 이러한 외부 설정 변경 없이 서비스를 운영할 수 있도록 지원합니다.
이용 방법
설치부터 첫 서비스 실행까지, 서버 외부 설정을 준비할 필요가 없습니다.
Agent를 설치할 호스트에서 스크립트를 실행합니다. Docker가 설치되어 있지 않으면 자동으로 설치됩니다.
Agent Dashboard가 열립니다
sh install-agent.sh
Agent Dashboard에 표시된 코드를 Console의 Workspace/Agent 화면에 입력합니다.
워크스페이스에 “연결 대기중”으로 표시
WORD-WORD 형식의 코드
Git 저장소 URL과 환경변수를 입력하고 배포를 실행합니다. 클론·빌드·컨테이너 시작은 Agent가 자동으로 처리합니다.
Running (3/3)
Dockerfile 또는 docker-compose 모드
코드를 입력해도 즉시 연결되지 않습니다. Agent Dashboard에 연결 요청이 표시되고, 이를 수락해야 연결이 성립합니다.
연결 방식
일반적으로 방화벽은 수신 연결을 차단하지만, 발신 연결은 허용합니다. 이에 따라 Hub가 Agent에 연결하는 대신 Agent가 Hub로 먼저 연결합니다. 명령은 이미 수립된 연결을 역방향으로 전달합니다.
터널 자체는 Cloudflare Tunnel이나 ngrok 같은 외부 서비스에 의존하지 않고 직접 구현했습니다. 연결이 외부 서비스에 종속되면 셀프호스팅의 의미가 훼손되기 때문입니다. 도메인 발급과 인증서는 Cloudflare를 사용합니다.
Agent는 유휴 소켓을 미리 열어 풀에 확보해 둡니다. 요청이 도착하면 Hub는 라우팅 정보만 제공하고, 프록시는 풀에서 소켓 하나를 꺼내 요청 바이트를 그대로 전달합니다. 이 경로에서는 Agent에게 명령이 전달되지 않습니다.
요약하면 — 공유기 설정을 변경하지 않아도 서비스가 외부에 공개됩니다. 서버는 계속 여러분의 소유로 남습니다.
왜 OPTiCS인가
외부 터널 서비스와 셀프호스팅 PaaS는 각각 이 문제의 일부를 해결합니다. 터널은 연결을 담당하고, PaaS는 배포를 자동화합니다. 아래 표는 어느 쪽이 우월하다는 주장이 아니라, 각 접근 방식이 무엇을 대가로 지불하는지를 정리한 것입니다.
외부 터널 서비스
예: ngrok, Cloudflare Tunnel
셀프호스팅 PaaS
예: Coolify, Dokploy
OPTiCS
터널 서비스는 연결만, PaaS는 배포만 담당합니다. OPTiCS는 공인 IP 없이 그 둘을 하나의 흐름으로 연결합니다 — 이미 사용 중인 도구를 대체하는 것이 아니라, 그 사이의 공백을 채우는 도구에 가깝습니다.
주요 기능
아래 세 가지는 서비스를 배포한 뒤 반복해서 사용하게 되는 화면입니다.
배포
Git 저장소 URL과 환경변수를 입력하면 클론부터 이미지 빌드, 컨테이너 기동까지 Agent가 처리합니다. 별도의 빌드 서버가 필요하지 않습니다.
네트워크
워크스페이스와 서비스마다 HTTPS 서브도메인이 발급됩니다. DNS 레코드는 서비스를 만들 때 생기고 지울 때 정리됩니다.
운영
Console에서 CPU와 메모리를 실시간으로 모니터링할 수 있으며, compose 프로젝트의 컨테이너를 개별적으로 시작하거나 재시작할 수 있습니다.
소스도, 이미지도, 데이터베이스도 내 서버를 떠나지 않습니다.
외부에서 들어온 요청만 Hub의 공개 프록시를 경유합니다.
구조
Hub와 Agent 사이에 NAT가 있어도 Agent가 먼저 연결하므로 경계를 개방할 필요가 없습니다.
요약하면 — 내 서버에 설치되는 것은 Agent와 Agent Dashboard, 두 컨테이너뿐입니다. 나머지는 저희 쪽에서 동작합니다.
시작하기
내 서버에서 실행합니다. Docker가 설치되어 있지 않으면 설치 스크립트가 함께 설치합니다.
스크립트는 이 순서로 동작합니다
설치
원문 보기$curl -fsSL http://github.com/OPTiCS-Organization/OPTiCS-Infra/raw/main/linux/install-agent.sh -o install-agent.sh && sh install-agent.sh제거
$curl -fsSL http://github.com/OPTiCS-Organization/OPTiCS-Infra/raw/main/linux/uninstall-agent.sh -o uninstall-agent.sh && sh uninstall-agent.sh설치가 완료되면 화면에 연결 코드가 출력됩니다. 해당 코드를 Console에 입력하십시오.
이미 실행 중인 서비스는 중단되지 않습니다. 컨테이너는 사용자 서버에서 Docker 데몬이 직접 실행하며, Agent 코드 어디에도 Hub와의 연결이 끊어졌다고 컨테이너를 중단하는 로직이 없습니다. 컨테이너의 포트도 Docker가 호스트에 직접 바인딩하므로, 서버 로컬 IP로 직접 접근하는 경우에도 영향을 받지 않습니다. 다만 <서비스>.<워크스페이스>.optics.run 같은 공개 주소로 들어오는 요청은 Hub의 공개 프록시를 반드시 거치므로, 이 경로는 Hub에 장애가 발생하면 함께 중단됩니다. 배포·시작·중지 같은 새 명령도 Hub API를 경유하므로, Hub가 복구될 때까지는 처리되지 않습니다.
OS와 배포판을 확인하고, Docker·Docker Compose가 없으면 설치 여부를 먼저 확인합니다(동의한 경우에만 sudo로 설치를 진행합니다). 그다음 Agent 저장소에서 docker-compose.yml과 .env.example 두 파일만 내려받습니다 — 소스를 클론하거나 빌드하지 않으며, 실제로 기동되는 이미지는 GHCR에 게시된 것입니다. 웹 SSH 터미널 사용 여부를 확인하고 동의하면 sshd를 설정하고 전용 키를 만들어 등록합니다. 포트(기본 5230/5240) 충돌을 확인한 뒤 이미지를 내려받아 컨테이너를 기동하는 것으로 완료됩니다. 아래 설치 섹션에 스크립트 원문 링크가 있습니다.
소스 코드, 빌드 이미지, 실행 중인 컨테이너 및 데이터베이스는 모두 사용자 서버(Agent)에 저장됩니다. Hub가 보관하는 정보는 계정 정보와 워크스페이스·서비스 설정 등의 메타데이터입니다. 다만 외부 방문자가 서비스에 접속할 때 전송하는 요청 바이트 자체는 Hub의 Gateway를 거쳐 서버로 중계됩니다 — Gateway는 요청을 전달할 뿐 내용을 로깅하거나 저장하지 않습니다.
Docker(와 Compose)가 동작할 수 있는 서버면 충분합니다. 별도로 정해 둔 최소 사양은 없습니다. 공인 IP나 포트포워딩도 필요하지 않습니다. Agent가 사용자 서버에서 먼저 Hub로 연결하므로 NAT 환경에서도 사용할 수 있습니다.
직접 발급하거나 갱신하지 않습니다. 서브도메인 발급과 인증서 모두 Cloudflare를 사용합니다. Hub가 워크스페이스·서비스 서브도메인의 DNS 레코드를 Cloudflare에 등록하면, 그 앞단에서 Cloudflare가 TLS를 처리합니다.
Agent 컨테이너에는 호스트의 Docker 소켓(/var/run/docker.sock)이 그대로 마운트됩니다. 배포·시작·중지· 재배포 같은 정상 기능이 이 권한으로 동작하지만, 반대로 Agent 컨테이너가 침해되면 호스트의 Docker 전체를 조작할 수 있다는 의미이기도 합니다. 설치 시 웹 SSH 터미널을 활성화했다면 전용 SSH 키도 컨테이너에 추가로 마운트됩니다. 신뢰할 수 있는 서버에만 설치해야 합니다.
현재 상태
Console 화면
명령·스크립트
팀 기능
완료 시기는 약속하지 않습니다. 진행 상황은 GitHub에서 확인할 수 있습니다.