Self-Signed Certificate #

Ketika kita membangun aplikasi web, mengaktifkan HTTPS di lingkungan pengembangan (development) lokal sangat penting untuk menyimulasikan kondisi lingkungan produksi (production) seakurat mungkin. Banyak fitur web modern — seperti Service Workers, Web Cryptography API, Geolocation, HTTP/2, hingga cookie dengan atribut Secure dan SameSite=None — menuntut koneksi terenkripsi (HTTPS) dan akan menolak berjalan di atas HTTP biasa.

Untuk lingkungan lokal, kita tidak perlu membeli sertifikat SSL komersial atau menggunakan Let’s Encrypt yang memerlukan nama domain publik aktif. Solusi praktisnya adalah menggunakan Self-Signed Certificate (Sertifikat yang Ditandatangani Sendiri). Di artikel ini, kita akan membahas secara mendalam kapan harus menggunakan self-signed certificate, cara membuatnya menggunakan OpenSSL (lengkap dengan konfigurasi SAN modern), penerapannya di Nginx, cara mengatasi peringatan keamanan browser di berbagai sistem operasi, hingga alternatif terbaik menggunakan tool modern mkcert.

Kapan Menggunakan Self-Signed Certificate? #

Sebelum kita masuk ke langkah-langkah praktis, kita harus memahami batas-batas penggunaan self-signed certificate. Secara fungsional, enkripsi yang dihasilkan oleh self-signed certificate sama kuatnya dengan sertifikat berbayar atau Let’s Encrypt karena menggunakan algoritma kriptografi yang sama. Perbedaan utamanya terletak pada aspek kepercayaan (trust).

SkenarioBoleh Menggunakan Self-Signed?Alasan & Alternatif
Development Lokal (localhost / myapp.local)YaLingkungan terkontrol; kita bisa memaksa sistem kita sendiri untuk mempercayai sertifikat tersebut.
Koneksi Internal Antar Server (Microservices)YaServer-ke-server di dalam Virtual Private Cloud (VPC) yang tertutup dari publik.
Staging/UAT Environment (Akses Internal Tim)YaSelama seluruh tim mendaftarkan sertifikat tersebut ke trust store masing-masing.
Production Website (Akses Publik)TidakBrowser pengguna akan menampilkan halaman peringatan merah yang menakutkan. Pengguna akan mengira situs kita diretas. Gunakan Let’s Encrypt atau CA publik.

Keterbatasan Common Name (CN) dan Kewajiban Subject Alternative Name (SAN) #

Pada masa lalu, saat membuat self-signed certificate, kita cukup mengisi kolom Common Name (CN) dengan nama domain kita (misalnya localhost atau myapp.local). Namun, cara ini sudah usang dan tidak lagi didukung oleh browser modern seperti Google Chrome (sejak versi 58) dan Apple Safari.

Browser modern kini mewajibkan penggunaan Subject Alternative Name (SAN). Jika kita membuat sertifikat tanpa ekstensi SAN, browser akan tetap menampilkan error ERR_CERT_COMMON_NAME_INVALID meskipun kita sudah mengimpor sertifikat tersebut ke dalam system trust store. Oleh karena itu, semua skrip pembuatan sertifikat kita di bawah ini akan menyertakan konfigurasi SAN secara eksplisit.


Panduan Membuat Self-Signed Certificate dengan OpenSSL #

OpenSSL adalah perkakas baris perintah serbaguna yang terpasang di hampir semua sistem operasi berbasis Unix (Linux dan macOS). Kita akan menggunakan OpenSSL untuk membuat sertifikat baru.

Langkah 1: Menyiapkan Struktur Direktori #

Pertama, mari kita buat direktori khusus di server Nginx untuk menyimpan kunci dan sertifikat SSL dengan aman:

# Buat direktori ssl di dalam konfigurasi Nginx
sudo mkdir -p /etc/nginx/ssl

# Masuk ke direktori tersebut
cd /etc/nginx/ssl

Langkah 2: Membuat File Konfigurasi OpenSSL untuk SAN #

Agar sertifikat kita mendukung SAN, kita perlu membuat file konfigurasi sementara (kita sebut saja openssl-san.cnf). File ini memberitahu OpenSSL domain dan IP apa saja yang boleh menggunakan sertifikat ini.

# Buat file konfigurasi menggunakan cat
cat <<EOF | sudo tee /etc/nginx/ssl/openssl-san.cnf
[req]
default_bits       = 2048
default_keyfile    = myapp.key
distinguished_name = req_distinguished_name
req_extensions     = v3_req
x509_extensions    = v3_req
prompt             = no

[req_distinguished_name]
C            = ID
ST           = Jakarta
L            = Jakarta Selatan
O            = Badri Creative Tech
OU           = Development Department
CN           = myapp.local

[v3_req]
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost
DNS.2 = myapp.local
DNS.3 = *.myapp.local
IP.1  = 127.0.0.1
IP.2  = 192.168.1.100
EOF

Dalam konfigurasi di atas:

  • CN = myapp.local: Nama umum sertifikat kita.
  • [alt_names]: Mendefinisikan domain tambahan (localhost, myapp.local, wildcard *.myapp.local untuk subdomain) serta alamat IP lokal (127.0.0.1 dan IP LAN server kita 192.168.1.100). Browser akan memvalidasi kecocokan URL dengan daftar ini.

Langkah 3: Menghasilkan Private Key dan Sertifikat #

Sekarang, kita jalankan perintah OpenSSL untuk menghasilkan Private Key (kunci rahasia) dan Certificate (sertifikat publik) sekaligus berdasarkan file konfigurasi SAN yang telah kita buat:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout /etc/nginx/ssl/myapp.key \
    -out /etc/nginx/ssl/myapp.crt \
    -config /etc/nginx/ssl/openssl-san.cnf

Penjelasan parameter perintah di atas:

  • req -x509: Meminta pembuatan sertifikat bertipe X.509 secara langsung (self-signed), bukan Certificate Signing Request (CSR) yang biasa dikirim ke CA eksternal.
  • -nodes: Singkatan dari No DES. Parameter ini memastikan private key tidak dienkripsi dengan kata sandi (passphrase). Jika private key dienkripsi, Nginx akan meminta kita memasukkan kata sandi setiap kali server dinyalakan atau dimuat ulang (reload), yang akan merusak otomatisasi server.
  • -days 365: Masa berlaku sertifikat selama satu tahun (365 hari).
  • -newkey rsa:2048: Membuat private key baru dengan algoritma RSA berkekuatan 2048 bit.
  • -keyout: Lokasi penyimpanan berkas private key kustom (myapp.key).
  • -out: Lokasi penyimpanan berkas sertifikat kustom (myapp.crt).
  • -config: Merujuk ke file konfigurasi SAN yang kita buat pada Langkah 2.

Langkah 4: Mengatur Hak Akses File (Permission Hardening) #

Private key adalah data yang sangat sensitif. Jika pihak luar berhasil menyalin private key kita, mereka dapat melakukan dekripsi terhadap seluruh trafik data. Mari kita batasi hak aksesnya agar hanya bisa dibaca oleh user root dan service Nginx:

# Private key hanya boleh dibaca & ditulis oleh pemilik (root)
sudo chmod 600 /etc/nginx/ssl/myapp.key

# Sertifikat publik boleh dibaca oleh publik/Nginx
sudo chmod 644 /etc/nginx/ssl/myapp.crt

Konfigurasi Nginx untuk Menggunakan Self-Signed Certificate #

Setelah kedua file sertifikat (myapp.crt dan myapp.key) siap, langkah selanjutnya adalah mengonfigurasi Nginx untuk mendengarkan pada port HTTPS (443) dan memuat file tersebut.

Mari kita buat file konfigurasi virtual host baru di /etc/nginx/conf.d/myapp.conf:

# Server Block untuk HTTPS
server {
    listen 443 ssl;
    server_name myapp.local www.myapp.local;

    # Tentukan lokasi berkas sertifikat dan private key
    ssl_certificate     /etc/nginx/ssl/myapp.crt;
    ssl_certificate_key /etc/nginx/ssl/myapp.key;

    # Protokol SSL/TLS yang diizinkan (Gunakan TLS modern)
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # Cipher suites yang aman (Mozilla Intermediate Profile)
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;

    # Lokasi root aplikasi
    root /var/www/myapp;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
    
    # Logging
    access_log /var/log/nginx/myapp_ssl_access.log;
    error_log /var/log/nginx/myapp_ssl_error.log;
}

# Server Block untuk Pengalihan (Redirect) HTTP ke HTTPS
server {
    listen 80;
    server_name myapp.local www.myapp.local;
    return 301 https://$host$request_uri;
}

Sebelum kita memuat ulang Nginx, pastikan direktori root /var/www/myapp dan file HTML sederhana sudah ada untuk keperluan pengujian:

sudo mkdir -p /var/www/myapp
echo "<h1>Halo dari HTTPS Lokal Nginx!</h1>" | sudo tee /var/www/myapp/index.html

# Uji konfigurasi Nginx untuk memastikan tidak ada kesalahan sintaksis
sudo nginx -t

# Jika sukses, muat ulang konfigurasi Nginx
sudo systemctl reload nginx

Cara Menambahkan Sertifikat ke OS & Browser Trust Store #

Ketika kita mencoba mengakses https://myapp.local melalui browser, kita akan disambut oleh halaman peringatan keamanan yang menyatakan sertifikat tidak dipercayai.

Untuk menghilangkan peringatan ini secara permanen di komputer lokal kita, kita harus memberi tahu sistem operasi atau browser bahwa kita mempercayai sertifikat self-signed yang kita buat.

flowchart TD
    A["Akses https://myapp.local"] --> B{"Browser Cek Sertifikat"}
    B -->|Bukan dari CA Terpercaya| C["Tampilkan Peringatan Keamanan (Merah)"]
    C -->|Solusi Manual| D["Import myapp.crt ke Trust Store OS/Browser"]
    D --> E["Browser Memverifikasi Rantai Kepercayaan Lokal"]
    E --> F["Website Terbuka dengan Gembok Hijau / Aman"]
    
    classDef danger fill:#ef4444,stroke:#dc2626,color:#ffffff;
    classDef success fill:#10b981,stroke:#059669,color:#ffffff;
    class C danger;
    class F success;

Berikut adalah langkah-langkah untuk mendaftarkan sertifikat myapp.crt ke berbagai sistem operasi dan browser:

1. macOS (Melalui Terminal / Keychain Access) #

Di macOS, kita dapat mengimpor sertifikat langsung ke system keychain menggunakan command line:

sudo security add-trusted-cert -d -r trustRoot \
    -k /Library/Keychains/System.keychain /etc/nginx/ssl/myapp.crt

Atau secara visual:

  1. Buka aplikasi Keychain Access (Akses Rantai Kunci).
  2. Pilih kategori System di bilah sisi kiri, lalu pilih tab Certificates.
  3. Seret (drag and drop) berkas myapp.crt ke dalam jendela Keychain Access.
  4. Klik ganda pada sertifikat yang baru diimpor tersebut, buka bagian Trust (Kepercayaan).
  5. Ubah opsi “When using this certificate” menjadi Always Trust (Selalu Percayai).

2. Linux (Ubuntu / Debian) #

Untuk sistem Linux pengembangan lokal, jalankan perintah berikut untuk menyalin sertifikat ke direktori sertifikat tepercaya sistem:

# Salin berkas sertifikat dengan ekstensi .crt
sudo cp /etc/nginx/ssl/myapp.crt /usr/local/share/ca-certificates/myapp.crt

# Perbarui database sertifikat sistem
sudo update-ca-certificates

3. Windows (Melalui PowerShell / GUI) #

Buka PowerShell sebagai Administrator dan jalankan perintah:

Import-Certificate -FilePath "C:\path\to\myapp.crt" -CertStoreLocation Cert:\LocalMachine\Root

Atau secara visual:

  1. Klik ganda pada file myapp.crt.
  2. Klik Install Certificate…
  3. Pilih Local Machine sebagai Store Location.
  4. Pilih opsi Place all certificates in the following store dan klik Browse.
  5. Pilih folder Trusted Root Certification Authorities (Otoritas Sertifikasi Akar Terpercaya).
  6. Klik Next dan Finish.

4. Browser Mozilla Firefox #

Mozilla Firefox tidak menggunakan trust store sistem operasi bawaan; ia mengelola database sertifikat tepercayanya sendiri.

  1. Buka Firefox, akses menu Settings (Pengaturan).
  2. Cari “Certificates” di kolom pencarian, lalu klik tombol View Certificates…
  3. Pada tab Authorities, klik tombol Import…
  4. Pilih file myapp.crt milik kita.
  5. Centang opsi “Trust this CA to identify websites” (Percayai CA ini untuk mengidentifikasi situs web).
  6. Klik OK.

Alternatif Terbaik untuk Pengembangan Lokal: mkcert #

Meskipun membuat sertifikat dengan OpenSSL sangat bagus untuk memahami konsep dasar, proses pembuatan konfigurasi SAN, mengelola tanggal kedaluwarsa, dan mengimpor sertifikat secara manual ke berbagai trust store cukup melelahkan.

Standard industri modern untuk pengembangan lokal saat ini adalah menggunakan mkcert.

mkcert adalah tool sederhana yang secara otomatis membuat Certificate Authority (CA) lokal kustom pada mesin kita, mendaftarkannya ke trust store sistem operasi (macOS, Windows, Linux) serta trust store browser (Firefox, Chrome, Safari) secara otomatis, lalu menghasilkan sertifikat lokal tepercaya tanpa peringatan keamanan sama sekali.

flowchart TD
    A["Install mkcert"] --> B["Jalankan 'mkcert -install'"]
    B --> C["mkcert Membuat Root CA Lokal Kustom"]
    C --> D["Root CA Lokal Dimasukkan ke Trust Store OS & Browser Otomatis"]
    D --> E["Jalankan 'mkcert localhost myapp.local'"]
    E --> F["Menghasilkan Sertifikat & Key Tepercaya tanpa Warning"]
    
    classDef step fill:#1e293b,stroke:#3b82f6,color:#ffffff;
    class A,B,C,D,E,F step;

Cara Menginstal dan Menggunakan mkcert #

Berikut adalah alur instalasi dan penggunaan mkcert di berbagai sistem operasi:

1. macOS (Menggunakan Homebrew) #

brew install mkcert
brew install nss # Dibutuhkan jika kita menggunakan Firefox

2. Ubuntu / Debian #

sudo apt update
sudo apt install mkcert libnss3-tools -y

3. Windows (Menggunakan Chocolatey) #

choco install mkcert

Langkah-langkah Penggunaan mkcert #

Setelah terinstal, ikuti langkah berikut untuk mengintegrasikannya dengan Nginx:

Langkah 1: Inisialisasi Root CA Lokal Jalankan perintah ini sekali saja di komputer kita. Perintah ini akan membuat Root CA lokal dan memasukkannya ke sistem keamanan OS dan browser kita:

mkcert -install

Output sukses: “The local CA is now installed in the system trust store! ⚡”

Langkah 2: Menghasilkan Sertifikat untuk Domain Kita Sekarang kita bisa membuat sertifikat untuk nama domain lokal apa pun yang kita inginkan. Misalnya localhost, myapp.local, dan wildcard:

# Buat direktori SSL Nginx jika belum ada
sudo mkdir -p /etc/nginx/ssl

# Buat sertifikat menggunakan mkcert
sudo mkcert -cert-file /etc/nginx/ssl/mkcert.crt \
            -key-file /etc/nginx/ssl/mkcert.key \
            localhost myapp.local "*.myapp.local" 127.0.0.1

Perintah di atas menghasilkan dua file di /etc/nginx/ssl/:

  • mkcert.crt (Sertifikat)
  • mkcert.key (Private Key)

Sertifikat ini secara otomatis dipercayai oleh sistem kita karena ditandatangani oleh Root CA kustom yang telah didaftarkan pada Langkah 1.

Langkah 3: Menyesuaikan Konfigurasi Nginx Sekarang, perbarui file konfigurasi server block Nginx kita untuk merujuk pada file baru tersebut:

server {
    listen 443 ssl;
    server_name myapp.local www.myapp.local;

    ssl_certificate     /etc/nginx/ssl/mkcert.crt;
    ssl_certificate_key /etc/nginx/ssl/mkcert.key;

    # ... sisa konfigurasi lainnya tetap sama
}

Jalankan pengujian konfigurasi dan muat ulang Nginx:

sudo nginx -t
sudo systemctl reload nginx

Buka browser dan akses https://myapp.local. Kita akan melihat ikon gembok terkunci dengan warna hijau/abu-abu bersih tanpa ada pesan peringatan keamanan apa pun!


Tabel Troubleshooting & Penanganan Error SSL Lokal #

Saat bekerja dengan self-signed certificate atau mkcert di Nginx, kita mungkin akan menemui kendala. Berikut adalah panduan penanganannya:

Jenis ErrorKemungkinan PenyebabCara Mengatasi
ERR_CERT_COMMON_NAME_INVALIDSertifikat dibuat hanya menggunakan Common Name (CN) tanpa konfigurasi Subject Alternative Name (SAN). Browser modern menolaknya.Buat ulang sertifikat menggunakan panduan OpenSSL SAN di atas, atau gunakan mkcert.
ERR_CERT_AUTHORITY_INVALID atau SEC_ERROR_UNKNOWN_ISSUERSertifikat terpasang dengan benar di Nginx, tetapi root sertifikat belum diimpor atau belum dipercayai di trust store OS/browser kita.Ikuti panduan bagian “Cara Menambahkan Sertifikat ke OS & Browser Trust Store” di atas untuk mengimpor berkas .crt kita.
curl: (60) SSL certificate problem: self signed certificateUtilitas CLI curl menolak koneksi karena tidak mempercayai sertifikat server kustom kita.1. Gunakan flag -k atau --insecure untuk mengabaikan keamanan (hanya untuk testing cepat): curl -k https://localhost2. Atau daftarkan sertifikat ke trust store sistem operasi agar curl mempercayainya secara permanen.
Nginx Error: KEY_VALUES_MISMATCH saat reloadBerkas sertifikat (myapp.crt) dan berkas private key (myapp.key) tidak cocok satu sama lain (mungkin salah satu terbuat ulang secara terpisah).Verifikasi kecocokan md5 hash dari modulus kedua file tersebut:`openssl x509 -noout -modulus -in myapp.crt
Peringatan “Sertifikat Kedaluwarsa” di BrowserMasa berlaku sertifikat self-signed yang kita buat telah habis (melebihi jumlah -days saat pembuatan).Jalankan kembali perintah pembuatan sertifikat OpenSSL atau jalankan mkcert untuk memperbarui masa aktif sertifikat.

Ringkasan #

  • Wajib menggunakan SAN: Browser modern seperti Chrome dan Safari menolak sertifikat SSL jika hanya menggunakan Common Name (CN). Konfigurasi Subject Alternative Name (SAN) adalah sebuah keharusan.
  • Amankan Private Key: Selalu gunakan perintah chmod 600 pada berkas private key kustom agar tidak dapat dibaca oleh user lain di dalam sistem server.
  • Gunakan -nodes untuk Otomatisasi: Jangan enkripsi private key dengan kata sandi saat membuat sertifikat untuk Nginx, agar Nginx dapat menyala otomatis tanpa intervensi manual.
  • mkcert adalah Standar Baru: Gunakan mkcert untuk pengembangan lokal sehari-hari guna menghindari kerumitan konfigurasi OpenSSL manual dan proses impor sertifikat ke sistem/browser.

← Sebelumnya: Konsep SSL/TLS   Berikutnya: Let’s Encrypt →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact