התקנת Certbot ב-Ubuntu 24.04 עבור nginx
מדריך להתקנת Certbot ב-Ubuntu 24.04 באמצעות apt או snap. נלמד מדוע חשוב למנוע כפילות ב-renewal timers וכיצד להגדיר את port 80 עבור HTTP-01.
התקנת Certbot: apt או snap
ב-Ubuntu 24.04, sudo apt install certbot python3-certbot-nginx מספקת גרסה עובדת של Certbot המנפיקה תעודות Let's Encrypt אמיתיות המקובלות בציבור. התיעוד הרשמי של Certbot ממליץ להשתמש ב-snap; ההבדל ביניהם קטן — ה-snap מתעדכן לפי הגרסאות העדכניות ביותר, בעוד חבילת ה-archive עוקבת אחרי מה שנשלח עם גרסת ה-LTS ומקבלת תיקוני אבטחה.
בחרו אפשרות אחת. שתי עותקים של Certbot יוצרים שני מנגנוני חידוש (renewal timers) הפועלים על אותו עץ /etc/letsencrypt, והגרסה שתשאירו ללא מעקב היא זו שתגרום לבעיות בלתי צפויות.
השימוש ב-apt:
sudo apt update
sudo apt install certbot python3-certbot-nginxפעולה זו מתקינה את /usr/bin/certbot, את ה-nginx plugin, זוג של certbot.service + certbot.timer, ורשומה של /etc/cron.d/certbot שאינה מבצעת פעולה תחת systemd.
השימוש ב-snap:
sudo apt remove certbot python3-certbot-nginx
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbotה-snap כולל timer משלו, snap.certbot.renew.timer. יש להסיר את חבילת ה-apt לפני התקנת ה-snap.
לאחר ההתקנה, שתי השיטות מתנהגות באופן זהה. בגרסת Certbot 2.x ברירת המחדל היא מפתחות ECDSA (P-256) — השתמשו ב---key-type rsa רק עבור לקוח שאינו תומך ב-ECDSA. כל המידע נשמר תחת /etc/letsencrypt: archive/ מכילה את קבצי המפתח והתעודה האמיתיים, live/ מכילה קישורי-סימליק (symlinks) לקבצים הנוכחיים, renewal/ מכילה קובץ הגדרה אחד לכל תעודה, ו-accounts/ היא מפתח חשבון ה-ACME שלכם.
מה HTTP-01 עושה בפועל, ומדוע port 80 אינו אופציונלי
אתגר HTTP-01 הוא callback. אתה מבקש מ-Let's Encrypt תעודה עבור example.com; הוא פותר את השם ב-DNS ציבורי, פותח חיבור ל-port 80 בכתובת שנמצאה, ומבקש את http://example.com/.well-known/acme-challenge/<token>. השרת שלך עונה עם תוכן ה-token המדויק ש-Certbot כתב לכונן. זהו המנגנון המלא. שלושה השלכות נובעות ממנו, והן האחראיות לרוב הכשלים בהנפקת תעודות.
- Port 80 חייב להיות נגיש מהאינטרנט הציבורי, ולא רק מהמחשב האישי שלך. כלל
ufw, security group של ספק ענן, או firewall של קונסולת VPS שפותחים רק את 443, יכשילו את ההנפקה ואת כל חידוש עתידי. - ה-DNS חייב כבר להצביע למחשב זה. שרת האימות מבצע lookup משלו מבחוץ; לרשומות ה-
/etc/hostsשלך ולמטמון הדפדפן אין משמעות עבורו. - אם פרסמת רשומת AAAA, תשתמש ב-IPv6 תחילה. Let's Encrypt ינסה שוב ב-IPv4 אם החיבור ב-IPv6 ייכשל לחלוטין — אך רשומת AAAA לא מעודכנת המכוונת למארח שמקבל את החיבור ומגיש תוכן אחר, תגרום לכשל מוחלט.
הפניות (Redirects) מותרות: האימות עוקב אחר הפניה מ-HTTP ל-HTTPS ולא מתחשב בכך שהתעודה בצד השני חסרה, פוקעת או חתומה עצמית. מה שהוא לא יעשה הוא להתחיל בפורט שונה מ-port 80. ל-Certbot אין מימוש ל-TLS-ALPN-01, לכן "פשוט תשתמש ב-443" אינו פתרון.
בחירת authenticator: --nginx, --webroot, --standalone
--nginx הוא ברירת המחדל המתאימה כאשר nginx כבר פועל ומשרת את הדומיין. Certbot מנתח את הקונפיגורציה, מזריק מיקום זמני עבור ה-challenge, מבצע reload ל-nginx, מבצע ולידציה, ולאחר מכן כותב את הגדרות ה-TLS לתוך ה-server block שלך. ללא downtime.
sudo certbot --nginx -d example.com -d www.example.comבאופן מתוזמן (Scripted), עבור שרת חדש:
sudo certbot --nginx \
-d example.com -d www.example.com \
--agree-tos -m ops@example.com --no-eff-email \
--redirect --non-interactive--webroot מתאים כאשר ברצונך ש-Certbot לא יגע בקונפיגורציה של nginx — למשל עבור קונפיגורציה שנוצרת מ-template, נשמרת ב-git, או נדחפת באמצעות Ansible. Certbot כותב רק את קובץ ה-challenge לתוך תיקייה שכבר מוגדרת בשירות (served).
sudo certbot certonly --webroot -w /var/www/example.com \
-d example.com -d www.example.com \
--deploy-hook "systemctl reload nginx"--standalone מתאים כאשר שום שירות אינו מאזין לפורט 80: שרת דואר, API המקשיב רק לפורט 443, או סקריפט boot ראשוני שרץ לפני קיומו של nginx. Certbot תופס (binds) את פורט 80 בעצמו למשך מספר שניות. אם nginx פועל, הפעולה תיכשל — יש להפסיק אותו לפני ההרצה:
sudo certbot certonly --standalone -d mail.example.com \
--pre-hook "systemctl stop nginx" \
--post-hook "systemctl start nginx"ה-hooks הללו נשמרים בקונפיגורציית החידוש (renewal config) של התעודה, כך שפעולות ה-stop/start יתבצעו באופן אוטומטי בעת החידוש.
בלוק שרת שעובד לפני ואחרי קיום התעודה
בעיית "הביצה והתרנגול": nginx מסרב לעלות כאשר ssl_certificate מצביע על קובץ שאינו קיים, ו-Certbot אינו יכול לבצע אימות בזמן ש-nginx כבוי. הפעל את האתר בפורט 80 תחילה.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
location ^~ /.well-known/acme-challenge/ {
root /var/www/example.com;
default_type "text/plain";
try_files $uri =404;
}
location / {
try_files $uri $uri/ =404;
}
}הרץ את sudo nginx -t && sudo systemctl reload nginx, וודא שcurl -I http://example.com/ מחזיר תשובה מתוך מערכת חיצונית, ולאחר מכן הנפק את התעודה. לאחר מכן:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location ^~ /.well-known/acme-challenge/ {
root /var/www/example.com;
default_type "text/plain";
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}הקידומת ^~ ב-location של ACME קריטית: היא מונעת מהבלוק של return 301 לספוג את בקשת ה-challenge. שמירת ה-location הזו בפורט 80 מבטיחה שהחידושים (renewals) ימשיכו לעבוד גם לאחר שהאתר כולו יעבור ל-HTTPS בלבד.
תחביר HTTP/2 תלוי בגרסת ה-nginx שלך, וערבוב בין שתי הצורות יגרום לשגיאת startup. בגרסת Ubuntu 24.04 מגיע nginx 1.24, הדורש הגדרה inline — listen 443 ssl http2;. בגרסת Debian 13 מגיע nginx חדש יותר, הדורש את הדירקטיבה http2 on; בנפרד. בדוק תחילה את nginx -v.
הפנה את nginx אל live/, לעולם לא אל archive/. ה-symlinks של live/ מתעדכנים בכל חידוש; שימוש בנתיב קשיח (hard path) אל archive/ יגרום לכך שתתקע עם תעודה שתפוג.
Wildcards משמעותם DNS-01, ו-DNS-01 מחייב שימוש ב-plugin
לא ניתן לאמת תעודת wildcard (*.example.com) באמצעות HTTP-01 — אין שם מארח (hostname) יחיד שניתן להוריד ממנו קובץ. DNS-01 הוא הדרך היחידה: עליך להוכיח שליטה על הדומיין על ידי פרסום רשומת _acme-challenge.example.com TXT. כדי ש-Certbot יבצע זאת באופן אוטומטי, הוא זקוק לפרטי ה-API של ספק ה-DNS שלך; זהו התפקיד של ה-plugins של הספק. מדריך מלא לתעודת wildcard מסביר את המנגנון של רשומת ה-TXT ואת בעיית החידוש במצב ידני (manual mode); לאחר מכן מופיעה גרסה קצרה עבור Cloudflare.
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflareבנתיב ה-apt, המצב הוא sudo apt install python3-certbot-dns-cloudflare. פרטי ההזדהות נשמרים בקובץ עבור root בלבד:
# /root/.secrets/cloudflare.ini
# then: sudo chmod 600 /root/.secrets/cloudflare.ini
dns_cloudflare_api_token = your_scoped_token_hereהגבל את ה-token להרשאות DNS-edit ב-zone הספציפי בלבד. זהו מפתח ל-DNS שלך; התייחס אליו כך.
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d '*.example.com'השתמש בגרשיים סביב ה-wildcard כדי שה-shell לא יבצע עליו globbing. DNS-01 פותר גם בעיה ש-HTTP-01 אינו יכול לפתור: הנפקת תעודות עבור מארחים ללא פורט 80 פתוח לציבור — שירות פנימי, שרת הנגיש רק דרך self-hosted WireGuard VPN on a VPS, או פאנל ניהול בממשק פרטי.
חידוש: 90 הימים, הטיימר, ו-deploy hook
תעודות Let's Encrypt תקפות למשך 90 יום. Certbot מבצע חידוש כאשר נותרו פחות מ-30 יום, מה שמעניק חלון זמן של 30 יום שבו חידוש שנכשל הוא תקלה שניתן לפתרון ולא השבתה של השירות. Let's Encrypt כבר לא שולחת אימיילים של אזהרת תפוגה — אף אחד לא יעדכן אתכם באופן ידני, לכן האחריות על הניטור היא עליכם.
בדקו את הטיימר שהתקנה שלכם כוללת:
systemctl list-timers 'certbot*' 'snap.certbot*'
sudo certbot certificatescertbot renew סורק כל קונפיגורציה ב-/etc/letsencrypt/renewal/, מדלג על כל מה שנמצא מחוץ לחלון ה-30 יום, ומחדש את השאר בדיוק עם ה-flags של ההרצה המקורית. זו הסיבה שההרצה הראשונה חשובה: היא זו שנשמרת בתיעוד.
חידוש הקובץ בדיסק אינו משנה דבר בפני עצמו — nginx ממשיך להגיש את התעודה הישנה מהזיכרון עד שפקודה כלשהי תורה לו לבצע reload. הגדירו deploy hook פעם אחת:
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/sh
set -e
nginx -t && systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shכל קובץ בר-הרצה ב-renewal-hooks/deploy/ ירוץ לאחר כל חידוש מוצלח. ה-flag של --deploy-hook מבצע פעולה דומה עבור תעודה אחת, ושומר את renew_hook = ... בקונפיגורציית החידוש שלו. certbot --nginx מבצע reload עבורכם; הגדרות --webroot ו---standalone אינן עושות זאת. היעדר hook הוא הסיבה המדויקת לכך שאתר מגיש תעודה פוקעת בזמן ש-certbot certificates מדווח בשמחה על תעודה חדשה. כל רכיב אחר שקורא את התעודה בזמן העלייה (startup) זקוק לאותו hook — אפליקציה מבוססת קונטיינר כגון Nextcloud VPS install with Docker, TLS and backups זקוקה גם היא לשלב restart או reload מוגדר כאן.
בדיקת חידוש בפועל
sudo certbot renew --dry-runפעולה זו מריצה את ה-challenge המלא מול סביבת ה-staging של Let's Encrypt: אותו נתיב קוד, אותו firewall, אותו DNS, ללא הגבלת קצב (rate-limit), ולא נכתב דבר לדיסק. אם הבדיקה עוברת היום, גם החידוש האוטומטי (unattended renewal) בעוד 60 יום יעבור, בהנחה ששום דבר בהגדרות השרת לא ישתנה.
dry run אינו מוכיח ש-reload hook פועל — ההתנהגות משתנה בין גרסאות Certbot שונות. יש לבדוק חלק זה באופן ידני: הרץ את ה-hook script ישירות, וודא ש-systemctl reload nginx מצליח, ובדוק את sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.
השגיאות שבהן תיתקלו בפועל
Could not bind to IPv4 or IPv6. — --standalone מכיוון ש-nginx כבר תופס את port 80. השתמש ב---nginx או ב---webroot, או עצור את nginx לפני ההרצה. בדוק מי תופס את הפורט באמצעות sudo ss -lntp | grep ':80'.
Timeout during connect (likely firewall problem) — Let's Encrypt לא הצליח להגיע ל-port 80. בדוק את השלבים הבאים: sudo ufw status (פתח אותו באמצעות sudo ufw allow 'Nginx Full'), לאחר מכן את ה-firewall של ספק ה-VPS, ולאחר מכן את ה-DNS. בדוק משרת חיצוני שאינו השרת שלך: curl -sSv http://example.com/.well-known/acme-challenge/test. רשומת AAAA שאינה מעודכנת תפיק הודעה זו.
unauthorized :: Invalid response from http://example.com/.well-known/acme-challenge/xyz: 404 — port 80 נגיש, אך ה-token אינו נשלח. הבקשה הגיעה ל-server block אחר (בדוק איזה block מחזיק ב-default_server), או שהספרייה שהועברה ל--w אינה הספרייה ש-nginx משרת. צור קובץ ב-/var/www/example.com/.well-known/acme-challenge/test ונסה לגשת אליו מבחוץ; אם מתקבל 404, הבעיה אינה בתעודה.
DNS problem: NXDOMAIN looking up A for example.com — השם אינו נפתר (resolve) באופן ציבורי. רשומות חדשות שטרם הופצו, או רשומה באזור (zone) שרשם הדומיינים שלך אינו משרת.
too many certificates already issued for: example.com — הגבלת קצב (rate limit), השגיאה הנפוצה בזמן ניסוי וטעייה בלולאה. Let's Encrypt מגביל תעודות כפולות — בדיוק אותן רשימות שמות — לחמש תעודות בשבוע, ובנפרד מאפשר 50 תעודות חדשות לכל דומיין רשום בשבוע; שום דבר לא יבטל את ההגבלה מלבד זמן. בצע debug מול ה-staging באמצעות --dry-run.
nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": No such file or directory — nginx מוגדר עבור תעודה שלא הונפקה מעולם, או כזו שהוסרה באמצעות certbot delete. בטל את ה-TLS server block (באמצעות comment), הפעל את nginx, הנפק את התעודה, והחזר את הבלוק.
open() "/etc/letsencrypt/options-ssl-nginx.conf" failed — הקובץ מגיע עם חבילת ה-nginx plugin. במערכת certonly ללא python3-certbot-nginx, הוסף את ה-plugin או החלף את שורת include בהגדרות ה-ssl_protocols וה-ssl_ciphers שלך.
ניהול בתscale
תעודה אחת יכולה להכיל עד 100 שמות, ושימוש ב-certbot --nginx -d a.example.com -d b.example.com ... יחיד הוא פיתוי — עד שרשומת DNS ישנה נכשלת באימות ולוקחת איתה את כל שאר השמות בתעודה. תעודות נפרדות לכל אתר נכשלות באופן עצמאי, וזה המצב הרצוי במערכת המארחת יותר מפריט אחד או שניים. מעבר לכמה אתרים, front door תומך ACME שווה את השקעה: Traefik reverse proxy running multiple apps under Docker Compose מבקש ומחדש את התעודות בעצמו, ו-Certbot אינו נחוץ יותר.
גבה את /etc/letsencrypt במלואו — sudo tar -czf letsencrypt-$(date +%F).tar.gz -C /etc letsencrypt — כולל symlinks. עץ התיקיות הזה מכיל את accounts/, מפתח חשבון ה-ACME שלך, שלא ניתן ליצור מחדש בצורה זהה. מעבר ל-VPS חדש מצטמצם לצעדים הבאים: rsync של העץ עם -a, התקנת Certbot, עדכון ה-DNS, והרצת certbot renew --dry-run לפני המעבר בפועל.
בנייה מחדש של השרת או מעבר לגרסת LTS חדשה יגרמו לכך שמונה המשימות (renewal timer) לא יעבור איתך. לאחר כל הגירה, שחזור snapshot, או שדרוג distro, הרץ את systemctl list-timers 'certbot*' ו---dry-run אחד. דילוג על שלב זה הוא הסיבה שאתר מפסיק לעבוד 89 ימים לאחר מכן, בשעה 3:00 לפנות בוקר, בתעודה שכולם הניחו שהיא מתחדשת מעצמה.
כל זה מניח שאתה שולט במכונה בעלת IP ציבורי ופורט 80 פתוח לעולם — במילים אחרות, VPS. המנגנונים לעיל זהים בכל אחד מהם.
אותם שלבי תעודה תקפים גם on Apache instead of nginx, וכאשר תעודה ציבורית אינה אפשרות, a self-signed certificate on Ubuntu תספק מענה לשירותים פנימיים.
FAQ
האם אני צריך לפתוח את פורט 80 אם האתר שלי משרת רק HTTPS?
כן, עבור HTTP-01 challenge. Let's Encrypt תמיד מתחילה את בקשת האימות בפורט 80. ל-Certbot אין מימוש של TLS-ALPN-01, לכן חומת אש שפותחת רק את פורט 443 תחסום גם את ההנפקה הראשונה וגם כל חידוש אוטומטי לאחר מכן. הפניה (redirect) מפורט 80 ל-HTTPS היא תקינה — האימות עוקב אחריה. הדרך היחידה לדלג על פורט 80 לחלוטין היא באמצעות DNS-01 עם תוסף ספק (provider plugin).
apt או snap — באיזה Certbot עלי להתקין עבור nginx ב-Ubuntu 24.04?
השתמש ב-apt. sudo apt install certbot python3-certbot-nginx מספקת לך את Certbot 2.9.0 ב-Ubuntu 24.04, גרסה עדכנית מספיק לכל מה שמופיע במדריך זה. היא מקבלת עדכוני אבטחה דרך unattended-upgrades ואינה דורשת את snapd. בחר ב-snap רק אם אתה זקוק לגרסה החדשה ביותר באופן מיידי או אם אתה זקוק לתוסף DNS המופץ אך ורק כ-snap. בכל מקרה, בחר רק אחת: שתי התקנות פירושן שני מנגנוני חידוש (renewal timers) המכוונים לאותו עץ /etc/letsencrypt, וההתקנה שנשכחת היא זו שתגרום לבעיה.
האם Certbot יכול להנפיק תעודת wildcard עבור nginx?
רק באמצעות DNS-01. ל-wildcard כמו *.example.com אין שם מארח (hostname) יחיד כדי למשוך ממנו קובץ אימות, לכן --nginx, --webroot ו---standalone אינם אפשריים. התקן את התוסף עבור ספק ה-DNS שלך, שים טוקן API עם הרשאות מוגבלות בקובץ הרשאות המיועד ל-root בלבד, והרץ את certbot certonly --dns-cloudflare -d example.com -d '*.example.com', תוך שימוש במירכאות סביב ה-wildcard כדי למנוע מה-shell לבצע globbing.
מדוע nginx עדיין משרת את התעודה הישנה לאחר חידוש מוצלח?
nginx שומר את התעודה בזיכרון ואינו מזהה את הקובץ החדש בדיסק עד לביצוע reload. certbot --nginx מבצע reload עבורך, אך הרצות של --webroot ו---standalone אינן עושות זאת, ולכן חידוש יכול להצליח בעוד הדפדפן עדיין מציג תעודה שעומדת פוקעת. הנח סקריפט הרצה בתוך /etc/letsencrypt/renewal-hooks/deploy/ שמריץ את nginx -t && systemctl reload nginx; הוא יופעל לאחר כל חידוש מוצלח.
האם certbot renew --dry-run מוכיח שהחידוש יעבוד?
ברוב המקרים. הוא מריץ את האימות האמיתי מול סביבת ה-staging — עם אותה חומת אש, אותו DNS ואותו נתיב קוד — ללא עלות של מגבלת קצב (rate-limit) וללא כתיבה לדיסק. לכן, הצלחה פירושה שחלק הרשת תקין. עם זאת, הוא אינו מוכיח באופן אמין ש-deploy hook שלך מופעל. בדוק זאת בנפרד: הרץ את סקריפט ה-hook ידנית ובדוק את sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.