> ## Content Index
> Fetch the complete content index at: https://blog.sejong.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# 스팀덱으로 어디서든 집 PC 게임하기: Tailscale + Moonlight + Apollo
- URL: https://blog.sejong.dev/steamdeck-moonlight-tailscale/
- Published: 2026-10-11T15:35:46.000Z
- Updated: 2026-10-11T15:35:46.000Z
- Description: 집 PC에 Apollo를 띄우고 스팀덱에 Tailscale을 깔아, 어느 네트워크에서든 tailnet IP 하나로 Moonlight를 붙였다. 반대로 스팀덱 게임을 거실 TV로 보내 보려다 회색 화면에 막혀 지금은 Steam Link로 버티는 중인 기록.
- Author: Sejong Yoo
- Tags: 홈서버, VPN, Tailscale, Steam Deck, Moonlight, 서버

스팀덱은 들고 다니기 좋은 게임기지만, 무거운 게임은 집 PC가 훨씬 잘 돌린다. 그래서 하고 싶은 건 두 가지였다.

1. **밖에서도** 스팀덱으로 집 PC 게임을 스트리밍하기
2. **집에서는** 스팀덱 게임을 거실 TV 큰 화면으로 보내 패드로 조작하기

스트리밍 도구는 양쪽 다 Moonlight 계열을 썼다. Moonlight는 클라이언트고, 호스트 쪽에는 Sunshine(또는 그 포크)을 띄운다. 1번은 잘 됐고, 2번은 아직 반쯤이다.

스팀덱 설정은 스팀덱을 직접 만지지 않고 [NAS에 상주하는 Claude Code](https://blog.sejong.dev/claude-code-on-nas/)에서 SSH로 붙어서 했다. 키 인증으로 접속을 열어 두고, 비밀번호가 필요한 `sudo`만 PC에서 `ssh -t deck@스팀덱 "sudo ..."` 한 줄로 직접 쳤다.

## 구성

![스팀덱 Moonlight가 tailnet으로 집 PC의 Apollo에 붙는 경로와, 집 LAN에서 스팀덱 Sunshine을 Google TV로 받는 경로(Moonlight는 회색 화면, Steam Link는 정상)](https://blog.sejong.dev/content/images/2026/10/steamdeck-streaming-diagram.png)

|        | 호스트 (화면을 보내는 쪽)             | 클라이언트 (받는 쪽)                           | 경로                  |
| ------ | --------------------------- | -------------------------------------- | ------------------- |
| ① 어디서든 | 집 PC — **Apollo**           | 스팀덱 — Moonlight                        | tailnet (WireGuard) |
| ② 집 안  | 스팀덱 — Sunshine (Decky 플러그인) | Google TV — Moonlight → 지금은 Steam Link | 집 LAN               |

## 스팀덱에 Tailscale 깔기

집 VPN은 [headscale](https://blog.sejong.dev/netbird-to-headscale/)이다. 제어 서버만 NAS에 있고 기기에는 Tailscale 공식 클라이언트를 깐다. 문제는 SteamOS였다.

SteamOS는 루트 파일 시스템(`/`)이 **읽기 전용**이고, OS 업데이트 때 A/B 파티션을 통째로 바꿔 끼운다. `pacman`으로 뭘 깔아도 다음 업데이트에 사라진다. 그래서 Tailscale이 직접 관리하는 스팀덱용 설치 스크립트 [tailscale-dev/deck-tailscale](https://github.com/tailscale-dev/deck-tailscale?ref=blog.sejong.dev)을 썼다. 스크립트를 먼저 받아 읽어 보니 하는 일은 단순했다.

- `pkgs.tailscale.com`에서 최신 정적 바이너리(tarball)를 받아 `/opt/tailscale`에 둔다. 스팀덱에서 `/opt`는 실제로 `/home` 쪽 offload 영역이라 OS 업데이트에도 남는다
- `tailscaled.service`와 `override.conf`를 `/etc/systemd/system`에 넣고 `enable` — 부팅하면 게임 모드에서도 알아서 뜬다
- `/etc/default/tailscaled`, `/etc/profile.d/tailscale.sh`를 `/etc/atomic-update.conf.d/`에 등록해 OS 업데이트 때도 유지되게 한다

```bash
# PC에서 한 줄로 (sudo 비밀번호는 여기서 입력)
ssh -t deck@<스팀덱 IP> "cd ~/deck-tailscale && sudo bash tailscale.sh && sudo /opt/tailscale/tailscale set --operator=deck"
```

`--operator=deck`을 주면 이후 `tailscale up/status`는 sudo 없이 `deck` 사용자로 할 수 있다. 그 다음 headscale에 붙였다.

```bash
/opt/tailscale/tailscale up \
  --login-server=https://vpn.example.com \
  --hostname=steamdeck \
  --accept-dns=false \
  --authkey=<10분짜리 1회용 키>
```

- 사용자 등록은 브라우저 로그인 대신 headscale에서 **10분짜리 사전 인증 키**를 만들어 넘겼다(키는 화면에 찍지 않고 바로 전달)
- `--accept-dns=false`: MagicDNS를 쓰지 않아서 스팀덱 DNS는 그대로 둔다. 그래서 뜨는 `systemd-resolved and NetworkManager are wired together incorrectly` 경고는 무시해도 된다
- 노드 만료는 없게 두었다. 게임기가 몇 달에 한 번 재인증을 요구하면 귀찮다

이걸로 스팀덱은 `100.64.0.6`을 받았고, 집 밖에서도 NAS에서 `ssh`가 붙는다(절전 중일 때는 당연히 안 된다).

## 집 PC: Sunshine 대신 Apollo

집 PC(Windows)에는 원래 Tailscale이 깔려 있어서 tailnet 주소가 이미 있었다. 호스트로는 Sunshine 대신 포크인 [Apollo](https://github.com/ClassicOldSong/Apollo?ref=blog.sejong.dev)를 깔았다.

Apollo의 가장 큰 차이는 **가상 디스플레이**다. 클라이언트가 붙으면 그 해상도·주사율에 맞는 가상 모니터를 만들어 그 화면을 보낸다. 스팀덱 화면은 1280×800(16:10)인데, 일반 Sunshine으로 16:9 모니터를 그대로 보내면 위아래에 검은 띠가 생기고 글자가 작아진다. Apollo는 스팀덱에 맞는 화면을 새로 만들어 주니 그런 게 없다. 연결이 끝나면 가상 모니터도 사라진다.

페어링은 Sunshine과 같다. 스팀덱 Moonlight에서 호스트를 추가하면 PIN이 뜨고, PC의 Apollo 웹 UI에 그 PIN을 넣으면 끝.

## Moonlight에 tailnet IP를 넣으면 끝

여기가 이 구성의 핵심이다. 스팀덱 Moonlight에서 호스트를 추가할 때 집 LAN 주소가 아니라 **PC의 tailnet IP(`100.64.0.x`)를 넣는다.** 그러면 스팀덱이 집 Wi-Fi에 있든, 카페 Wi-Fi든, 휴대폰 테더링이든 같은 주소로 붙는다.

원래 Moonlight를 집 밖에서 쓰려면 공유기에 포트를 열어야 한다.

| 프로토콜 | 포트                  | 용도                  |
| ---- | ------------------- | ------------------- |
| TCP  | 47984, 47989, 48010 | HTTPS/HTTP 제어, RTSP |
| UDP  | 47998–48000         | 영상·제어·음성 스트림        |

게임 스트리밍 호스트를 인터넷에 그대로 열어 두는 건 내키지 않는다. tailnet 안에서는 이 포트들이 WireGuard 터널 안으로만 오가니 공유기는 아무것도 열 필요가 없다.

네트워크 쪽에서 보면 이게 되는 이유는 이렇다.

- headscale은 각 기기의 공개키와 엔드포인트(공인 IP:포트)만 나눠 준다. 영상 트래픽은 지나가지 않는다
- 두 기기는 STUN으로 알아낸 서로의 엔드포인트로 UDP 홀 펀칭을 시도해 **직접** WireGuard 연결을 맺는다
- 대칭형 NAT처럼 직접 연결이 안 되는 망이면 DERP 중계를 거친다. 기본 DERP는 도쿄라 멀어서 집 NAS에 DERP를 하나 따로 두었고, 이 경우에도 집까지 한 번 거치는 정도로 끝난다

스트리밍은 지연에 민감해서 중계보다 직접 연결이 훨씬 낫다. `tailscale status`에서 상대가 `direct`로 보이는지 확인해 두면 좋다.

## 반대로: 스팀덱 게임을 거실 TV로

이번엔 스팀덱을 **호스트**로 쓰고, 거실 Google TV의 Moonlight로 받아 큰 화면에서 하려 했다. 스팀덱에는 Decky Loader 플러그인 **Decky Sunshine**을 썼다. 이 플러그인이 Flatpak Sunshine을 root 권한으로 띄워 KMS로 화면을 직접 잡는다. 여기서는 몇 가지에 걸렸다.

**플러그인이 starting에서 멈춤** — `~/homebrew/plugins`에 이름이 같은 "Decky Sunshine" 플러그인이 두 개(신버전·구버전) 들어 있었다. 부팅할 때마다 나중에 뜬 구버전이 신버전을 내리고, 구버전이 띄운 Sunshine은 몇 초 뒤 죽었다. 구버전 폴더를 밖으로 빼고 `plugin_loader`를 재시작해서 해결.

**웹 UI에서 설정을 저장하면 503** — Sunshine 웹 UI에서 인코더(`vaapi`)·언어를 바꿔 저장했더니, Moonlight에서 앱을 실행할 때 503이 났다. 로그를 보니 저장 직후 Sunshine이 같은 프로세스로 재시작하면서 root 권한을 잃고 화면 캡처에 실패하고 있었다.

```
Couldn't get handle for DRM Framebuffer
Unable to find display or encoder
```

Decky에서 Sunshine을 껐다 켜면(플러그인이 다시 root로 띄움) 돌아온다. 설정을 바꾼 뒤엔 꼭 플러그인에서 재시작해야 한다.

**화면이 느리게 바뀜** — 소리는 정상인데 화면만 늦게 따라왔다. 스팀덱 쪽(Sunshine 로그, Wi-Fi 신호·링크 속도)은 문제가 없었고, Google TV Moonlight의 코덱을 HEVC에서 **H.264**로 바꾸니 해결됐다. TV 쪽 HEVC 디코딩 문제로 보인다.

### 남은 문제: 게임을 켜면 회색 화면

여기까지 하면 스팀덱 홈 화면은 TV에 잘 나온다. 그런데 **게임을 실행하면 화면이 회색으로 바뀐다.** 원인은 아직 못 찾았다.

그래서 TV 쪽은 당분간 **Steam Link**를 쓴다. Google TV에 Steam Link 앱을 깔면 같은 LAN에 있는 스팀덱을 Steam 원격 플레이 호스트로 바로 잡는다. 따로 깔 것도, 설정할 것도 없고 게임 화면도 정상으로 나온다. 회색 화면을 해결하면 Moonlight로 다시 옮길 생각이다.

## 정리

- SteamOS는 `/`가 읽기 전용이라 패키지 대신 **`deck-tailscale` 스크립트**로 Tailscale을 깐다. `/opt`·`atomic-update.conf.d` 덕에 OS 업데이트에도 남는다
- 호스트 PC와 스팀덱이 같은 tailnet에 있으면 Moonlight에 **tailnet IP만 넣으면 어느 네트워크에서든** 붙는다. 포트포워딩은 필요 없다
- 스팀덱 해상도에 맞춘 가상 디스플레이가 필요하면 Sunshine보다 **Apollo**
- 스팀덱을 호스트로 쓰는 Decky Sunshine은 웹 UI 저장 후 재시작이 필수, Google TV에서는 H.264\. 게임 실행 시 회색 화면은 아직 숙제라 그동안은 Steam Link