n8n 텔레그램 웹훅을 켜는 순간 “bad webhook: Failed to resolve host” 오류가 나면서 봇이 메시지를 받을 길이 막혔습니다. 제가 셀프호스팅한 n8n 서버는 PC에서 API로 워크플로우를 만들 수 있을 만큼 멀쩡했는데, 텔레그램 쪽에서만 제 도메인을 찾지 못했습니다. 결국 웹훅을 접고 1분마다 텔레그램에 새 메시지를 묻는 폴링으로 바꿨고 7월부터 이 구조로 휴대폰에서 본 링크를 모으고 있습니다.
2026년 10월 기준으로 원인을 좁힌 순서, 지금 돌아가는 설정, 석 달 써 보며 드러난 한계까지 적어 둡니다.
휴대폰에서 본 링크를 봇으로 보관하고 싶었습니다
저는 IT 회사 마케터입니다. PC에 마크다운으로 된 개인 지식 창고(세컨드 브레인)를 두고 클로드 코드로 정리합니다. 걸리는 건 입구였습니다. 좋은 영상이나 기사는 주로 휴대폰에서 만나는데, 그걸 PC의 지식 창고까지 옮길 길이 없었습니다.
원한 흐름은 단순했습니다.
- 휴대폰 공유 버튼으로 텔레그램 봇에 링크를 보낸다
- 서버 어딘가에 쌓이고 봇이 ✅ 답장으로 받았다고 알려 준다
- 나중에 PC에서 클로드에게 “인제스트해줘”라고 하면 쌓인 것을 한꺼번에 가져가 정리한다
받는 쪽은 PC가 아니라 서버여야 했습니다. PC의 클로드 코드와 이어 둔 기존 텔레그램 연동은 PC 세션에 붙어 있어서 자주 끊겼기 때문입니다. 마침 셀프호스팅으로 돌리던 n8n이 있었습니다. n8n을 쓰게 된 이야기는 노코드 자동화 도구 비교 글에 적어 두었습니다.
같은 날 옵시디언 앱으로 공유해 구글 드라이브로 동기화하는 경로도 함께 만들었는데, 이 글은 텔레그램 봇 쪽 이야기입니다.
웹훅이 안 된 증상과 원인
활성화하자마자 나온 bad webhook 오류
n8n에서 텔레그램 메시지를 받는 정석은 Telegram Trigger 노드입니다. 워크플로우를 활성화할 때 텔레그램에 웹훅 주소를 등록하는 방식입니다. n8n 문서의 Telegram Trigger 자주 겪는 문제에도 텔레그램은 봇 하나에 웹훅을 하나만 등록받는다고 나옵니다.
활성화하자 “bad webhook: Failed to resolve host”가 떴습니다. 웹훅 등록 자체가 실패했으니 봇에게 보낸 메시지가 n8n까지 올 길이 없었습니다.
같은 문서가 대표로 다루는 오류는 “An HTTPS URL must be provided for webhook”입니다. 리버스 프록시 뒤에서 WEBHOOK_URL 환경변수가 잘못됐을 때 나는 오류로, 제 경우와는 문구부터 달랐습니다.
텔레그램만 제 도메인을 찾지 못했습니다
텔레그램 Bot API 문서를 보면 봇이 메시지를 받는 방법은 getUpdates(봇이 물어보기)와 웹훅(텔레그램이 보내 주기) 두 가지이고 둘은 동시에 쓸 수 없습니다. 웹훅은 텔레그램 서버가 제 서버 주소로 접속하는 방식이라 텔레그램이 먼저 DNS로 제 도메인의 IP를 알아내야 합니다. “Failed to resolve host”는 바로 그 이름 찾기 단계에서 막혔다는 뜻입니다.
원인은 세 단계로 좁혔습니다.
- 구글 공개 DNS(dns.google)와 Cloudflare DNS로 제 도메인을 조회했습니다. 둘 다 정상으로 IP를 돌려줬습니다.
- n8n을 빼고 텔레그램 setWebhook을 직접 호출했습니다. 같은 오류가 났으니 n8n 설정 문제는 아닙니다.
- 남는 건 텔레그램이 쓰는 DNS 리졸버가 제 도메인을 조회하지 못한다는 가능성입니다.
가장 그럴듯한 설명은 제 도메인의 네임서버가 해외에서 오는 조회에 답하지 않는다는 것입니다. 다만 이건 추정이고 끝까지 확인하지는 못했습니다. 웹훅을 살리려면 네임서버를 Cloudflare 같은 곳으로 옮기면 됩니다. 그 선택지는 나중으로 미루고 텔레그램이 제 서버에 접속할 필요가 없는 폴링으로 방향을 바꿨습니다.
1분 폴링으로 바꾼 설계
폴링은 방향이 반대입니다. n8n이 1분마다 텔레그램 API(getUpdates)에 새 메시지가 있는지 묻고, 있으면 가져옵니다. 요청이 n8n에서 텔레그램으로 나가기만 하니 텔레그램이 제 도메인을 찾을 일이 없습니다.
워크플로우는 둘로 나눴습니다.
| 워크플로우 | 하는 일 | 상태 |
|---|---|---|
| 수집기 (Poller) | 1분 스케줄 → getUpdates(일반 메시지만) → Code 노드로 텍스트·메시지 번호·시각·보낸 사람 추출, “/”로 시작하는 명령어 제외 → 보관함 호출 → offset으로 확인 처리 | 활성 |
| 보관함 (Inbox) | 수집기가 넘긴 값을 그대로 받음 → “Captured” 빈 노드 → 봇이 ✅ 답장 | 비활성 (정상) |

봇 자격증명과 두 워크플로우는 클로드 코드가 n8n 공개 API로 만들어 올리고 활성화까지 했습니다.
offset으로 같은 메시지를 두 번 받지 않습니다
getUpdates는 아직 확인되지 않은 업데이트를 돌려줍니다. 문서 표현을 옮기면 “update_id보다 큰 offset으로 getUpdates를 호출하는 순간 그 업데이트는 확인된 것으로 본다”입니다. 그래서 수집기 마지막에 가장 큰 update_id에 1을 더한 값을 offset으로 넣어 한 번 더 부릅니다. 이 확인 호출이 보관함 호출 뒤에 있어서 보관 단계가 실패하면 확인도 되지 않고 다음 회차에 같은 메시지를 다시 가져옵니다.
명령어만 들어온 회차에는 Code 노드가 넘길 게 없어서 확인 호출까지 가지 않습니다. 그 명령어는 다음 링크가 들어올 때 함께 확인 처리됩니다. 매번 Code 노드에서 걸러지니 남아 있어도 문제는 없습니다.
PC 쪽에서도 한 번 더 거릅니다. 클로드가 마지막으로 처리한 메시지 번호를 설정 파일에 커서로 적어 두고 그보다 큰 번호만 가져옵니다. 옵시디언 경로로 같은 링크가 들어올 수도 있어서 유튜브 공유 링크의 si= 같은 추적용 값을 떼고 비교해 중복을 지웁니다.
실행 이력을 보관함으로 씁니다
이 구조에는 데이터베이스도 스프레드시트도 없습니다. 보관함 워크플로우가 실행될 때마다 n8n이 남기는 실행 이력이 곧 보관함입니다. PC의 클로드는 n8n API로 이 이력을 읽어 “Captured” 노드의 값만 꺼냅니다. 저장소 자격증명을 따로 만들 필요가 없었습니다.
대신 수집기는 1분마다 돌아서 하루 1,440번 실행됩니다. 이걸 다 기록하면 이력이 빈 실행으로 뒤덮이니, 수집기는 성공한 실행을 저장하지 않고 오류만 남기게 했습니다. n8n 실행 데이터 관리 문서에도 성공 실행을 저장하지 않는 설정이 나오고 이 설정을 워크플로우마다 따로 줄 수 있다고 적혀 있습니다. 보관함을 별도 워크플로우로 뗀 것도 저장할 실행과 버릴 실행을 나누기 위해서입니다.
석 달 써 보니 좋은 점과 아쉬운 점
7월 19일 만든 날부터 10월 19일 마지막 수거까지 봇으로 들어온 건 링크 9건과 메모 1건이었습니다. 링크는 9건 모두 유튜브였고 PC에서 수거할 때 클로드가 자막을 따로 받아 내용까지 정리했습니다.
좋았던 점은 이렇습니다.
- 텔레그램이 제 서버를 찾을 필요가 없으니 DNS 문제와 상관없이 돌아갑니다.
- ✅ 답장이 오니 저장됐는지 휴대폰에서 바로 압니다.
- 같은 날 만든 옵시디언 경로가 7월 첫 수거 이후 한 건도 들어오지 않는 사이에도, 봇 경로로는 링크가 계속 들어왔습니다. 옵시디언 쪽은 휴대폰 동기화가 멈춘 건 아닌지 아직 확인할 일로 남아 있습니다.
아쉬운 점도 분명합니다.
- ✅ 답장이 바로 오지 않습니다. 다음 폴링 회차까지 최대 1분을 기다립니다.
- 메시지는 한 달에 몇 건인데 실행은 하루 1,440번입니다. 셀프호스팅이라 실행 횟수 요금은 없지만 대부분이 빈 실행입니다.
- 보관 기간이 있습니다. n8n은 기본으로 336시간(14일)이 지난 실행 기록을 지웁니다. 9월 16일 수거 뒤 다음 수거가 10월 6일이라 3주가 비었는데, 그 앞쪽에 보낸 링크가 있었다면 지워졌을 수 있습니다. 실제로 사라진 게 있었는지는 알 수 없습니다.
- 텔레그램도 확인되지 않은 업데이트를 최대 24시간만 보관합니다. n8n 서버가 하루 넘게 멈추면 그동안 보낸 링크는 잃습니다.
- 링크만 보내면 나중에 왜 저장했는지가 남지 않습니다. 링크 뒤에 맥락 메모를 따로 보낸 건 한 번뿐이었고 나머지는 정리할 때 저장 이유를 추정으로 적어야 했습니다.

같은 상황이라면
n8n 텔레그램 웹훅에서 bad webhook 오류가 난다면 저는 이 순서로 봅니다.

- 오류 문구로 갈래를 나눕니다. “An HTTPS URL must be provided”면 n8n의 WEBHOOK_URL과 HTTPS 설정을, “Failed to resolve host”면 DNS를 봅니다. 텔레그램 getWebhookInfo의 last_error_message 항목에도 마지막 오류가 남습니다.
- 구글 공개 DNS 같은 공개 DNS로 내 도메인을 조회합니다. 다만 이런 서비스는 가까운 국내 거점이 대신 조회할 수 있어서, 정상으로 나와도 해외에서만 생기는 문제는 걸러지지 않습니다. 해외 여러 지점에서 조회해 주는 온라인 DNS 점검 도구를 함께 쓰는 편이 확실합니다.
- n8n을 빼고 setWebhook을 직접 호출해 같은 오류인지 봅니다.
- 텔레그램 웹훅 조건도 맞춰 봅니다. 텔레그램 웹훅 안내 문서 기준으로 포트는 443·80·88·8443만 되고, IPv6는 지원하지 않으며, TLS 1.2 이상이어야 합니다.
- 네임서버를 옮길 수 있으면 웹훅을, 당장 어렵다면 폴링을 씁니다. 웹훅이 등록된 봇이라면 deleteWebhook으로 먼저 지워야 getUpdates가 동작합니다.
- 실행 이력을 보관함으로 쓴다면 보관 기간(기본 14일) 안에 수거합니다.
자주 묻는 질문
n8n 텔레그램 웹훅 대신 폴링을 쓰면 메시지를 놓치지 않나요?
텔레그램은 봇이 가져갈 때까지 업데이트를 서버에 보관하고 offset으로 확인하기 전까지는 같은 업데이트를 계속 돌려줍니다. 그래서 1분 폴링이면 서버가 살아 있는 동안은 놓칠 일이 거의 없습니다. 걸리는 건 두 가지입니다. 텔레그램 쪽 보관 한도가 24시간이라 n8n 서버가 하루 넘게 멈추면 그 사이 메시지가 사라집니다. 실행 이력을 보관함으로 쓴다면 n8n의 이력 보관 기간도 지켜야 합니다.
1분 간격이면 n8n 실행 기록이 너무 많아지지 않나요?
하루 1,440번이지만 대부분은 새 메시지가 없어 getUpdates 한 번으로 끝나는 짧은 실행입니다. 수집기는 성공한 실행을 저장하지 않게 해 두어서 실행 이력에는 오류와 보관함 기록만 남습니다.
이미 쓰고 있는 텔레그램 봇을 같이 써도 되나요?
권하지 않습니다. 저도 쓰던 봇이 있었지만 수집용 봇을 BotFather에서 따로 만들었습니다. 봇 하나는 웹훅과 getUpdates 중 한 가지로만 받을 수 있습니다. getUpdates로 두 시스템이 같은 봇을 가져가면 한쪽이 확인 처리한 메시지를 다른 쪽은 받지 못합니다.