SSD Nodes Learn
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-07-24

איך להקים WireGuard VPN בשרת VPS

מדריך להקמת WireGuard ב-Linux VPS: הגדרת wg0.conf, IP forwarding, NAT ופתרון בעיות handshake ו-DNS. כולל דגשים ל-Ubuntu 24.04 ו-Debian 13.

מה אתם בונים

הקמת WireGuard VPN בשרת שבבעלותכם דורשת כ-40 שורות הגדרה: זוג מפתחות אחד, קובץ ממשק (interface) אחד, הגדרת sysctl אחת, כלל NAT אחד ופרצה אחת בחומת האש. תהליך ההתקנה פשוט, לכן רוב המדריך עוסק בדברים שעלולים להשתבש — הרשאות מפתחות, AllowedIPs, ניתוב (forwarding) ו-DNS.

WireGuard הוא מנהרה (tunnel) בשכבה 3 (Layer 3) בתוך ה-kernel. הוא חלק מה-mainline החל מגרסת Linux 5.6, לכן בגרסאות Ubuntu 24.04 ו-Debian 13 הוא מגיע מובנה ללא צורך במודול חיצוני. אין משא ומתן על הצפנה (cipher negotiation), אין רשות אישורים (CA), ואין שלב של שם משתמש או סיסמה: "peer" מוגדר כמפתח ציבורי בתוספת כתובות ה-IP שהוא רשאי להשתמש בהן. חבילה (packet) שנכשלת בבדיקת ה-MAC שלה נזרקת ללא כל תגובה, ולכן הפורט אינו מגיב לסריקות. הצד השני של המצב: אין שרת אימות (auth server), לכן הסרת גישה מחייבת מחיקת ה-peer מהמערכת.

בדקו תחילה את הווירטואליזציה

WireGuard דורש קרנל (kernel) שניתן לטעון אליו module, וב-KVM VPS זה עובד ישירות מההתקנה. בווירטואליזציית קונטיינרים (containers) המשתמשת בקרנל של המארח — OpenVZ, LXC — הפקודה הראשונה תיכשל עם RTNETLINK answers: Operation not supported, והפתרון החלופי הוא מימוש ה-userspace של wireguard-go. בדקו תחילה באמצעות sudo modprobe wireguard && echo ok.

יצירת מפתחות ללא דליפה

קובץ /etc/wireguard/server.key עם הרשאות קריאה לכל המשתמשים שקול לכך שאין VPN בכלל. שורת ה-umask 077 && wg genkey | sudo tee ... הנפוצה אינה אמינה, מכיוון ש-sudo מחיל umask משלו על הקובץ ש-tee יוצר. הגדר את ה-mode באופן מפורש.

sudo apt update && sudo apt install -y wireguard nftables
sudo install -d -m 700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/server.key'
sudo sh -c 'wg pubkey < /etc/wireguard/server.key > /etc/wireguard/server.pub'
sudo chmod 600 /etc/wireguard/server.key

צור את זוג מפתחות ה-client באותה דרך. wg genpsk מוסיפה pre-shared key אופציונלי, בשורה אחת בכל קובץ config.

ממשק השרת: /etc/wireguard/wg0.conf

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contents of /etc/wireguard/server.key>

[Peer]
PublicKey = <laptop public key>
PresharedKey = <psk, optional>
AllowedIPs = 10.8.0.2/32

chmod 600 it; אזהרת הפעלה המציינת שהקובץ נגיש לכל המשתמשים (world accessible) מעידה על כך שדילגת על שלב זה. Address הוא כתובת השרת בתוך המנהרה (tunnel), והיא כוללת את המסכה (mask) של כל תת-רשת ה-VPN. בחר טווח שלא יתנגש ברשתות אחרות — 192.168.1.0/24 מתנגש בחצי מהנתבים הביתיים שמאחוריהם נמצאים הלקוחות, מה שגורם למנהרה להפסיק לעבוד בשקט בשל התנגשות עם הנתיב המקומי (local route).

ה-AllowedIPs של Peer בצד ה-server הוא ה-/32, כתובת המנהרה היחידה המשויכת ללקוח. אם תגדיר עבור שני Peers את אותה כתובת IP ב-allowed IP, המערכת תעבור לכתובת האחרונה שהוגדרה, והראשונה תפסיק לקבל תעבורה ללא הודעת שגיאה. השאר את SaveConfig ללא הגדרה, אחרת wg-quick down יכתוב מחדש את הקובץ מתוך המצב הפעיל (live state).

הפוך את המחשב לנתב (router)

שרת Linux אינו מעביר חבילות (packets) שאינן מיועדות אליו. כברירת מחדל, אפשרות ה-Forwarding ואפשרות ה-source NAT אינן מופעלות.

printf 'net.ipv4.ip_forward = 1\nnet.ipv6.conf.all.forwarding = 1\n' \
  | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
sysctl net.ipv4.ip_forward

הגדרת sysctl -w פשוטה תעבוד עד לאתחול הבא, ולאחר מכן תפסיק לעבוד ללא התראה. NAT דורש את ממשק ה-egress — כרטיס הרשת (NIC) שמחובר לאינטרנט, ולא את wg0. אל תניח שeth0 הוא הממשק הנכון; בדוק את הממשק שלך באמצעות ip route show default, מכיוון שאימג'ים עדכניים משתמשים בשמות כמו enp1s0 או ens3.

Firewall: הפורט ונתיב ההעברה (forward path)

קובץ nftables אחד מכסה גם סינון (filter) וגם NAT. יש לכתוב את /etc/nftables.conf — פעולה זו מנקה (flushes) את סט הכללים הקיים, לכן יש לדלג על שלב זה במערכת המנוהלת כבר על ידי ufw או Docker.

#!/usr/sbin/nft -f
flush ruleset

table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    ct state established,related accept
    iif lo accept
    tcp dport 22 accept
    udp dport 51820 accept
  }
  chain forward {
    type filter hook forward priority filter; policy drop;
    ct state established,related accept
    iifname "wg0" oifname "enp1s0" accept
  }
}

table ip nat {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    ip saddr 10.8.0.0/24 oifname "enp1s0" masquerade
  }
}

החל את ההגדרות באמצעות sudo systemctl enable --now nftables, תוך שמירה על סשן SSH נוסף פתוח: שגיאת הקלדה בrule של SSH בתוך policy drop תגרום לכניסה חסומה לשרת. שים לב למה ששרשרת ה-forward אינה מאפשרת — wg0 עד wg0. שרתים (Peers) יכולים להגיע לאינטרנט, אך לא אחד לשני; יש להוסיף את iifname "wg0" oifname "wg0" accept עבור VPN מסוג peer-to-peer. אותה שרשרת שולטת במה ששרת יכול לגעת בו עצמו, דבר שחשוב כאשר המחשב משמש גם כ- remote development box running Claude Code in tmux ולא תרצה לחשוף את הצד הזה באופן ציבורי.

במערכת ufw: יש להשתמש בufw allow 51820/udp, ב-DEFAULT_FORWARD_POLICY="ACCEPT" בתוך /etc/default/ufw, ובכלל POSTROUTING MASQUERADE ב-*nat בראש הקובץ /etc/ufw/before.rules.

Bring it up under systemd

sudo systemctl enable --now wg-quick@wg0
sudo wg show

wg-quick יוצר את הממשק, מוסיף את הכתובות ומתקין נתיבים המופקים מ-AllowedIPs. enable --now הוא החלק החשוב: הגדרה ידנית של wg-quick up wg0 תאבד לאחר הפעלה מחדש הבאה, ושדרוגי kernel מחייבים הפעלה מחדש.

הגדרת הלקוח, וההגדרה שכולם טועים בה

[Interface]
PrivateKey = <laptop private key>
Address = 10.8.0.2/32
DNS = 10.8.0.1

[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

AllowedIPs מבצעת שתי משימות שונות בו-זמנית, והערבוב ביניהן הוא המקור לרוב הבלבול ב-WireGuard.

בכיוון היוצא (Outbound) היא טבלת ניתוב. חבילה שהיעד שלה תואם ל-AllowedIPs של ה-peer, מוצפנת ונשלחת לאותו peer. 0.0.0.0/0, ::/0 שולחת את כל התעבורה דרך המנהרה — מנהרה מלאה, כאשר השרת הוא ה-default route. split tunnel הוא רשימה מצומצמת יותר: AllowedIPs = 10.8.0.0/24, 10.20.0.0/16 מעביר תעבורת VPN بالإضافة לרשת פרטית אחת מאחורי השרת, וכל שאר התעבורה שומרת על הניתוב המקומי שלה. הרשימה המצומצמת הזו מאפשרת לשמור שירותים מחוץ לאינטרנט הציבורי לחלוטין — מופע Nextcloud פרטי ב-VPS המקושר לכתובת המנהרה, או מכונות וירטואליות של מעבדת nested-virtualisation הרצות על אותה מכונה, נשארים נגישים ל-peers ובלתי נראים עבור כולם אחרים.

בכיוון הנכנס (Inbound) היא רשימת בקרת גישה (ACL). חבילה שהוצפנה מ-peer שכתובת המקור שלה אינה מופיעה ב-AllowedIPs של אותו peer, נזרקת. זו הסיבה שהשרת מציין את 10.8.0.2/32 עבור הלפטופ: רישום של 0.0.0.0/0 שם יאפשר ללקוח זה לבצע spoof לכל כתובת בתוך המנהרה.

PersistentKeepalive מיועד ללקוחות מאחורי NAT, שבו הנתב מחזיק את מיפוי ה-UDP פתוח רק כל עוד זורמות חבילות. כאשר הפעילות פוקעת, השרת לא יוכל להגיע ללקוח יותר. PersistentKeepalive = 25 שומר על המיפוי פתוח — הגדר זאת בלקוח, לא בשרת עם IP ציבורי.

DNS, והדליפה שאף אחד לא מבחין בה

כאשר משתמשים ב-AllowedIPs = 0.0.0.0/0 ללא שורת DNS =, הלקוח שומר על ה-resolver שנלמד מהרשת המקומית — הנתב של בית הקפה ב-192.168.1.1. נתיב זה ספציפי יותר מהנתיב الاברית (default route), ולכן שאילתות DNS יוצאות דרך הקישור המקומי בפורמט cleartext, בעוד שכל שאר התעבורה עוברת בתוך ה-tunnel. התעבורה פרטית; רשימת השמות אינה פרטית.

ישנן שתי אפשרויות הגיוניות. ניתן להפנות את DNS ל-public resolver (כמו DNS = 9.9.9.9) והשאילתות יעברו בתוך ה-tunnel ויצאו מהשרת שלכם, אם כי ה-resolver עדיין יראה אותן. לחלופין, ניתן להריץ את unbound או dnsmasq המקושרים ל-10.8.0.1, להגדיר את DNS = 10.8.0.1, ולהוסיף את udp dport 53 iifname "wg0" accept ל-input chain — הגדרת השורה הזו תגרום לכך שה-resolver לא יתפקד, ושום דבר לא יתורגם (resolve).

בלקוחות Linux, wg-quick מחיל את DNS באמצעות resolvconf; אם הוא חסר, תקבלו את resolvconf: command not found. התקינו את openresolv, או הגדירו את PostUp = resolvectl dns %i 10.8.0.1 בלקוח systemd-resolved.

הוספה והסרה של peers ללא ניתוק ה-tunnel

הפעלה מחדש של ה-interface לצורך הוספת משתמש תנתק את כל החיבורים הקיימים. יש להוסיף את הבלוק [Peer] ל-wg0.conf, ולאחר מכן לטעון מחדש את ה-peer set במקומו.

sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)'

הפקודה wg-quick strip מדפיסה את הקונפיגורציה ללא מפתחות ה-wg-quick-only (Address, DNS, PostUp), והפקודה syncconf מחילה את השינויים מבלי להפסיק את הסשנים הפעילים. הפקודה מעדכנת peers בלבד: שינוי ב-Address עדיין דורש פעולת down/up מלאה. כדי לבטל, השתמש ב-sudo wg set wg0 peer <public key> remove ולאחר מכן מחק את הבלוק מהקובץ, אחרת הוא יוחזר בטעינה הבאה.

מצבי כשל, עם המחרוזות שיופיעו

ה-Handshake אינו מסתיים. wg show מציג את ה-peer ללא latest handshake, והלקוח מציג ב-logs:

Handshake for peer 1 (10.0.0.10:51820) did not complete after 5 seconds, retrying (try 2)

מידע אינו מגיע, או שמידע אינו מתקבל. בדוק לפי הסדר: האם UDP 51820 פתוח ב-firewall של ה-VPS וגם ב-firewall של ספק השרת (בפאנל נפרד ברוב המקרים); האם ה-address וה-port של Endpoint נכונים; האם המפתחות הוחלפו. המפתח בבלוק [Peer] של הלקוח חייב להיות המפתח ה-public של השרת, ולהיפך — הדבקת private key, או ה-public key של הלקוח עצמו, תגרום בדיוק לתסmind הזה. sudo tcpdump -ni any udp port 51820 בשרת מראה אם חבילות (packets) מגיעות בכלל. מודול ה-kernel אינו מתעד דבר כברירת מחדל; הודעות WireGuard יופיעו ב-dmesg רק לאחר הפעלת dynamic debug (echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control), וכאשר זה מופעל, חוסר התאמה במפתח יופיע כ-invalid-MAC drop.

ה-Handshake עובד, אין אינטרנט. ping 10.8.0.1 מצליח אך ping 1.1.1.1 נכשל ב-timeout: חסר forwarding או NAT. בדוק ש-sysctl net.ipv4.ip_forward קורא את 1, ולאחר מכן עקוב אחר המונים (counters) בזמן שהלקוח מבצע ping, באמצעות sudo nft list ruleset או sudo iptables -t nat -L POSTROUTING -n -v. אפס חבילות ב-masquerade rule מעיד על שם interface egress שגוי; מונה עולה ללא תשובות מעיד על ה-forward chain policy.

האינטרנט עובד, שמות דומיין לא. ping 1.1.1.1 מצליח ו-curl https://example.com מחזיר Could not resolve host. שורת ה-DNS חסרה, או שהיא מציינת resolver שאינו נגיש מתוך ה-tunnel.

אתרי HTTPS מסוימים נתקעים. SSH ו-ping עובדים; דפים גדולים נתקעים. זוהי בעיית path MTU: ה-tunnel מוסיף overhead, וחלק מהקישורים בדרך מDROP חבילות גדולות מדי ללא שליחת הודעת ICMP חזרה. הורד את MTU ב-[Interface] של הלקוח — נסה 1420, לאחר מכן 1380, ואז 1280.

ה-Interface מסרב לעלות. Address already in use פירושו שתהליך אחר תופס את UDP 51820. Cannot find device wg0 לאחר up שנכשל פירושו בדרך כלל שהקונפיגורציה נדחתה; קרא את journalctl -u wg-quick@wg0 -n 50.

מעבר מ-Streisand או OpenVPN

פרויקט Streisand אינו מתוחזק ומאגר הקוד שלו נארכב. הרצת VPN על כלי אוטומציה נטוש מהווה בעיית אבטחה מתמשכת. אין אפשרות לשדרוג במקום (in-place upgrade), ותשתית ה-PKI של OpenVPN אינה ניתנת להמרה: ל-WireGuard אין תעודות, אין CA ואין תוקף, ולכן כל לקוח מקבל זוג מפתחות חדש.

בצעו מעבר במקביל — WireGuard על UDP 51820 יכול להתקיים לצד OpenVPN על 1194 באותה מכונה. התקינו את wg0, העבירו לקוחות אחד אחד, ולאחר מכן עצרו את השירות הישן. מודל שם המשתמש/סיסמה והביטול (revocation) של OpenVPN אינו עובר; אם אתם זקוקים לחשבונות או למעקב ביקורת (audit trail), יש להוסיף שכבה כזו מעל WireGuard.

Backups, upgrades, and what strains at scale

/etc/wireguard is השרת. בצע גיבוי (sudo tar czf wg-backup.tgz -C /etc wireguard, mode 600, שמור מחוץ למכונה) ותוכל לשחזר את השרת על VPS חדש תוך דקות. אם תאבד את המפתח הפרטי של השרת, תצטרך להנפיק מחדש את כל הגדרות הלקוחות, מכיוון שהלקוחות קובעים (pin) את המפתח הציבורי של השרת. שדרוגים הם תהליך apt upgrade רגיל בתוספת הפעלה מחדש עבור עדכוני kernel, ו-wg-quick@wg0 יחזור לפעולה מעצמו אם הפעלת אותו.

מצב ה-per-peer הוא קטן והקריפטוגרפיה רצה בתוך ה-kernel, לכן המגבלה היא ה-CPU והרוחב פס של ה-VPS ולא פרמטר כלשהו בהגדרות אלו — מדוד אותם באמצעות iperf3 לאורך ה-tunnel במקום להסתמך על נתון מפורסם. מה שיוצר עומס בקנה מידה גדול הוא התפעול (operations). כל peer זקוק לכתובת IP ייחודית בתוך ה-tunnel, ועריכה ידנית של שישים בלוקים של [Peer] היא הדרך שבה כפילויות של AllowedIPs חודרות למערכת: צור את ההגדרות באמצעות script. שרת אחד הוא endpoint אחד של UDP ונקודת כשל אחת, ו-WireGuard אינו תומך ב-clustering: יתירות (redundancy) פירושה שרת שני עם מפתחות משלו. רוטציית מפתחות נשארת ידנית, לכן רשום מי מחזיק איזה מפתח וכיצד מבטלים מפתח קיים.

כל זה דורש מכונת Linux בשליטתך — כתובת IP ציבורית, kernel שניתן לטעון אליו module, ו-firewall בשליטתך מקצה לקצה.

FAQ

מדוע ה-handshake של WireGuard לא מסתיים לעולם?

אם ה-wg show מציג peer ללא latest handshake, המשמעות היא שחבילות לא מגיעות או לא מתקבלות. בדקו את UDP 51820 גם ב-firewall של ה-VPS וגם ב-firewall הנפרד של ספק השירות. ודאו שה-Endpoint וה-port נכונים. ודאו שהמפתחות לא הוחלפו — בבלוק ה-[Peer] של ה-client חייב להופיע ה-public key של ה-server. פקודת sudo tcpdump -ni any udp port 51820 בשרת תראה אם חבילות מגיעות בכלל; dmesg תדווח על כשלים ב-handshake של WireGuard רק לאחר הפעלת dynamic debug (echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control). במצב זה, חוסר התאמה במפתחות יופיע כ-invalid-MAC drop.

ה-tunnel מחובר אך אין לי אינטרנט. מה חסר?

אם ה-ping 10.8.0.1 עובד אך ה-ping 1.1.1.1 נכשל ב-timeout, הבעיה היא ב-forwarding או ב-NAT. ודאו ש-sysctl net.ipv4.ip_forward קורא את 1 ושהוא מוגדר ב-/etc/sysctl.d/, ולא רק באמצעות sysctl -w שנמחק לאחר reboot. לאחר מכן, בדקו את שמות חוקי ה-masquerade עבור ממשק ה-egress האמיתי שלכם מתוך ip route show default — לרוב enp1s0 או ens3, ובמקרים נדירים eth0.

האם אני זקוק לשורה DNS = בקובץ ה-config של ה-client?

במצב של full tunnel ללא שורת DNS =, ה-client ישמור על ה-resolver מהרשת המקומית. שאילתות אלו יישלחו בטקסט גלוי (cleartext) דרך הקישור המקומי, בעוד שכל שאר התעבורה תעבור בתוך ה-tunnel. הפנו את DNS ל-public resolver, או הריצו את unbound/dnsmasq המקושרים ל-10.8.0.1 ופתחו את udp dport 53 iifname "wg0" ב-input chain.

מה AllowedIPs שולט בפועל?

לפקודה זו שתי משימות. בתעבורה היוצאת (outbound) היא טבלת ניתוב: תעבורה התואמת ל-AllowedIPs של peer מסוים תוצפן ותשלח לאותו peer. בתעבורה נכנסת (inbound) היא רשימת בקרת גישה (ACL): חבילה שהוצפנה ומוצפנת מחדש, שמקורها מחוץ ל-AllowedIPs של אותו peer, תימחק (dropped). זו הסיבה שצד השרת מציג /32 לכל client, בעוד שצד ה-client עשוי להציג 0.0.0.0/0.

האם WireGuard יעבוד בכל VPS?

ב-KVM VPS זה יעבוד באמצעות ה-in-kernel module ללא הגדרות נוספות. בווירטואליזציית קונטיינרים המשתמשת ב-kernel של המארח, כגון OpenVZ או LXC, ה-modprobe wireguard ייכשל עם Operation not supported והפתרון החלופי הוא ה-wireguard-go userspace implementation. הריצו sudo modprobe wireguard && echo ok לפני כל דבר אחר.

#wireguard#vpn#linux-networking#nftables#systemd#self-hosting