SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-31

מדריך הקמת WireGuard על שרת VPS: הגדרה ופתרון תקלות

למדו להקים שרת VPN עצמאי עם WireGuard על Linux. המדריך כולל יצירת מפתחות, הגדרת wg0.conf, ניתוב IP, חוקי NAT ופתרון תקלות נפוצות ב-handshake ובהרשאות קבצים בשרת.

מה אתם בונים

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

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

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

WireGuard דורש ליבה שניתן לטעון לתוכה מודול, ובשרת VPS מסוג KVM הוא עובד ללא הגדרות נוספות. בווירטואליזציה מבוססת מכולות המשתפת את ליבת המארח, כגון 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 יוצר. הגדירו את ההרשאות במפורש.

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

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

ממשק השרת: /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 אותו; אזהרת עלייה המציינת כי הקובץ נגיש לכל משתמש מעידה על כך שדילגת על שלב זה. Address היא כתובת השרת בתוך המנהרה, והיא נושאת את ה־mask של כל רשת ה־VPN. בחר טווח שלא תיתקל בו ברשתות חיצוניות; 192.168.1.0/24 מתנגש עם מחצית מנתבי הבית שמאחוריהם נמצאים הלקוחות שלך, והמנהרה תפסיק להעביר תעבורה בשקט לטובת הניתוב המקומי.

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

הפיכת השרת לנתב

שרת Linux משליך חבילות מידע שאינן ממוענות אליו. כברירת מחדל, העברת חבילות (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, כלומר כרטיס הרשת שדרכו מגיעים לאינטרנט, ולא את wg0. אל תניחו שזהו eth0; בדקו את שם הממשק שלכם באמצעות ip route show default, כיוון שתמונות מערכת עדכניות משתמשות בשמות כמו enp1s0 או ens3.

חומת אש: הפורט ונתיב ההעברה

קובץ nftables אחד מרכז את ה-filter ואת ה-NAT. כתבו את /etc/nftables.conf; פעולה זו מרוקנת את סט החוקים הקיים, לכן דלגו עליה בשרת שמנוהל כבר על ידי 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 שני פתוח: טעות הקלדה ב-policy drop בחוק ה-SSH תנעל אתכם מחוץ לשרת שלכם. שימו לב למה ששרשרת ה-forward אינה מאפשרת, מ-wg0 ועד wg0. עמיתים (peers) מגיעים לאינטרנט, אך לא זה לזה; הוסיפו את iifname "wg0" oifname "wg0" accept עבור VPN מסוג peer-to-peer. אותה שרשרת קובעת למה עמית רשאי לגשת בשרת עצמו, דבר שחשוב כאשר השרת משמש גם כ-סביבת פיתוח מרוחקת המריצה Claude Code בתוך tmux ואתם מעדיפים לא לחשוף צד זה שלו באופן ציבורי.

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

העלאת השירות תחת systemd

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

wg-quick יוצר את הממשק, מוסיף את הכתובות ומתקין נתיבים הנגזרים מ-AllowedIPs. enable --now הוא החצי החשוב: הרצה ידנית של wg-quick up wg0 נמחקת לאחר האתחול הבא, ושדרוגי ליבה מחייבים אתחולים. יחידה שנכשלת לעלות לאחר אחד מאותם אתחולים נשארת דוממת עד שמישהו מנסה להתחבר, לכן הגדרת drop-in מסוג OnFailure= ב-wg-quick@wg0 המפנה אל שרת ntfy משלך היא הדרך הזולה ביותר לקבל על כך התראה לטלפון במקום לשמוע על כך ממשתמש חסום.

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

[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.

בכיוון יוצא, זהו טבלת ניתוב. חבילה שיעד הכתובת שלה תואם ל-AllowedIPs של עמית (peer), מוצפנת ונשלחת לאותו עמית. 0.0.0.0/0, ::/0 שולח את כל התעבורה דרך המנהרה, מה שיוצר מנהרה מלאה (full tunnel) שבה השרת משמש כנתיב ברירת מחדל. מנהרה מפוצלת (split tunnel) היא רשימה מצומצמת יותר: AllowedIPs = 10.8.0.0/24, 10.20.0.0/16 מעביר תעבורת VPN בתוספת רשת פרטית אחת מאחורי השרת, בעוד שכל שאר התעבורה ממשיכה בנתיב המקומי שלה. רשימה מצומצמת זו היא שמאפשרת לכם להשאיר שירותים מחוץ לאינטרנט הציבורי לחלוטין, כמו מופע Nextcloud פרטי ב-VPS המקושר לכתובת המנהרה, או מכונות וירטואליות במעבדת וירטואליזציה מקוננת הרצות על אותו שרת, כך שהן נשארות נגישות לעמיתים ובלתי נראות לכל השאר.

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

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

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

עם AllowedIPs = 0.0.0.0/0 וללא שורת DNS =, הלקוח ממשיך להשתמש ב־resolver שהוא למד מהרשת המקומית, כלומר הנתב של בית הקפה בכתובת 192.168.1.1. נתיב זה ספציפי יותר מנתיב ברירת המחדל, ולכן שאילתות DNS יוצאות דרך החיבור המקומי בטקסט גלוי, בעוד שכל שאר התעבורה עוברת במנהרה. התעבורה עצמה פרטית; רשימת השמות שאליהם אתם פונים – לא.

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

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

הוספה והסרה של עמיתים (peers) ללא ניתוק המנהרה

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

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

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

מצבי כשל והודעות שגיאה נפוצות

לחיצת היד (handshake) אינה מושלמת. הפקודה wg show מציגה את העמית ללא latest handshake, ובלוג הלקוח מופיע:

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

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

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

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

אתרי HTTPS מסוימים נתקעים. SSH ו-ping עובדים כראוי; דפים כבדים נתקעים. מדובר בבעיית MTU: המנהרה מוסיפה תקורה (overhead), ואחד הצמתים בדרך משליך חבילות גדולות מדי מבלי להחזיר הודעת ICMP. הקטינו את ה-MTU ב-[Interface] של הלקוח, נסו את 1420, לאחר מכן את 1380, ולבסוף את 1280. אם הקטנת ה-MTU פותרת את התקיעות אך קצב העברת הנתונים עדיין אינו מספק, הפסיקו לנחש מספרים עגולים ופעלו לפי מציאת ה-MTU האמיתי של הנתיב באמצעות חצייה ו-clamping ל-TCP MSS, מה שישלול גם גורמים שאינם קשורים למנהרה כלל.

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

הגירה מ-Streisand או מ-OpenVPN

הפרויקט Streisand אינו מתוחזק עוד והמאגר שלו בארכיון; הרצת VPN על גבי אוטומציה נטושה מהווה סיכון אבטחה מתמשך. לא קיים מסלול שדרוג ישיר, ומערכת ה-PKI של OpenVPN אינה ניתנת להמרה: ל-WireGuard אין תעודות, אין CA ואין תאריכי תפוגה, לכן כל לקוח מקבל זוג מפתחות חדש.

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

גיבויים, שדרוגים ומגבלות בקנה מידה גדול

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

מצב (state) של peer בודד הוא קטן והצפנה רצה בתוך ה־kernel, לכן התקרה היא ה־CPU ורוחב הפס של ה־VPS שלכם ולא הגדרה כלשהי בקובץ זה; מדדו זאת עם iperf3 דרך ה־tunnel במקום להסתמך על נתונים מפורסמים. מה שיוצר עומס בקנה מידה גדול הוא התפעול. כל peer זקוק לכתובת IP ייחודית בתוך ה־tunnel, ועריכה ידנית של שישים בלוקים של [Peer] היא הדרך שבה AllowedIPs כפולים מחליקים פנימה: צרו את הקבצים באמצעות סקריפט. שרת אחד הוא נקודת קצה UDP אחת ונקודת כשל אחת, ול־WireGuard אין יכולת clustering: יתירות משמעותה שרת שני עם מפתחות משלו. החלפת מפתחות (rotation) נשארת ידנית, לכן תעדו מי מחזיק איזה מפתח וכיצד אתם מבטלים אחד. ברגע שהניהול הזה חורג מקובץ טקסט, התשובה המקובלת היא control plane שיושב מעל אותו data plane של ה־kernel, ו־שרת NetBird באירוח עצמי מטפל בהקצאת כתובות, הפצת peers ומפתחות התקנה שאתם מבצעים כעת ידנית. אם הרצת ה־control plane בעצמכם היא שרת אחד יותר מדי, Tailscale מארחת אחד עבורכם, ו־התוכנית החינמית שלה מכסה שישה משתמשים עם מכשירים ללא הגבלה, מספיק כדי שרוב ציי המכשירים האישיים לעולם לא ישלמו על כך. מעבר לנקודה זו התשלום מבוסס על אנשים ולא על מכונות, לכן מה שמשק בית או צוות קטן משלמים בפועל תלוי בכמה בני אדם מחזיקים פרטי התחברות, לא בכמה peers הייתם עורכים ידנית לתוך wg0.conf. בצד הזה, ניהול ה־split-tunnel ב־AllowedIPs הופך ל־פרסום הטווחים הפרטיים שלכם מתוך subnet router, שמוכרז פעם אחת מ־VPS אחד ומאושר מרכזית במקום להיות מודבק לתוך כל קובץ לקוח. השאלה אם כדאי לבצע את ההחלפה הזו תלויה במה ש־control plane מנוהל יכול להגיע אליו בפועל, ו־הוא לעולם לא מחזיק את המפתחות שמצפינים את התעבורה שלכם, אם כי הוא מחליט אילו peers יכירו זה את זה.

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

FAQ

מדוע לחיצת היד (handshake) של WireGuard לעולם אינה מסתיימת?

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

המנהרה מתחברת אך אין לי גישה לאינטרנט. מה חסר?

כאשר 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 עבור ממשק היציאה האמיתי שלכם מתוך ip route show default, enp1s0 או ens3, ולעיתים רחוקות eth0.

האם אני זקוק לשורת DNS = בתצורת הלקוח שלי?

במנהרה מלאה ללא שורת DNS =, הלקוח ממשיך להשתמש ב-resolver שלמד מהרשת המקומית. שאילתות אלו יוצאות בטקסט גלוי דרך החיבור המקומי, בעוד שאר התעבורה עוברת במנהרה. כוונו את DNS ל-resolver ציבורי, או הריצו unbound/dnsmasq המאזין ל-10.8.0.1 ופתחו את udp dport 53 iifname "wg0" בשרשרת ה-input.

מה בדיוק מנהל AllowedIPs?

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

האם WireGuard ירוץ על כל VPS?

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