๐Ÿš€ SWAG : ๋‹น์‹ ์˜ homelab์„ ํ˜์‹ ํ•  Reverse Proxy Docker!

๋ฐœํ–‰: (2025๋…„ 12์›” 7์ผ ์˜คํ›„ 05:14 GMT+9)
8 min read
์›๋ฌธ: Dev.to

Source: Dev.to

SWAG๋ž€ ์ •ํ™•ํžˆ ๋ฌด์—‡์ธ๊ฐ€์š”?

SWAG๋Š” nginx ๊ธฐ๋ฐ˜์˜ ์˜ฌ์ธ์› ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ๋กœ, Letโ€™s Encrypt SSL ์ธ์ฆ์„œ๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•ด ์ค๋‹ˆ๋‹ค. ์‰ฝ๊ฒŒ ๋งํ•ด, ์—ฌ๋Ÿฌ๋ถ„์˜ ๋””์ง€ํ„ธ ๋ฌธ์ง€๊ธฐ๋กœ์„œ:

  • ๐Ÿ”’ SSL ์ธ์ฆ์„œ๋กœ ์„œ๋น„์Šค๋ฅผ ์ž๋™ ๋ณดํ˜ธ
  • ๐ŸŒ ์„œ๋น„์Šค๋ฅผ ๊ณ ์œ ํ•œ ์„œ๋ธŒ๋„๋ฉ”์ธ์— ๋…ธ์ถœ
  • ๐Ÿ›ก๏ธ ์ค‘์•™ ์ธ์ฆ์„ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณดํ˜ธ
  • ๐Ÿ“‹ ๊ฐ„๋‹จํ•œ ์„ค์ •๋งŒ์œผ๋กœ ๋ชจ๋“  ๊ฒƒ์„ ๊ด€๋ฆฌ

์™œ SWAG๋ฅผ ์„ ํƒํ•ด์•ผ ํ• ๊นŒ์š”?

SWAG๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์—๋Š” ์ผ๋ฐ˜ nginx์™€ certbot์„ ์ง์ ‘ ๋‹ค๋ค˜๋Š”๋ฐโ€ฆ ์ •๋ง ๊ณจ์น˜ ์•„ํŒ ์Šต๋‹ˆ๋‹ค! ์ธ์ฆ์„œ ๊ฐฑ์‹  ์‹คํŒจ, ์ˆ˜๋™ nginx ์„ค์ •, ๋„๋ฉ”์ธ ๊ด€๋ฆฌ ๋“ฑ ์—ฌ๋Ÿฌ ๋ฌธ์ œ๋ฅผ ํ•œ ๋ฒˆ์— ํ•ด๊ฒฐํ•ด ์ฃผ๋Š” ๊ฒƒ์ด SWAG์˜€์Šต๋‹ˆ๋‹ค:

  • ์ž๋™ ์™€์ผ๋“œ์นด๋“œ ์ธ์ฆ์„œ
  • ์ธ๊ธฐ ์„œ๋น„์Šค์šฉ ์‚ฌ์ „ ์„ค์ • ํŒŒ์ผ ์ œ๊ณต
  • Docker์™€์˜ ๋„ค์ดํ‹ฐ๋ธŒ ํ†ตํ•ฉ
  • ์ธ์ฆ ์ง€์› (Authelia, OAuth ๋“ฑ)

๋ชฉํ‘œ ์•„ํ‚คํ…์ฒ˜

์ œ๊ณต์—…์ฒด ์„ค์ • ์˜ˆ์‹œ (Free)

  1. Freebox ๊ด€๋ฆฌ ํŽ˜์ด์ง€์— ๋กœ๊ทธ์ธ
  2. Freebox ์„ค์ • โ†’ ํฌํŠธ ๊ด€๋ฆฌ
  3. ํฌํŠธ ํฌ์›Œ๋”ฉ ์„ค์ •:
์™ธ๋ถ€ ํฌํŠธ๋‚ด๋ถ€ ํฌํŠธ๋Œ€์ƒ IPํ”„๋กœํ† ์ฝœ
443 (HTTPS)443192.168.1.100 (์˜ˆ์‹œ)TCP
80 (HTTP)80192.168.1.100TCP

๐Ÿ’ก ๋ณด์•ˆ ํŒ: 80/443 ํฌํŠธ๋ฅผ ๋ฐ”๋กœ ์—ด๊ธฐ๋ณด๋‹ค ์ปค์Šคํ…€ ํฌํŠธ(์˜ˆ: 8443)๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ํฌ์›Œ๋”ฉํ•˜๋ฉด ๋” ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

DuckDNS ์„ค์ •

  1. DuckDNS์— ํšŒ์›๊ฐ€์ž…
  2. ๋„๋ฉ”์ธ ์ƒ์„ฑ: monhomelab.duckdns.org
  3. ํ† ํฐ์„ ๊ธฐ๋ก (Docker์—์„œ ์‚ฌ์šฉ)

๋Œ€์ฒด DNS ์ œ๊ณต์—…์ฒด

๋ฌด๋ฃŒ์œ ๋ฃŒ
DuckDNSCloudflare
FreeDNSOVH
Noโ€‘IPGandi
Route53
DigitalOcean
Namecheap

Cloudflare ์„ค์ • ์˜ˆ์‹œ:

environment:
  - URL=mondomaine.com
  - VALIDATION=dns
  - DNSPLUGIN=cloudflare
  - EMAIL=votre-email@example.com
  - CLOUDFLARETOKEN=votre-api-token-cloudflare

๊ณต์ธ IP ํ™•์ธ

# ๊ณต์ธ IP ํ™•์ธ
curl ifconfig.me
# DuckDNS๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ฐ€๋ฆฌํ‚ค๋Š”์ง€ ํ™•์ธ
nslookup monhomelab.duckdns.org

IP๊ฐ€ ์ผ์น˜ํ•˜๋ฉด OK! ๐ŸŽฏ

์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ

# ๋กœ์ปฌ ์„œ๋ฒ„ ๊ฐ„๋‹จํžˆ ์‹คํ–‰
python3 -m http.server 8080
# ์™ธ๋ถ€์—์„œ ๋„๋ฉ”์ธ์œผ๋กœ ํ…Œ์ŠคํŠธ
curl http://monhomelab.duckdns.org:8080

์ •์ƒ ๋™์ž‘ํ•˜๋ฉด SWAG๋ฅผ ์„ค์น˜ํ•  ์ค€๋น„๊ฐ€ ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค!

Docker Compose๋กœ ์„ค์น˜

ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ค€๋น„

version: "3.8"

networks:
  web-proxy:
    external: false

services:
  swag:
    image: lscr.io/linuxserver/swag:latest
    container_name: swag
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Paris
      - URL=monhomelab.duckdns.org      # DuckDNS ๋„๋ฉ”์ธ
      - VALIDATION=duckdns              # DuckDNS ์ธ์ฆ
      - DUCKDNSTOKEN=12345678-1234-1234-1234-123456789012  # DuckDNS ํ† ํฐ
      - SUBDOMAINS=wildcard             # *.monhomelab.duckdns.org ํ—ˆ์šฉ
      - EMAIL=votre-email@example.com
      - ONLY_SUBDOMAINS=false           # ๋ฉ”์ธ ๋„๋ฉ”์ธ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก
    volumes:
      - ./swag/data:/config
    ports:
      - "80:80"     # HTTP (HTTPS๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ)
      - "443:443"   # HTTPS (๋ณด์•ˆ ์„œ๋น„์Šค)
    networks:
      - web-proxy
    restart: unless-stopped

์ฃผ์š” ๋ณ€์ˆ˜

  • URLโ€ฏ: ์ „์ฒด ๋„๋ฉ”์ธ (DuckDNS, Cloudflare ๋“ฑ)
  • VALIDATIONโ€ฏ: DNS ์ œ๊ณต์—…์ฒด์— ๋งž๋Š” ์ธ์ฆ ๋ฐฉ์‹
  • SUBDOMAINS=wildcardโ€ฏ: ๋ชจ๋“  ์„œ๋ธŒ๋„๋ฉ”์ธ์— ๋Œ€ํ•œ ์ธ์ฆ์„œ ์ƒ์„ฑ
  • DUCKDNSTOKENโ€ฏ: DNS ์ œ๊ณต์—…์ฒด ํ† ํฐ / API ํ‚ค
  • ONLY_SUBDOMAINS=falseโ€ฏ: ๋ฉ”์ธ ๋„๋ฉ”์ธ๋„ ๋™์‹œ์— ์‚ฌ์šฉ ๊ฐ€๋Šฅ

SWAG ์‹œ์ž‘

docker-compose up -d swag
docker logs swag   # โ€œServer readyโ€์™€ โ€œCertificate renewal successfulโ€ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ณด์ผ ๊ฒ๋‹ˆ๋‹ค

์ƒ์„ฑ๋œ ํด๋” ๊ตฌ์กฐ

swag/data/
โ”œโ”€โ”€ nginx/
โ”‚   โ”œโ”€โ”€ nginx.conf
โ”‚   โ”œโ”€โ”€ site-confs/
โ”‚   โ””โ”€โ”€ proxy-confs/     # โ† ์„œ๋น„์Šค๋ณ„ ํ”„๋ก์‹œ ์„ค์ •
โ”œโ”€โ”€ keys/
โ”‚   โ””โ”€โ”€ letsencrypt/     # โ† SSL ์ธ์ฆ์„œ
โ””โ”€โ”€ log/

์ฒซ ๋ฒˆ์งธ ์„œ๋น„์Šค ์ถ”๊ฐ€

์„œ๋น„์Šคโ€ฏ1โ€ฏ: Home Assistant

๊ฐ™์€ dockerโ€‘compose.yml์— ์•„๋ž˜ ๋‚ด์šฉ์„ ์ถ”๊ฐ€:

  homeassistant:
    image: homeassistant/home-assistant:stable
    container_name: homeassistant
    environment:
      - TZ=Europe/Paris
    volumes:
      - ./homeassistant/data:/config
    networks:
      - web-proxy
    ports:
      - "8123:8123"   # ๋กœ์ปฌ ์ง์ ‘ ์ ‘๊ทผ์šฉ (์„ ํƒ)
    restart: unless-stopped

SWAG ํ”„๋ก์‹œ ์„ค์ •

swag/data/nginx/proxy-confs/homeassistant.subdomain.conf ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ :

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name homeassistant.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app homeassistant;
        set $upstream_port 8123;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }

    # WebSocket ์ง€์› (Home Assistant ํ•„์ˆ˜!)
    location /api/websocket {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app homeassistant;
        set $upstream_port 8123;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

์„ค์ • ํ…Œ์ŠคํŠธ

# ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธ
docker ps | grep homeassistant

# ์™ธ๋ถ€์—์„œ ์ ‘๊ทผ ํ…Œ์ŠคํŠธ
curl -k https://homeassistant.monhomelab.duckdns.org

Home Assistant ๋กœ๊ทธ์ธ ํ™”๋ฉด์ด ๋ณด์ด๋ฉด ์„ฑ๊ณต!

๋„คํŠธ์›Œํฌ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

์ „์šฉ Docker ๋„คํŠธ์›Œํฌ

SWAG, Home Assistant ๋“ฑ ๋ชจ๋“  ์„œ๋น„์Šค๊ฐ€ ๋™์ผํ•œ Docker ๋„คํŠธ์›Œํฌ(web-proxy)์— ์—ฐ๊ฒฐ๋ผ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํฌํŠธ ๊ณต๊ฐœ ์—†์ด ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„(homeassistant, swag ๋“ฑ)๋งŒ์œผ๋กœ ์„œ๋กœ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋กœ๊ทธ ๊ด€๋ฆฌ

docker logs swag          # ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ ๋กœ๊ทธ
docker logs homeassistant

SWAG ๋กœ๊ทธ๋Š” swag/data/log/์—๋„ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

์„ค์ • ๊ฒ€์ฆ

  • ์ธ์ฆ์„œ๊ฐ€ ์ƒ์„ฑ๋๋Š”์ง€ ํ™•์ธ:
    ls swag/data/keys/letsencrypt/live/monhomelab.duckdns.org/
  • HTTP โ†’ HTTPS ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ํ…Œ์ŠคํŠธ:
    curl -I http://monhomelab.duckdns.org

์™€์ผ๋“œ์นด๋“œ ์ธ์ฆ์„œ

SWAG๋Š” ์ž๋™์œผ๋กœ *.monhomelab.duckdns.org ์™€์ผ๋“œ์นด๋“œ ์ธ์ฆ์„œ๋ฅผ ๋ฐœ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ธŒ๋„๋ฉ”์ธ๋งˆ๋‹ค ๋ณ„๋„ ์ธ์ฆ์„œ๋ฅผ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

Authelia๋กœ ๋ณด์•ˆ ๊ฐ•ํ™” (๋ณด๋„ˆ์Šค)

Authelia๋ฅผ ์ธ์ฆ ๋ฏธ๋“ค์›จ์–ด๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  authelia:
    image: authelia/authelia
    container_name: authelia
    environment:
      - TZ=Europe/Paris
    volumes:
      - ./authelia/config:/config
    networks:
      - web-proxy
    restart: unless-stopped

๊ทธ ํ›„ ์„œ๋น„์Šค ํ”„๋ก์‹œ ํŒŒ์ผ์— ๋‹ค์Œ์„ ์‚ฝ์ž…:

    location / {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        auth_request /authelia;
        auth_request_set $user $upstream_http_remote_user;
        proxy_set_header Remote-User $user;
        # โ€ฆ
    }

์ „์ฒด ์„ค์ • ๋ฐฉ๋ฒ•์€ Authelia ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์ตœ์ข… ๊ฒฐ๊ณผ

  • ๋‹จ์ผ ์ง„์ž…์ (https://monhomelab.duckdns.org)์ด ๋ชจ๋“  ์„œ๋น„์Šค๋กœ ๋ผ์šฐํŒ…
  • ์ž๋™ ๊ฐฑ์‹ ๋˜๋Š” SSL ์ธ์ฆ์„œ
  • ์ค‘์•™ํ™”๋œ ๋กœ๊ทธ์™€ Docker ๋„คํŠธ์›Œํฌ ๊ด€๋ฆฌ

ํ”ํžˆ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์™€ ํ•ด๊ฒฐ๋ฒ•

๋ฌธ์ œํ™•์ธ ๋ฐฉ๋ฒ•ํ•ด๊ฒฐ์ฑ…
์ธ์ฆ์„œ๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์Œdocker logs swagDuckDNS ํ† ํฐ๊ณผ ์ธํ„ฐ๋„ท ์—ฐ๊ฒฐ ์ƒํƒœ ํ™•์ธ
443 ํฌํŠธ ์ฐจ๋‹จnc -zv votre-ip 443๋ผ์šฐํ„ฐ/๋ชจ๋Ž€์—์„œ ํฌํŠธ ํฌ์›Œ๋”ฉ ์„ค์ • ํ™•์ธ
์„œ๋น„์Šค ์ ‘๊ทผ ๋ถˆ๊ฐ€curl -I https://homeassistant.monhomelab.duckdns.org์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋™์ผํ•œ Docker ๋„คํŠธ์›Œํฌ์— ์žˆ๋Š”์ง€ ํ™•์ธ
DNS๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ง€์ •๋˜์ง€ ์•Š์Œnslookup monhomelab.duckdns.orgDuckDNS ํ˜น์€ ์‚ฌ์šฉ ์ค‘์ธ DNS ์ œ๊ณต์—…์ฒด์—์„œ IP ์—…๋ฐ์ดํŠธ

๊ฒฐ๋ก 

SWAG๋Š” homelab์— SSL์ด ์ ์šฉ๋œ ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ๋ฅผ ์†์‰ฝ๊ฒŒ ๊ตฌ์ถ•ํ•˜๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค. Docker, DuckDNS(๋˜๋Š” ๋‹ค๋ฅธ DNS ์ œ๊ณต์—…์ฒด)์™€ ์‚ฌ์ „ ์„ค์ •๋œ ๊ตฌ์„ฑ ํŒŒ์ผ์„ ๊ฒฐํ•ฉํ•˜๋ฉด ์‹œ๊ฐ„ยท๋ณด์•ˆยท์œ ์—ฐ์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ๋‹จ๊ณ„

  • SWAG ๊ณต์‹ ๋ฌธ์„œ
  • ์ง€์› DNS ์ œ๊ณต์—…์ฒด ์ „์ฒด ๊ฐ€์ด๋“œ
  • Authelia ํŠœํ† ๋ฆฌ์–ผ
  • ์ „์ฒด ์Šคํƒ ์˜ˆ์‹œ (Traefik, Portainer ๋“ฑ)
Back to Blog

๊ด€๋ จ ๊ธ€

๋” ๋ณด๊ธฐ ยป

์šฐ๋ฆฌ ์‚ฌ์ดํŠธ๊ฐ€ ์‹ฑ๊ฐ€ํฌ๋ฅด์—์„œ๋Š” ๋А๋ฆฌ๊ณ  ์œ ๋Ÿฝ์—์„œ๋Š” ์™„๋ฒฝํ–ˆ๋Š”๋ฐ, ๊ทธ ์ด์œ ๋Š”.

๋ฌธ์ œ: ์šฐ๋ฆฌ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์ œ๋Œ€๋กœ ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ API๋Š” Cloudflare ๋’ค์— ์œ„์น˜ํ•˜๊ณ  ์—ฃ์ง€ ์บ์‹ฑ์„ ์‚ฌ์šฉํ–ˆ์œผ๋ฉฐ, ๋Œ€์‹œ๋ณด๋“œ์—์„œ๋Š” p95 ์‘๋‹ต ์‹œ๊ฐ„์ด 100 ms ๋ฏธ๋งŒ์ž„์„ ๋ณด์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. Af...

๋‚˜๋Š” Game Boy๋ฅผ ChatGPT ์•ˆ์— ๋„ฃ์—ˆ๋‹ค (ChatGPT Apps)

์†Œ๊ฐœ: ChatGPT ์•ฑ์€ ์•„์ง BETA ๋‹จ๊ณ„์ด์ง€๋งŒ, ์–ด์ œ๋ถ€ํ„ฐ ๋ชจ๋“  ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž์‹ ์˜ ์•ฑ์„ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์ œ์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” Game Boy ์•ˆ์— ๋งž์ถ”์–ด ๋ณด๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค.

spaceorbust โ€“ GitHub ์ปค๋ฐ‹์œผ๋กœ ์šฐ์ฃผ ๋ฌธ๋ช…์„ ์›€์ง์ด๋Š” ํ„ฐ๋ฏธ๋„ RPG

๊ฐœ์š”: ์‹ค์ œ GitHub ํ™œ๋™์ด ์ธ๋ฅ˜์˜ ์šฐ์ฃผ ์ง„์ถœ์„ ์ด‰์ง„ํ•˜๋Š” ํ„ฐ๋ฏธ๋„ RPG. - ์ปค๋ฐ‹์€ ์—๋„ˆ์ง€๋กœ ๋ณ€ํ™˜๋œ๋‹ค - ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๋Š” ์žฌ๋ฃŒ๊ฐ€ ๋œ๋‹ค - ์ด์Šˆโ€ฆ