Tailscale ACL: 테일넷 정책 파일로 서버 잠그기
테일넷에 올린 VPS는 기본값으로 모든 기기에게 모든 포트를 엽니다. 태그와 grants 규칙으로 노트북과 휴대폰만 통과시키고, tests로 저장 전에 검증하고, 잠겼을 때 돌아오는 길까지 정리합니다. 무료 Personal 요금제에서도 쓸 수 있습니다.
Tailscale ACL이 해결하는 문제
Tailscale ACL(access control list, 접근 제어 목록)은 테일넷 안에서 어떤 기기가 어떤 포트에 닿을 수 있는지를 정하는 규칙입니다. 새로 만든 테일넷의 정책 파일에는 전체 허용 규칙 하나만 들어 있습니다. 그래서 VPS를 테일넷에 넣는 순간, 그 서버의 모든 포트가 테일넷 안의 모든 기기에게 열립니다.
기본 정책 파일은 이렇게 생겼습니다.
{
"acls": [
{
"action": "accept",
"src": ["*"],
"dst": ["*:*"]
}
]
}src가 *이고 dst가 *:*입니다. 출발지 제한이 없고 목적지 포트 제한도 없다는 뜻입니다. 공인 IP 쪽을 ufw로 막아 두었다면 Postgres의 5432, Ollama의 11434, n8n의 5678, Grafana의 3000은 인터넷에서 보이지 않습니다. 그러나 테일넷 안에서는 그대로 보입니다. 서비스를 테일넷 주소에만 바인딩했어도 결과는 같습니다. 바인딩은 "아무에게도 공개하지 않는다"가 아니라 "테일넷에만 공개한다"는 뜻이기 때문입니다.
테일넷에 기기가 내 노트북 하나뿐이라면 차이가 없습니다. 가족 계정을 초대했거나, 예전에 쓰던 휴대폰이 목록에 남아 있거나, 다른 VPS를 같은 테일넷에 넣었다면 그 기기들도 전부 5432에 닿습니다. 기기 하나가 털리면 테일넷 전체가 평평한 내부망이 됩니다. 테일넷이 무엇이고 기기들이 어떻게 서로를 찾는지부터 정리하고 싶다면 테일넷의 기본 구조를 설명한 글을 먼저 읽는 편이 좋습니다.
고치는 순서는 세 걸음입니다. 서버에 태그를 붙이고, 전체 허용 규칙을 지우고, 내 계정이 실제로 쓰는 포트만 다시 엽니다.
시작하기 전에: 지금 누가 무엇에 닿는지 본다
서버에서 먼저 현재 상태를 확인합니다.
tailscale status출력은 한 줄에 기기 하나씩입니다. 테일넷 IP, 기기 이름, 소유자 이메일, 운영체제, 연결 상태 순서로 나옵니다. 여기 보이는 모든 줄이 지금 이 서버의 모든 포트에 닿을 수 있는 기기입니다. 목록이 생각보다 길다면 그 자체가 정책 파일을 손봐야 하는 이유입니다.
정책 파일은 관리 콘솔의 Access controls 페이지에서 고칩니다. 주소는 https://login.tailscale.com/admin/acls입니다. API나 GitOps 연동으로도 같은 파일을 고칠 수 있지만, 처음에는 콘솔 편집기가 가장 빠릅니다.
2026년 9월 기준으로 Tailscale 문서는 접근 제어가 모든 요금제에서 제공된다고 밝히고 있습니다. 무료 Personal 요금제도 정책 파일을 직접 편집할 수 있고, 사용자 6명까지, 태그가 붙은 리소스 50개까지 포함됩니다. 요금제에 따라 달라지는 것은 기기 상태 기반 규칙 같은 상위 기능이지, 정책 파일 편집 자체가 아닙니다.
1단계: 태그를 먼저 만든다
규칙의 목적지로 기기 이름을 쓰고 싶은 유혹이 있습니다. 권하지 않습니다. 기기 이름은 바뀝니다. VPS를 다시 만들면 같은 서버가 아니라 새 기기가 되고, 이름 뒤에 -1이 붙기도 합니다. 그때마다 정책 파일을 따라 고쳐야 합니다.
태그는 기기가 아니라 역할에 붙습니다. tag:home-server라는 태그를 정해 두면, 서버를 다시 만들어도 태그만 다시 붙이면 규칙이 그대로 적용됩니다. 먼저 정책 파일에 태그를 선언합니다.
{
"tagOwners": {
"tag:home-server": ["autogroup:admin"]
}
}tagOwners는 "누가 이 태그를 기기에 붙일 수 있는가"를 정합니다. 접근 권한이 아니라 발급 권한입니다. autogroup:admin은 Admin 역할을 가진 사용자 전체를 가리킵니다. 혼자 쓰는 테일넷이라면 본인이 Owner이므로 여기에 포함됩니다. 이메일을 직접 써도 됩니다.
선언하지 않은 태그는 존재하지 않습니다. tagOwners에 없는 태그를 기기에 붙이려고 하면 명령이 거부됩니다. 오류 문구는 클라이언트 버전에 따라 조금씩 다르지만, 요지는 요청한 태그를 적용할 권한이 없다는 것입니다.
2단계: 서버에 태그를 붙인다
태그를 붙이는 명령은 서버에서 직접 실행합니다.
sudo tailscale up --advertise-tags=tag:home-server태그가 적용되면 명령은 아무것도 출력하지 않고 프롬프트로 돌아옵니다. 다만 태그를 붙이는 행위는 기기의 사용자 인증을 없애고 태그를 기기의 정체성으로 바꾸기 때문에, 재인증이 필요한 상태에서는 https://login.tailscale.com/으로 시작하는 주소 한 줄이 출력됩니다. 그 주소를 브라우저에서 열어 승인해야 태그가 실제로 붙습니다.
이 명령은 테일넷 주소로 접속한 SSH 세션을 끊을 수 있습니다. 기기의 정체성이 바뀌면 지금 적용 중인 규칙이 더 이상 맞지 않을 수 있기 때문입니다. 공인 IP로 들어가는 SSH 세션이나 제공업체의 웹 콘솔을 다른 창에 열어 둔 상태에서 실행하세요.
적용됐는지는 두 곳에서 확인합니다. tailscale status에서 서버 줄의 소유자가 내 이메일이 아니라 tagged-devices로 바뀝니다. 관리 콘솔의 Machines 목록에서는 기기 이름 옆에 tag:home-server가 표시됩니다. 둘 중 하나라도 그대로면 재인증 주소를 아직 열지 않은 것입니다.
부수 효과가 하나 있는데, 좋은 쪽입니다. 태그가 붙은 기기는 키 만료가 기본으로 꺼집니다. 서버가 몇 달 뒤 혼자 로그아웃되어 새벽에 접속이 안 되는 사고가 사라집니다. 태그를 서버에 쓰는 이유 중 하나가 이것입니다.
반대로 되돌릴 때는 주의할 점이 있습니다. 태그가 붙은 기기에서 모든 태그를 떼어 정체성을 비울 수는 없습니다. 다른 태그로 바꾸거나, 관리 콘솔에서 기기 설정을 고쳐야 합니다.
3단계: 전체 허용 규칙을 지우고 필요한 포트만 연다
여기서 쓰는 문법을 분명히 해 둡니다. 2026년 9월 기준 Tailscale 문서는 정책 파일에 grants 섹션을 권장하고 있습니다. 기존 acls 섹션도 그대로 동작하며, 두 섹션은 한 파일 안에 함께 쓸 수 있습니다. 아래 예시는 grants 문법입니다. 기존 acls 문법으로 쓴 규칙을 억지로 바꿀 필요는 없습니다.
{
"tagOwners": {
"tag:home-server": ["autogroup:admin"]
},
"grants": [
{
"src": ["me@example.com"],
"dst": ["tag:home-server"],
"ip": ["tcp:22"]
},
{
"src": ["me@example.com"],
"dst": ["tag:home-server"],
"ip": ["tcp:5432", "tcp:11434", "tcp:5678", "tcp:3000"]
}
]
}앞서 본 acls의 전체 허용 규칙은 이 파일에 없습니다. 그게 핵심입니다. 규칙 하나하나는 허용만 합니다. 거부 규칙이라는 것은 없습니다. 어디에서도 허용되지 않은 출발지와 목적지의 조합이 곧 거부입니다.
src는 출발지, dst는 목적지, ip는 네트워크 계층에서 허용할 프로토콜과 포트입니다. tcp:22처럼 씁니다. dst에 태그를 쓰면 그 태그가 붙은 모든 기기가 목적지가 됩니다.
같은 내용을 기존 문법으로 쓰면 이렇습니다. 포트가 dst 안에 host:port 형태로 들어간다는 점이 다릅니다.
{
"acls": [
{
"action": "accept",
"src": ["me@example.com"],
"proto": "tcp",
"dst": ["tag:home-server:22", "tag:home-server:11434"]
}
]
}action에는 accept만 쓸 수 있습니다. 문법 자체가 거부를 표현하지 못하도록 되어 있습니다. 전체 문법은 Tailscale의 정책 파일 문법 문서에 정리되어 있습니다.
내 노트북과 휴대폰만 통과시키려면
src에 이메일을 쓰면 그 사용자의 모든 기기가 포함됩니다. 노트북, 휴대폰, 태블릿이 전부 들어갑니다. 혼자 쓰는 테일넷에서는 이게 맞는 단위입니다. 사용자를 기준으로 쓰면 새 노트북을 사도 정책 파일을 고칠 일이 없습니다.
기기 단위로 더 좁히고 싶다면 hosts로 테일넷 IP에 이름을 붙입니다.
{
"hosts": {
"laptop": "100.96.14.21",
"phone": "100.71.203.8"
},
"grants": [
{
"src": ["laptop", "phone"],
"dst": ["tag:home-server"],
"ip": ["tcp:5432"]
}
]
}이 방식에는 대가가 있습니다. 테일넷 IP는 기기를 지웠다가 다시 넣으면 바뀝니다. 휴대폰을 바꾸거나 노트북을 초기화하면 hosts의 값도 같이 고쳐야 하고, 고치는 것을 잊으면 조용히 접근이 끊깁니다. 데이터베이스 포트처럼 정말 좁혀야 하는 한두 줄에만 쓰고, 나머지는 사용자 단위로 두세요.
클라이언트에도 태그를 붙이는 방법이 있지만 권하지 않습니다. 태그를 붙이는 순간 그 기기는 사용자 소유가 아니게 됩니다. autogroup:self처럼 "내 기기"를 뜻하는 선택자에서 빠지고, 기기 공유 동작도 달라집니다. 태그는 사람이 로그인하지 않는 기계에 쓰는 물건입니다.
SSH 경로는 따로 챙겨야 합니다
일반 sshd를 22번 포트로 쓰고 있다면 위의 tcp:22 규칙 하나면 끝입니다. Tailscale SSH를 켰다면 이야기가 다릅니다.
Tailscale 문서는 두 가지 규칙이 모두 필요하다고 명시합니다. 네트워크 계층에서 22번 포트를 여는 규칙 하나, 그리고 ssh 섹션의 규칙 하나입니다. Tailscale SSH는 포트 규칙을 건너뛰지 않습니다. ssh 섹션만 쓰고 포트를 열지 않으면 연결이 되지 않습니다.
{
"ssh": [
{
"action": "check",
"src": ["autogroup:member"],
"dst": ["tag:home-server"],
"users": ["autogroup:nonroot", "ubuntu"],
"checkPeriod": "12h"
}
]
}action이 accept면 조건을 만족하는 연결을 그냥 받습니다. check면 정해진 주기마다 브라우저에서 다시 인증하라고 요구합니다. checkPeriod를 쓰지 않으면 기본값은 12시간입니다. users는 서버에서 어떤 계정으로 로그인할 수 있는지를 정합니다. autogroup:nonroot는 root를 제외한 모든 계정을 뜻합니다.
tailscale set --ssh로 Tailscale SSH를 켜는 순간, 그 서버의 테일넷 주소로 열려 있던 기존 SSH 연결이 멈출 수 있습니다. 데몬이 22번 포트를 가로채기 시작하기 때문입니다. 다른 경로를 열어 둔 상태에서 켜세요. 서버 자체의 SSH 설정을 어디까지 조여야 하는지는 SSH를 단단히 조이는 기본 설정에서 따로 다룹니다.
저장하기 전에 tests로 증명합니다
정책 파일에는 tests 섹션이 있습니다. 규칙에 대한 주장을 적어 두면, 파일을 저장할 때마다 Tailscale이 그 주장을 검사합니다. 주장이 틀리면 저장을 거부하고, 어떤 테스트가 실패했는지 알려 줍니다.
{
"tests": [
{
"src": "me@example.com",
"proto": "tcp",
"accept": ["tag:home-server:22", "tag:home-server:11434"]
},
{
"src": "family@example.com",
"proto": "tcp",
"deny": ["tag:home-server:22", "tag:home-server:5432"]
}
]
}src는 검사할 주체입니다. 이메일, 그룹, 태그, 호스트 이름을 쓸 수 있습니다. accept에는 닿아야 하는 목적지를, deny에는 막혀 있어야 하는 목적지를 host:port 형태로 적습니다. proto를 생략하면 TCP와 UDP를 모두 검사합니다.
deny 쪽이 더 중요합니다. accept만 쓰면 "열려 있어야 할 것이 열려 있다"만 증명합니다. 정작 알고 싶은 것은 "닫혀 있어야 할 것이 닫혀 있다"입니다. 가족 계정이나 두 번째 VPS를 출발지로 삼아 deny 항목을 적어 두면, 나중에 누군가 규칙을 느슨하게 고쳤을 때 저장 단계에서 걸립니다.
순서가 중요한 이유가 있습니다. 저장 버튼을 누르는 순간 규칙은 테일넷 전체로 퍼집니다. "일단 저장하고 접속해 보자"는 방식은 자신을 잠글 수 있습니다. tests는 그 순서를 뒤집어 줍니다. 저장이 성공했다면 적어도 적어 둔 주장만큼은 이미 참입니다.
자신을 잠그는 두 가지 방법
첫째, 내 SSH 경로를 잘라 먹는 경우입니다. 전체 허용 규칙을 지우면서 22번 포트 규칙을 빠뜨리면 그다음 접속이 되지 않습니다. Tailscale SSH를 쓰는 경우에는 더 흔합니다. ssh 섹션은 남겨 두고 네트워크 계층의 tcp:22를 빼면, 문법 오류도 없고 테스트도 없으니 저장은 깔끔하게 성공하고 접속만 막힙니다.
둘째, 내가 소유하지 않은 태그를 붙이는 경우입니다. tagOwners에 자신이 들어 있지 않으면 --advertise-tags 명령 자체가 거부되므로 이쪽은 금방 알아차립니다. 더 조용한 사고는 명령이 성공했을 때 일어납니다. 규칙을 autogroup:self 기준으로 써 두었다면, 서버에 태그를 붙이는 순간 그 서버는 더 이상 내 기기가 아니므로 규칙에서 빠집니다. 접근 권한은 태그 쪽으로 옮겨 갔는데 태그를 대상으로 한 규칙은 아직 없는 상태가 됩니다.
돌아오는 길은 여러 갈래가 있습니다.
- 관리 콘솔의 Access controls 페이지에서 규칙을 되돌립니다. 콘솔은 테일넷 트래픽이 아니라 웹 로그인으로 들어가므로, 정책 파일이 아무리 엄격해도 콘솔 접근을 막지 못합니다. 이것이 가장 확실한 복구 경로입니다.
- 관리 콘솔의 Machines 목록에서 기기의 태그를 직접 고칩니다. Owner, Admin, Network admin 역할은
tagOwners설정과 무관하게 어떤 태그든 적용할 수 있습니다. - 공인 IP로 SSH 접속합니다. 22번 포트를 인터넷에 열어 두지 않았다면 이 길은 막혀 있습니다.
- 제공업체의 웹 콘솔이나 시리얼 콘솔로 들어갑니다. 네트워크 설정을 전부 날려 먹었을 때 남는 마지막 길입니다.
습관 하나를 권합니다. 정책 파일을 처음 조일 때는 관리 콘솔 탭과 별도의 접속 세션을 함께 열어 둡니다. 되돌리는 데 걸리는 시간이 몇 초와 몇십 분 사이에서 갈립니다.
Tailscale ACL이 하지 않는 일
여기서 오해가 자주 생깁니다. 정책 파일은 테일넷 트래픽만 거릅니다. 그 밖의 것은 손대지 않습니다.
공인 IP는 그대로입니다. 서버에 공인 IP가 붙어 있고 5432가 0.0.0.0에 바인딩되어 있다면, 인터넷에서 오는 연결은 정책 파일을 거치지 않습니다. 그쪽은 여전히 방화벽의 일입니다. ufw로 공개 포트를 막는 기본 규칙은 Tailscale을 쓰든 안 쓰든 그대로 필요합니다.
도커는 방화벽을 우회합니다. -p 5432:5432로 포트를 게시하면 도커가 직접 규칙을 넣기 때문에 ufw의 거부 규칙이 소용없어집니다. Tailscale ACL은 이 문제를 고치지 못합니다. 테일넷 밖에서 들어오는 트래픽이기 때문입니다. 도커 게시 포트가 ufw를 건너뛰는 이유를 먼저 확인하고, 필요하면 바인딩 주소를 127.0.0.1이나 테일넷 주소로 좁히세요.
로컬 네트워크 접근에는 영향이 없습니다. Tailscale 문서의 표현 그대로, ACL은 기기가 자기 로컬 네트워크에서 무엇에 닿을 수 있는지를 바꾸지 않습니다. 같은 공유기 아래에 있는 기기끼리는 테일넷을 거치지 않고 통신합니다.
인증이 아닙니다. 규칙은 경로만 정합니다. 5432에 닿을 수 있게 된 기기 앞에는 여전히 Postgres의 비밀번호가 서 있어야 합니다. ACL을 켰으니 관리자 화면의 로그인을 빼도 된다는 생각은 위험합니다.
제어 서버가 하는 일도 그대로입니다. 정책 파일은 어떤 기기가 서로를 알게 되는지를 정하지만, 트래픽을 푸는 열쇠를 다루지는 않습니다. Tailscale이 무엇을 보고 무엇을 보지 못하는지는 제어 서버의 역할을 따로 설명한 글에 정리되어 있고, 제어 서버가 기기를 임의로 추가하지 못하게 막는 장치는 테일넷 락입니다.
서브넷 라우터 뒤의 NAS는 라우터의 규칙을 물려받습니다
시놀로지 NAS나 집 공유기 뒤의 홈 서버를 서브넷 라우터를 통해 쓰고 있다면 규칙의 모양이 달라집니다. 그 기기들은 테일넷 기기가 아닙니다. 계정도 없고 태그도 붙일 수 없습니다. 그래서 정책 파일에서 그 기기들을 가리키는 방법은 IP 주소 범위뿐입니다.
{
"grants": [
{
"src": ["me@example.com"],
"dst": ["192.168.0.10/32"],
"ip": ["tcp:5000", "tcp:5001"]
}
]
}dst를 192.168.0.0/24처럼 넓게 쓰면 집 안의 모든 기기가 목적지가 됩니다. 공유기 관리 화면, 프린터, IP 카메라까지 전부 포함됩니다. NAS 하나만 열고 싶다면 위처럼 /32로 한 대만 지정하세요.
결과적으로 NAS의 접근 권한은 서브넷 라우터에 적용된 규칙을 따라갑니다. NAS 자체에 방화벽 설정이 있어도 그것은 NAS에 도착한 다음의 이야기이고, 테일넷 쪽 통과 여부는 라우터를 향한 규칙이 결정합니다. 이 구조가 불편하다면 NAS에 Tailscale을 직접 설치하는 편이 낫습니다. 그러면 NAS가 자기 태그와 자기 규칙을 갖게 됩니다. 라우터를 세우는 쪽을 택한다면 VPS로 서브넷 라우터를 구성하는 방법에 경로 승인과 IP 포워딩 설정이 함께 정리되어 있습니다.
경로 승인을 손으로 누르기 싫다면 autoApprovers로 자동화할 수 있습니다.
{
"autoApprovers": {
"routes": {
"192.168.0.0/24": ["tag:home-server"]
},
"exitNode": ["tag:home-server"]
}
}출구 노드를 쓰는 경우에는 목적지가 조금 특별합니다. 인터넷으로 나가는 트래픽은 autogroup:internet으로 표현합니다. 기존 acls 문법으로는 이렇게 씁니다. 두 문법은 한 파일에 같이 둘 수 있으므로, 위의 grants와 아래 규칙을 함께 써도 됩니다.
{
"acls": [
{
"action": "accept",
"src": ["me@example.com"],
"dst": ["autogroup:internet:*"]
}
]
}이 규칙이 없으면 출구 노드로 지정은 되는데 인터넷이 나가지 않습니다. 설정 전체는 VPS를 출구 노드로 만드는 글에서 다룹니다.
규칙이 실제로 먹었는지 확인하는 법
저장 후에는 새 연결로 확인해야 합니다. 이미 열려 있던 세션은 상태가 애매할 수 있으니 기준으로 삼지 마세요.
tailscale ping home-server
nc -vz 100.96.14.30 5432tailscale ping은 포트와 무관하게 노드 사이의 연결을 확인합니다. 포트를 막아 두어도 이 명령은 계속 성공합니다. 이것이 정상입니다. 두 명령의 결과가 다르다고 해서 설정이 깨진 것이 아닙니다.
nc -vz의 반응은 두 가지로 갈립니다. 규칙이 막고 있으면 아무 응답 없이 멈춰 있다가 타임아웃됩니다. 규칙은 통과했는데 서비스가 떠 있지 않으면 즉시 Connection refused가 돌아옵니다. 차단된 패킷은 그냥 버려지고 거부 응답을 되돌려 주지 않기 때문에 이런 차이가 생깁니다. 이 구분을 알면 "규칙 문제인가, 서비스 문제인가"를 한 번에 가릅니다.
서버 쪽에서는 journalctl -u tailscaled -n 50으로 데몬 로그를 봅니다. 정책이 갱신되면 새 패킷 필터를 받았다는 기록이 남습니다.
포트를 하나 늘릴 때
정책 파일은 시간이 지나면 지저분해집니다. 급할 때 넣은 넓은 규칙이 그대로 남고, 없어진 서비스의 포트가 계속 열려 있습니다.
규칙을 추가할 때마다 tests도 같이 추가하는 습관을 들이세요. 포트를 하나 열면 그 포트에 대한 accept 한 줄과, 그 포트에 닿으면 안 되는 주체에 대한 deny 한 줄을 넣습니다. 두 줄이면 충분합니다.
정책 파일 전체를 git 저장소에 두고 GitOps 연동으로 적용하면 변경 이력이 남습니다. 누가 언제 어떤 포트를 열었는지 코드 리뷰처럼 볼 수 있고, 되돌리기도 커밋 하나입니다. 혼자 쓰는 테일넷이라도 6개월 뒤의 자신을 위해 해 둘 만합니다.
마지막으로, 이 모든 규칙은 서버가 이미 기본적으로 정리되어 있다는 전제 위에서 의미가 있습니다. 공개 포트 정리, 사용자 계정, 자동 업데이트 같은 기본기는 새 VPS를 받고 처음 할 일 쪽에 있습니다.
FAQ
무료 Personal 요금제에서도 정책 파일을 편집할 수 있나요?
할 수 있습니다. 2026년 9월 기준 Tailscale 문서는 접근 제어가 모든 요금제에서 제공된다고 밝히고 있습니다. Personal 요금제는 사용자 6명, 사용자 기기 무제한, 태그가 붙은 리소스 50개, ACL 그룹 3개를 포함합니다. 상위 요금제에서 추가되는 것은 기기 상태 기반 규칙이나 외부 연동 같은 기능이며, 정책 파일 편집 자체는 막혀 있지 않습니다. 관리 콘솔의 Access controls 페이지에서 바로 고치면 됩니다.
규칙을 저장하면 지금 열려 있는 연결은 어떻게 되나요?
변경된 정책은 몇 초 안에 테일넷의 모든 기기로 퍼집니다. 새로 맺는 연결은 곧바로 새 규칙을 따릅니다. 이미 열려 있던 연결이 끊기는지는 상황에 따라 다르므로, 끊긴다고 가정하고 작업하는 편이 안전합니다. 확인도 기존 세션이 아니라 새 연결로 하세요. 열려 있는 SSH 창이 살아 있다는 것은 규칙이 맞다는 증거가 되지 못합니다.
grants와 acls 중 무엇으로 써야 하나요?
새로 쓴다면 grants를 권합니다. 2026년 9월 기준 Tailscale 문서가 대부분의 경우에 grants를 쓰라고 안내하고, 네트워크 계층과 응용 계층 권한을 한 규칙에 담을 수 있습니다. 기존 acls 문법도 그대로 동작하며, 두 섹션을 한 파일에 함께 둘 수 있습니다. 이미 acls로 잘 돌아가는 정책을 급히 바꿀 이유는 없습니다. 차이는 포트를 적는 위치입니다. acls는 dst에 tag:x:22처럼 붙이고, grants는 ip 배열에 tcp:22로 씁니다.
서버에 태그를 붙였더니 접속이 끊겼습니다. 어떻게 되돌리나요?
태그를 붙이면 그 기기는 사용자 소유에서 태그 소유로 바뀝니다. autogroup:self나 사용자 이메일을 기준으로 쓴 규칙에서 빠지므로, 태그를 목적지로 하는 규칙이 없으면 접근이 사라집니다. 관리 콘솔의 Access controls에서 tag:home-server를 목적지로 하는 규칙을 추가하는 것이 정석입니다. 태그 자체를 되돌리려면 Machines 목록에서 해당 기기의 태그를 수정합니다. Owner와 Admin 역할은 tagOwners 설정과 무관하게 어떤 태그든 적용할 수 있으므로 이 경로는 항상 열려 있습니다. 관리 콘솔은 웹 로그인으로 들어가기 때문에 정책 파일이 콘솔 접근을 막는 일은 없습니다.
Tailscale ACL을 설정했으니 ufw는 꺼도 되나요?
아닙니다. 정책 파일은 테일넷을 통해 들어오는 트래픽만 거릅니다. 서버의 공인 IP로 직접 들어오는 연결은 이 규칙을 전혀 거치지 않습니다. 도커로 게시한 포트라면 ufw까지 우회합니다. 두 방향을 각각 막아야 합니다. 공인 IP 쪽은 방화벽으로 닫고, 테일넷 쪽은 정책 파일로 좁히는 것이 올바른 조합입니다.