SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor

Instal Certbot untuk nginx di Ubuntu 24.04

Pasang certbot python3-certbot-nginx dengan apt, lalu jalankan certbot --nginx sekali. Pahami perbedaan apt dan snap serta timeout port 80 saat pembaruan.

Instal Certbot: apt atau snap

Pada Ubuntu 24.04, sudo apt install certbot python3-certbot-nginx menyediakan Certbot yang dapat menerbitkan sertifikat Let's Encrypt yang valid dan dipercaya publik. Dokumentasi upstream Certbot mengarahkan Anda ke snap. Perbedaannya terbatas: snap mengikuti rilis upstream, sedangkan paket archive mengikuti versi yang disertakan dalam LTS dan menerima perbaikan keamanan.

Pilih salah satu. Dua salinan Certbot berarti ada dua timer pembaruan yang menargetkan tree /etc/letsencrypt yang sama. Salinan yang Anda lupakan akan menimbulkan masalah.

Jalur apt:

sudo apt update
sudo apt install certbot python3-certbot-nginx

Perintah tersebut menginstal /usr/bin/certbot, plugin nginx, pasangan certbot.service + certbot.timer, serta entri /etc/cron.d/certbot yang tidak melakukan apa pun di bawah systemd.

Jalur 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 menyediakan timer-nya sendiri, snap.certbot.renew.timer. Hapus paket apt sebelum menginstal snap.

Setelah itu, kedua instalasi berfungsi dengan cara yang sama, kecuali waktu saat keduanya memutuskan untuk memperbarui sertifikat (dibahas pada bagian Pembaruan di bawah). Secara default, Certbot 2.x menggunakan key ECDSA (P-256). Gunakan --key-type rsa hanya untuk client yang tidak mendukung ECDSA. Semua state disimpan di bawah /etc/letsencrypt: archive/ menyimpan file key dan sertifikat yang sebenarnya, live/ berisi symlink ke file yang sedang digunakan, renewal/ menyimpan satu file konfigurasi untuk setiap sertifikat, dan accounts/ menyimpan key akun ACME Anda.

Apa yang sebenarnya dilakukan HTTP-01, dan mengapa port 80 tidak bersifat opsional

Challenge HTTP-01 adalah callback. Anda meminta sertifikat dari Let's Encrypt yang mencakup example.com; Let's Encrypt mencari nama tersebut di DNS publik, membuka koneksi ke port 80 pada alamat yang ditemukan, lalu meminta http://example.com/.well-known/acme-challenge/<token>. Server Anda merespons dengan isi token yang baru saja ditulis Certbot ke disk. Itulah seluruh mekanismenya. Tiga konsekuensi berikut menjelaskan sebagian besar kegagalan penerbitan sertifikat.

  • Port 80 harus dapat dijangkau dari Internet publik, bukan hanya dari laptop Anda. Aturan ufw, security group dari penyedia cloud, atau firewall pada konsol VPS yang hanya membuka port 443 akan menggagalkan penerbitan dan semua pembaruan sertifikat berikutnya.
  • DNS harus sudah mengarah ke server ini. Server validasi melakukan lookup sendiri dari luar; entri /etc/hosts dan cache browser Anda tidak berpengaruh.
  • Jika Anda menerbitkan record AAAA, IPv6 akan dicoba terlebih dahulu. Let's Encrypt hanya mencoba kembali melalui IPv4 jika koneksi IPv6 mengalami timeout. Koneksi IPv6 yang ditolak tidak akan dicoba ulang, dan record AAAA yang usang serta mengarah ke host yang menerima koneksi tetapi menyajikan layanan lain akan menyebabkan kegagalan permanen.

Redirect diperbolehkan: validasi mengikuti redirect HTTP ke HTTPS dan tidak mempermasalahkan sertifikat pada tujuan yang tidak ada, sudah kedaluwarsa, atau ditandatangani sendiri. Namun, proses ini tidak akan dimulai dari port selain port 80. Certbot tidak memiliki implementasi TLS-ALPN-01, jadi "cukup gunakan 443" bukan solusi.

Memilih authenticator: --nginx, --webroot, --standalone

--nginx adalah pilihan default yang tepat jika nginx sudah berjalan dan sudah melayani domain tersebut. Certbot membaca konfigurasi Anda, memasukkan lokasi challenge sementara, memuat ulang nginx, melakukan validasi, lalu menulis direktif TLS ke dalam server block Anda. Tidak ada downtime.

sudo certbot --nginx -d example.com -d www.example.com

Berikut contoh berbasis skrip untuk server baru:

sudo certbot --nginx \
  -d example.com -d www.example.com \
  --agree-tos -m ops@example.com --no-eff-email \
  --redirect --non-interactive

--webroot tepat jika Anda tidak ingin Certbot menyentuh konfigurasi nginx, misalnya karena konfigurasi dibuat dari template, disimpan di git, atau diterapkan menggunakan Ansible. Certbot hanya menulis file challenge ke direktori yang sudah Anda layani.

sudo certbot certonly --webroot -w /var/www/example.com \
  -d example.com -d www.example.com \
  --deploy-hook "systemctl reload nginx"

--standalone tepat jika tidak ada proses yang listening pada port 80: misalnya mail server, API yang hanya menggunakan 443, atau skrip first-boot yang berjalan sebelum nginx tersedia. Certbot sendiri akan bind ke port 80 selama beberapa detik. Jika nginx sedang berjalan, proses ini gagal. Hentikan nginx sebelum menjalankannya, lalu jalankan kembali setelah selesai:

sudo certbot certonly --standalone -d mail.example.com \
  --pre-hook "systemctl stop nginx" \
  --post-hook "systemctl start nginx"

Hook tersebut dicatat dalam konfigurasi renewal sertifikat, sehingga proses stop/start yang sama dilakukan tanpa intervensi saat renewal.

Blok server yang berfungsi sebelum dan sesudah sertifikat tersedia

Masalah ayam dan telur: nginx menolak start jika ssl_certificate mengarah ke file yang tidak ada, sedangkan Certbot tidak dapat melakukan validasi ketika nginx berhenti. Aktifkan situs pada port 80 terlebih dahulu.

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;
    }
}

Jalankan sudo nginx -t && sudo systemctl reload nginx, pastikan curl -I http://example.com/ memberikan respons dari luar server, lalu terbitkan sertifikat. Setelah itu:

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;
    }
}

Prefix ACME yang lebih panjang sudah diprioritaskan daripada location /, sehingga return 301 tidak pernah menerima permintaan challenge. Modifier ^~ berguna di tempat lain: setelah prefix tersebut cocok, nginx melewati location regex sepenuhnya. Dengan demikian, aturan yang ditambahkan kemudian, seperti location ~ /\. { deny all; }, tidak dapat memblokir challenge. Mempertahankan location tersebut pada port 80 memastikan renewal tetap berfungsi setelah seluruh situs hanya menggunakan HTTPS.

Kedua blok di atas menyajikan file dari disk. Jika nginx justru berada di depan sebuah aplikasi, location / menjadi blok proxy_pass. Blok server reverse proxy, baris demi baris menjelaskan header yang diperlukan aplikasi tersebut, sedangkan location ACME dan directive TLS tetap sama persis.

Sintaks HTTP/2 bergantung pada versi nginx yang Anda gunakan. Ubuntu 24.04 menyertakan nginx 1.24, yang mengharuskan sintaks inline, listen 443 ssl http2;, dan gagal start jika Anda memberinya directive http2 on; terpisah. Debian 13 menyertakan nginx 1.26, yang mengharuskan http2 on; dan hanya memberikan peringatan bahwa bentuk inline sudah deprecated. Periksa nginx -v terlebih dahulu.

Arahkan nginx ke live/, bukan ke archive/. Symlink live/ diarahkan ulang setiap kali renewal. Path langsung ke dalam archive/ membuat Anda tetap menggunakan sertifikat yang akhirnya kedaluwarsa.

Wildcard berarti DNS-01, dan DNS-01 berarti plugin

Sertifikat wildcard (*.example.com) tidak dapat divalidasi melalui HTTP-01 karena tidak ada satu hostname tertentu untuk mengambil file. DNS-01 adalah satu-satunya cara: Anda membuktikan kendali dengan menerbitkan record TXT _acme-challenge.example.com. Certbot memerlukan kredensial API untuk provider DNS Anda agar proses ini dapat berjalan tanpa intervensi. Plugin provider digunakan untuk keperluan tersebut. Panduan lengkap sertifikat wildcard menjelaskan mekanisme record TXT dan masalah renewal dalam mode manual. Versi singkat untuk Cloudflare ada di bawah ini.

sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare

Pada jalur apt, gunakan sudo apt install python3-certbot-dns-cloudflare sebagai gantinya. Simpan kredensial dalam file yang hanya dapat diakses oleh root:

# /root/.secrets/cloudflare.ini
# then: sudo chmod 600 /root/.secrets/cloudflare.ini
dns_cloudflare_api_token = your_scoped_token_here

Batasi token agar hanya memiliki hak untuk mengubah DNS pada satu zone tersebut. Token ini adalah kunci untuk DNS Anda. Perlakukan token ini dengan semestinya.

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
  -d example.com -d '*.example.com'

Gunakan tanda kutip pada wildcard agar shell tidak melakukan globbing. DNS-01 juga mengatasi hal yang tidak dapat dilakukan HTTP-01: menerbitkan sertifikat untuk host tanpa port publik 80, service internal, mesin yang hanya dapat dijangkau melalui WireGuard yang di-host sendiri pada VPS, atau panel admin pada interface privat.

Perpanjangan: 90 hari, timer, dan deploy hook

Sertifikat Let's Encrypt berlaku selama 90 hari. Paket apt (Certbot 2.9.0) melakukan perpanjangan ketika masa berlaku tersisa kurang dari 30 hari. snap menggunakan Certbot versi terbaru. Sejak versi 4.1, Certbot juga meminta waktu perpanjangan yang disarankan kepada Let's Encrypt melalui ACME Renewal Info (ARI) dan dapat melakukan perpanjangan lebih awal. Untuk sertifikat Let's Encrypt, perpanjangan biasanya dilakukan setelah sekitar dua pertiga masa berlaku terlewati. Dengan kedua mekanisme tersebut, tersedia jendela waktu sekitar 30 hari untuk memperbaiki perpanjangan yang gagal sebelum menimbulkan gangguan layanan. Mulai tahun depan, perpanjangan akan lebih sering dilakukan. Profil default Let's Encrypt beralih ke sertifikat 64 hari pada February 10, 2027, dan ke sertifikat 45 hari pada February 16, 2028. Let's Encrypt tidak lagi mengirim email peringatan kedaluwarsa. Tidak ada pihak yang akan mengingatkan Anda, jadi pemantauan kini menjadi tanggung jawab Anda.

Periksa timer yang disertakan dalam instalasi Anda:

systemctl list-timers 'certbot*' 'snap.certbot*'
sudo certbot certificates

certbot renew memeriksa setiap konfigurasi di /etc/letsencrypt/renewal/, melewati konfigurasi yang belum waktunya diperpanjang, lalu memperpanjang konfigurasi lainnya menggunakan opsi yang tersimpan di dalam konfigurasi tersebut. Opsi itu adalah flag dari eksekusi awal, kecuali Anda telah mengubahnya dengan certbot reconfigure. Karena itu, eksekusi pertama penting: eksekusi tersebut yang dicatat.

Memperbarui file sertifikat pada disk tidak mengubah apa pun dengan sendirinya. nginx tetap menyajikan sertifikat lama dari memori sampai ada perintah untuk memuat ulang konfigurasi. Konfigurasikan deploy hook sekali:

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

Semua file yang dapat dieksekusi di renewal-hooks/deploy/ dijalankan setelah perpanjangan berhasil. Flag --deploy-hook menjalankan fungsi yang sama untuk satu sertifikat dan menyimpan renew_hook = ... dalam konfigurasi perpanjangannya. certbot --nginx melakukan reload untuk Anda. Konfigurasi --webroot dan --standalone tidak melakukannya. Hook yang tidak ada adalah alasan situs masih menyajikan sertifikat kedaluwarsa, sementara certbot certificates melaporkan sertifikat baru dengan normal. Apa pun yang membaca sertifikat saat start memerlukan hook yang sama. Aplikasi dalam container, seperti instalasi Nextcloud VPS dengan Docker, TLS, dan backup, juga memerlukan langkah restart atau reload tersendiri yang dikonfigurasikan di sini.

Menguji perpanjangan secara nyata

sudo certbot renew --dry-run

Perintah tersebut menjalankan challenge lengkap terhadap staging environment Let's Encrypt: jalur kode, firewall, dan DNS yang sama; tidak ada yang dihitung terhadap batas rate produksi Anda (staging memiliki batasnya sendiri yang jauh lebih longgar); dan tidak ada sertifikat yang disimpan ke disk. Jika pengujian ini berhasil hari ini, renewal otomatis tanpa intervensi juga akan berhasil dalam 60 hari, selama tidak ada perubahan pada server.

Dry run tidak membuktikan bahwa reload hook Anda dijalankan. Perilakunya berbeda-beda bergantung pada versi Certbot. Uji bagian tersebut secara manual: jalankan skrip hook secara langsung, pastikan systemctl reload nginx berhasil, lalu periksa sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.

Error yang benar-benar akan Anda temui

Could not bind to IPv4 or IPv6., --standalone saat nginx sudah menggunakan port 80. Gunakan --nginx atau --webroot, atau hentikan nginx selama proses berjalan. Pastikan proses yang menggunakan port tersebut dengan sudo ss -lntp | grep ':80'.

Timeout during connect (likely firewall problem), Let’s Encrypt tidak dapat menjangkau port 80. Periksa dari luar ke dalam: sudo ufw status (buka dengan sudo ufw allow 'Nginx Full'), lalu firewall milik penyedia VPS, kemudian DNS. Uji dari lokasi yang bukan server Anda: curl -sSv http://example.com/.well-known/acme-challenge/test. Entri AAAA yang sudah usang dapat menghasilkan pesan yang sama.

unauthorized :: Invalid response from http://example.com/.well-known/acme-challenge/xyz: 404, port 80 dapat dijangkau, tetapi token tidak disajikan. Permintaan masuk ke server block yang berbeda (periksa server block yang memiliki default_server), atau direktori yang diberikan ke -w bukan direktori yang disajikan nginx. Buat file di /var/www/example.com/.well-known/acme-challenge/test, lalu ambil file tersebut dari luar server. Jika menghasilkan 404, masalahnya bukan pada sertifikat.

DNS problem: NXDOMAIN looking up A for example.com, nama tersebut tidak dapat di-resolve secara publik. Penyebabnya dapat berupa record baru yang belum terpropagasi atau record di zone yang tidak disajikan oleh registrar Anda.

too many certificates (5) already issued ..., terjadi rate limit. Ini sering dialami saat melakukan debugging berulang kali. Pesan tersebut menyebutkan batasnya dan diakhiri dengan waktu retry after. Let’s Encrypt membatasi sertifikat duplikat, yaitu set nama yang persis sama, hingga lima sertifikat per minggu. Tidak ada override untuk batas tersebut, sehingga Anda hanya perlu menunggu. Secara terpisah, Let’s Encrypt mengizinkan 50 sertifikat baru per registered domain per minggu. Batas ini dapat dinaikkan dengan mengajukan override. Permintaan untuk set nama yang persis sama dengan sertifikat yang sudah ada dihitung sebagai renewal dan tidak terkena batas ini. Renewal yang dikoordinasikan melalui ARI tidak terkena batas apa pun. Lakukan debugging pada staging dengan --dry-run.

nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": No such file or directory, nginx dikonfigurasi untuk sertifikat yang tidak pernah diterbitkan atau sudah dihapus dengan certbot delete. Nonaktifkan sementara server block TLS, jalankan nginx, terbitkan sertifikat, lalu aktifkan kembali server block tersebut.

open() "/etc/letsencrypt/options-ssl-nginx.conf" failed, file tersebut disertakan dalam paket plugin nginx. Pada sistem certonly tanpa python3-certbot-nginx, tambahkan plugin tersebut atau ganti baris include dengan pengaturan ssl_protocols dan ssl_ciphers Anda sendiri.

Mengelolanya dalam skala besar

Satu sertifikat dapat memuat hingga 100 nama, dan satu certbot --nginx -d a.example.com -d b.example.com ... tampak menarik. Namun, satu catatan DNS yang kedaluwarsa dapat gagal dalam validasi dan menyebabkan semua nama lain pada sertifikat tersebut ikut tidak berfungsi. Sertifikat terpisah untuk setiap situs gagal secara independen. Ini yang Anda inginkan pada server yang menampung lebih dari beberapa layanan. Jika jumlah situs sudah mencapai beberapa, front door yang mendukung ACME akan sangat membantu: reverse proxy Traefik yang menjalankan beberapa aplikasi dengan Docker Compose meminta dan memperbarui sertifikat itu sendiri, sehingga Certbot tidak lagi diperlukan. Proxy yang digunakan pada front door tersebut merupakan keputusan tersendiri. Membandingkan Nginx dengan Caddy dan Traefik pada dasarnya bergantung pada seberapa banyak pekerjaan terkait sertifikat dan konfigurasi per aplikasi yang ingin Anda serahkan kepada proxy.

Cadangkan seluruh /etc/letsencrypt, termasuk sudo tar -czf letsencrypt-$(date +%F).tar.gz -C /etc letsencrypt, dan pertahankan symlink. Pohon direktori tersebut memuat accounts/, yaitu kunci akun ACME Anda, yang tidak dapat dibuat ulang secara identik. Saat berpindah ke VPS baru, langkahnya menjadi: sinkronkan pohon tersebut dengan -a, instal Certbot, arahkan ulang DNS, lalu jalankan certbot renew --dry-run sebelum melakukan pengalihan.

Jika Anda membangun ulang server atau berpindah ke LTS baru, timer pembaruan tidak ikut berpindah. Setelah migrasi, pemulihan snapshot, atau upgrade distro, jalankan systemctl list-timers 'certbot*' dan satu --dry-run. Jika langkah ini dilewati, situs dapat tidak dapat diakses 89 hari kemudian, pada pukul 3 pagi, karena sertifikat yang dianggap semua orang akan diperbarui secara otomatis ternyata tidak diperbarui.

Rute HTTP-01 di atas mengasumsikan mesin yang Anda kendalikan, dengan IP publik dan port 80 yang terbuka untuk semua jaringan, yaitu VPS. DNS-01 tidak memerlukan keduanya. Mekanisme di atas sama pada semua jenis mesin tersebut.

Langkah sertifikat yang sama berlaku pada Apache, bukan nginx, dan jika sertifikat publik bukan pilihan, sertifikat self-signed pada Ubuntu dapat digunakan untuk layanan internal.

FAQ

Apakah port 80 harus dibuka jika situs saya hanya melayani HTTPS?

Ya, untuk challenge HTTP-01. Let’s Encrypt selalu memulai permintaan validasi pada port 80, dan Certbot tidak memiliki implementasi TLS-ALPN-01. Karena itu, firewall yang hanya membuka port 443 akan memblokir penerbitan pertama dan setiap renewal otomatis setelahnya. Redirect dari port 80 ke HTTPS dapat digunakan; validasi akan mengikutinya. Satu-satunya cara untuk sepenuhnya melewati port 80 adalah DNS-01, baik dengan plugin provider maupun dengan --manual --preferred-challenges dns milik Certbot. Dalam metode ini, Anda menambahkan record TXT sendiri, dan renewal tidak lagi otomatis kecuali Anda menyediakan skrip --manual-auth-hook.

apt atau snap, Certbot mana yang harus saya instal untuk nginx di Ubuntu 24.04?

Gunakan apt. sudo apt install certbot python3-certbot-nginx menyediakan Certbot 2.9.0 di Ubuntu 24.04. Versi ini cukup baru untuk semua hal dalam panduan ini, menerima patch keamanan melalui unattended-upgrades, dan tidak memerlukan snapd. Pilih snap hanya jika Anda memerlukan release terbaru segera atau plugin DNS yang hanya didistribusikan sebagai snap. Apa pun pilihannya, gunakan tepat satu metode. Dua instalasi berarti ada dua timer renewal yang mengarah ke tree /etc/letsencrypt yang sama, dan instalasi yang terlupakan itulah yang akhirnya menimbulkan masalah.

Apakah Certbot dapat menerbitkan sertifikat wildcard untuk nginx?

Hanya melalui DNS-01. Wildcard seperti *.example.com tidak memiliki satu hostname tertentu untuk mengambil file challenge, sehingga --nginx, --webroot, dan --standalone tidak dapat digunakan. Instal plugin untuk provider DNS Anda, simpan token API dengan cakupan terbatas dalam file kredensial yang hanya dapat diakses oleh root, lalu jalankan certbot certonly --dns-cloudflare -d example.com -d '*.example.com'. Gunakan tanda kutip pada wildcard agar shell tidak memperlakukannya sebagai glob.

Mengapa nginx masih menyajikan sertifikat lama setelah renewal berhasil?

nginx menyimpan sertifikat di memori dan tidak mendeteksi file baru di disk sampai melakukan reload. certbot --nginx melakukan reload secara otomatis, tetapi proses --webroot dan --standalone tidak melakukannya. Akibatnya, renewal dapat berhasil sementara browser masih menerima sertifikat yang akan kedaluwarsa. Letakkan skrip yang dapat dieksekusi ke dalam /etc/letsencrypt/renewal-hooks/deploy/ dan jalankan nginx -t && systemctl reload nginx di dalamnya. Skrip tersebut akan dijalankan setelah setiap renewal yang berhasil.

Apakah certbot renew --dry-run membuktikan bahwa renewal akan berhasil?

Sebagian besar. Perintah tersebut menjalankan challenge nyata terhadap environment staging dengan firewall, DNS, dan jalur kode yang sama, tanpa memengaruhi rate limit produksi dan tanpa menyimpan sertifikat ke disk. Karena itu, keberhasilan pengujian menunjukkan bahwa bagian jaringan berfungsi dengan baik. Namun, pengujian ini tidak secara andal membuktikan bahwa deploy hook akan dijalankan. Uji secara terpisah: jalankan skrip hook secara manual dan periksa sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.