SSD Nodes Learn 🎉 VPS dari $5.50/bln
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-08-13

Nginx vs Caddy vs Traefik: Mana Satu Pilihan Terbaik?

Bandingkan Nginx, Caddy, dan Traefik untuk VPS anda. Ketahui perbezaan pengurusan sijil TLS, konfigurasi Docker, sokongan websocket, dan kos penyelenggaraan setiap servis.

Nginx vs Caddy vs Traefik: jawapan ringkas

Nginx, Caddy dan Traefik melakukan tugas yang sama sebagai reverse proxy: mendengar pada port 443, membaca hostname dalam setiap permintaan, dan menghantarnya ke servis yang betul pada VPS anda. Mana-mana daripada ketiga-tiganya mampu meletakkan empat aplikasi self-hosted di sebalik satu alamat IP awam, dan kesemuanya cukup pantas sehingga aplikasi anda akan menjadi bahagian yang perlahan. Perbezaannya terletak pada cara setiap satu memperoleh sijil TLS (transport layer security) dan berapa banyak konfigurasi yang diperlukan oleh setiap aplikasi tambahan. Perbezaan lain akan muncul kemudian, pada hari anda memerlukan sesuatu yang tidak disentuh oleh tutorial biasa.

Pilih Caddy jika anda mahu HTTPS diuruskan untuk anda dan servis anda adalah aplikasi web biasa. Pilih Traefik jika semuanya berjalan dalam Docker Compose dan anda menambah servis baharu setiap beberapa minggu. Pilih Nginx jika anda sudah menggunakannya, atau jika anda memerlukan response caching, sijil klien, raw TCP forwarding, atau konfigurasi sedia ada yang besar yang anda tidak mahu tulis semula.

Bagaimanakah setiap satu mendapatkan sijil TLS?

Paksi ini menentukan pilihan bagi kebanyakan orang, jadi mulakan di sini. Ketiga-tiganya akhirnya memegang sijil yang sama daripada pihak berkuasa yang sama. Usaha yang anda lakukan untuk mencapainya tidak sama.

Caddy meminta sijil tersebut kerana anda menamakan hostname. Tulis app.example.com sebagai alamat tapak dan Caddy akan meminta sijil melalui ACME (automatic certificate management environment) daripada Let's Encrypt, menggunakan ZeroSSL sebagai sandaran jika gagal, menyediakan redirect HTTP ke HTTPS pada port 80, dan melakukan pembaharuan secara automatik. Tiada alat kedua dan tiada pemasa untuk diperiksa. Sijil disimpan dalam direktori data pengguna caddy, /var/lib/caddy/.local/share/caddy semasa pemasangan pakej, jadi tambahkan laluan tersebut ke dalam sandaran anda atau terima pengeluaran sijil baharu selepas pembinaan semula. Bagi hostname yang tidak awam, tls internal menandatangani sijil dengan pihak berkuasa sijil tempatan Caddy sendiri. Ini memberikan hasil yang sama seperti mencipta sijil self-signed pada Ubuntu, dengan pembaharuan diuruskan untuk anda.

Nginx tidak mempunyai klien ACME. Certbot mendapatkan sijil tersebut, dan pemalam --nginx miliknya menulis semula blok pelayan anda untuk menambah listener 443 dan redirect. Pembaharuan dijalankan daripada pemasa systemd yang dipasang oleh pakej tersebut, jadi terdapat dua bahagian yang bergerak dan dua perkara untuk disahkan: systemctl list-timers | grep certbot menunjukkan pemasa wujud, dan sudo certbot renew --dry-run membuktikan laluan pembaharuan masih berfungsi. Langkah demi langkah terdapat dalam Certbot pada Ubuntu 24.04 dengan Nginx, dan alat yang sama meliputi sijil wildcard melalui cabaran DNS-01 apabila anda mempunyai lebih banyak subdomain daripada yang anda ingin senaraikan.

Traefik membawa klien ACME sendiri. Anda mengkonfigurasi satu penyelesai sijil (certificate resolver) dalam konfigurasi statik, dan setiap router kemudian boleh menggunakannya. Semua keadaan, termasuk kunci akaun dan sijil, terletak dalam satu fail acme.json. Traefik enggan menggunakan fail tersebut jika ia boleh dibaca oleh sesiapa selain pemiliknya, dan ia akan memberitahu anda sebelum ia menggugurkan penyelesai tersebut:

The ACME resolver "le" is skipped from the resolvers list because: unable to get ACME account: permissions 660 for /letsencrypt/acme.json are too open, please use 600

Mount satu direktori dan biarkan Traefik mencipta fail tersebut sendiri. Jika anda menciptanya terlebih dahulu dengan touch, ia akan mewarisi umask anda, yang merupakan punca kebanyakan orang menghadapi ralat tersebut.

Satu perkara adalah benar untuk ketiga-tiganya. Cabaran HTTP-01 memerlukan port 80 boleh dicapai dari internet, kerana pihak berkuasa sijil akan membuat sambungan balik kepadanya. Jika anda hanya membuka port 443, pengeluaran sijil akan gagal dengan mesej ralat yang kelihatan seperti masalah DNS.

Tugas penghalaan dua aplikasi yang sama dalam tiga konfigurasi

Tugasnya: app.example.com dihalakan ke servis pada 127.0.0.1:8080, files.example.com dihalakan ke servis pada 127.0.0.1:8081, kedua-duanya melalui HTTPS. Berikut adalah keseluruhan konfigurasi bagi setiap proksi supaya perbezaan tahap verbositi dapat dilihat dengan jelas dan bukan sekadar dakwaan.

Nginx

# /etc/nginx/sites-available/app.example.com
server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Kemudian pautkan fail tersebut, uji, muat semula, dan tambah sijil.

sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d app.example.com

nginx -t yang mencetak syntax is ok dan test is successful ialah semakan yang perlu dijalankan sebelum setiap muat semula. Aplikasi kedua menggunakan blok yang sama dengan hostname dan port yang telah diubah. Baris proxy_set_header bukanlah hiasan: apabila proxy_pass menamakan alamat, nginx menghantar Host: 127.0.0.1:8080 ke upstream secara lalai, jadi aplikasi yang membina URL mutlak daripada header Host akan menghantar pengguna anda ke localhost.

Caddy

app.example.com {
	reverse_proxy 127.0.0.1:8080
}

files.example.com {
	reverse_proxy 127.0.0.1:8081
}
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

Itu adalah keseluruhan fail. reverse_proxy menetapkan X-Forwarded-For, X-Forwarded-Proto dan X-Forwarded-Host secara automatik, dan secara lalai ia mengabaikan apa sahaja yang dihantar oleh klien dalam header tersebut, jadi permintaan tidak boleh menipu backend anda tentang asal usulnya. Sijil, redirect port 80 dan pembaharuan semuanya diuruskan berdasarkan dua alamat tapak tersebut. Tiada arahan lain dalam fail yang memintanya.

Traefik

Traefik memerlukan konfigurasi statik sebelum ia menghalakan sebarang trafik. Sebagai servis Compose, dengan tag imej yang terkini sehingga Ogos 2026:

services:
  traefik:
    image: traefik:v3.7
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.le.acme.email=you@example.com"
      - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt

Setiap aplikasi kemudian membawa konfigurasi penghalaannya sendiri, melalui label, dalam fail compose masing-masing:

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app.rule=Host(`app.example.com`)"
      - "traefik.http.routers.app.entrypoints=websecure"
      - "traefik.http.routers.app.tls.certresolver=le"
      - "traefik.http.services.app.loadbalancer.server.port=8080"

loadbalancer.server.port ialah port di dalam kontena, bukan port yang diterbitkan, kerana Traefik mencapai kontena melalui rangkaian Docker yang dikongsi. Aplikasi tersebut tidak memerlukan baris ports: langsung, dan itulah kelebihan sebenar: hanya Traefik yang diterbitkan. Binaan penuh, termasuk rangkaian dikongsi dan middleware redirect, terdapat dalam penghalaan berbilang aplikasi dengan Traefik dan Docker Compose.

Berapakah kos konfigurasi bagi setiap aplikasi tambahan?

ChartNon-blank config lines for the same two-app routing job
The data behind this chart
[
  {
    "tool": "Nginx",
    "proxy_setup_lines": 0,
    "lines_per_app": 11
  },
  {
    "tool": "Caddy",
    "proxy_setup_lines": 0,
    "lines_per_app": 3
  },
  {
    "tool": "Traefik",
    "proxy_setup_lines": 17,
    "lines_per_app": 5
  }
]

Dikira daripada blok di atas. Blok pelayan Nginx mengandungi 11 baris yang bukan kosong, dan anda perlu menulisnya semula bagi setiap hostname. Blok tapak Caddy mengandungi 3 baris. Traefik memerlukan 17 baris konfigurasi statik sebelum ia melayani satu permintaan pun, kemudian 5 label bagi setiap aplikasi.

Nilai pertukaran ini, bukan pemenangnya. Traefik menelan kos paling tinggi sebelum aplikasi pertama dan kos paling rendah bagi setiap aplikasi seterusnya, dan kedua-dua jumlah ini bertemu sekitar tapak ketiga. Di bawah jumlah itu, konfigurasi statik merupakan bebanan yang tidak diperlukan. Di atas jumlah itu, label menjadi lebih efisien dan terus mendahului, kerana penghalaan (routing) terletak bersebelahan dengan servis yang dihalanya. Padamkan servis tersebut dan laluannya akan turut terpadam, sesuatu yang sukar dilakukan oleh fail konfigurasi berpusat: blok pelayan yang lapuk bagi aplikasi yang sudah tidak wujud sejak berbulan-bulan lalu.

Kiraan baris juga menampakkan Nginx lebih baik daripada keadaan sebenar. Setiap blok tersebut memerlukan symlink, satu nginx -t, muat semula (reload) dan satu proses certbot, manakala suntingan Caddy hanya memerlukan satu muat semula dan suntingan Traefik tidak memerlukan sebarang arahan langsung. Ketiga-tiganya boleh dimuat semula tanpa memutuskan sambungan yang sedang aktif. Perbezaannya terletak pada bilangan langkah berasingan yang perlu anda ingat pada pukul satu pagi.

Yang manakah mengenali kontena anda?

Traefik memantau Docker socket dan membina router daripada label kontena apabila kontena bermula dan berhenti. Tiada perisian lain di sini yang melakukan perkara tersebut. Nginx dan Caddy kedua-duanya memerlukan pengeditan konfigurasi dan muat semula (reload) apabila kontena baharu muncul, dan ia memerlukan alamat yang boleh dicapai: sama ada port yang diterbitkan pada loopback, atau rangkaian Docker berkongsi yang disambungkan dengan proksi.

Ciri tersebut mempunyai harganya, dan ia perlu dinyatakan dengan jelas. Traefik membaca /var/run/docker.sock. Sesiapa yang boleh berhubung dengan socket tersebut boleh memulakan kontena dengan sistem fail hos yang dilekapkan (mounted) di dalamnya, yang bermaksud root pada hos. Melekapkannya sebagai baca sahaja (read-only) mengurangkan risiko tanpa menghilangkannya. Jika perkara ini penting bagi model ancaman anda, letakkan socket proxy di antara yang hanya mendedahkan endpoint senarai kontena yang diperlukan oleh Traefik.

Caddy boleh melakukan penemuan berasaskan label melalui pemalam komuniti, tetapi pemalam Caddy dikompil masuk, jadi anda perlu membina binari tersuai atau imej tersuai dengan xcaddy dan kemudian anda bertanggungjawab ke atas binaan tersebut serta kemas kininya. Untuk tiga atau empat servis, menyunting Caddyfile adalah kurang kerja.

Websocket dan penstriman: apa yang tergendala, dan mengapa

Nginx memerlukan bantuan untuk perkara ini. Sambungan WebSocket bermula sebagai permintaan HTTP yang membawa Upgrade: websocket, dan nginx tidak menghantar header hop-by-hop ke upstream melainkan anda mengarahkannya untuk berbuat demikian.

# /etc/nginx/conf.d/upgrade-map.conf
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

Kemudian, di dalam blok location, tiga baris yang mesti ada semuanya:

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

Jika anda meninggalkannya, konsol pelayar akan memaparkan WebSocket connection to 'wss://app.example.com/ws' failed manakala log backend anda menunjukkan GET biasa. map wujud kerana Connection: upgrade yang ditetapkan secara hardcode akan dihantar pada setiap permintaan, termasuk permintaan biasa yang sepatutnya menyatakan close.

Dua lagi tetapan lalai Nginx sering menjadi punca masalah. proxy_read_timeout ialah 60 saat dan ia terpakai pada terowong selepas naik taraf (upgrade), jadi websocket tanpa trafik selama seminit akan ditutup oleh proksi. Selain itu, server-sent events akan tiba lewat atau secara berperingkat sehingga anda menetapkan proxy_buffering off; pada lokasi tersebut, kerana nginx menahan respons dalam penimbal (buffer) sementara halaman anda menunggunya.

Caddy melakukan naik taraf dan menukar sambungan kepada terowong dua hala tanpa sebarang arahan tambahan. Ia juga melakukan flush serta-merta apabila respons adalah text/event-stream atau tidak mempunyai panjang yang diketahui, jadi penstriman berfungsi tanpa gangguan. Traefik membenarkan naik taraf dan tidak menimbal respons melainkan anda menambah middleware buffering sendiri. Jika servis anda merangkumi sembang, terminal web, log tails atau papan pemuka langsung, ini merupakan perbezaan ketara dari segi jumlah konfigurasi yang perlu anda tulis dan nyahpepijat.

Blok pelayan Nginx penuh, termasuk websocket dan SSE
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name app.example.com;
    client_max_body_size 64m;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 3600s;
        proxy_buffering off;
    }
}

map perlu diletakkan dalam konteks http, bukan di dalam server, jadi simpan ia dalam failnya sendiri di bawah /etc/nginx/conf.d/. Matikan proxy_buffering hanya pada lokasi yang melakukan penstriman, kerana penimbalan (buffering) adalah fungsi yang membolehkan nginx melepaskan pekerja backend lebih awal bagi respons biasa. Certbot akan menulis semula blok ini apabila anda menjalankannya, jadi baca semula fail tersebut selepas itu.

Apa yang berlaku apabila anda memerlukan sesuatu yang luar biasa?

Di sinilah Nginx membuktikan nilainya dengan konfigurasi tambahan.

  • Sijil klien, juga dikenali sebagai mTLS (mutual TLS), di mana klien juga perlu mengemukakan sijil. Nginx memerlukan ssl_client_certificate /etc/ssl/ca.pem; dan ssl_verify_client on; di dalam blok server. Caddy memerlukan blok client_auth di dalam tls. Label Traefik tidak dapat melaksanakannya secara langsung: anda perlu mentakrifkan pilihan TLS dalam penyedia fail dan menghalakan router kepadanya menggunakan traefik.http.routers.app.tls.options=mtls@file. Model yang meletakkan segala-galanya dalam label akan menemui pengecualian apabila anda memerlukan fungsi ini.
  • Muat naik bersaiz besar. Nginx mengehadkan badan permintaan kepada 1 MB secara lalai. Muat naik yang lebih besar akan mengembalikan 413 Request Entity Too Large, dan log ralat akan memaparkan client intended to send too large body. Tingkatkan nilai client_max_body_size. Caddy dan Traefik tidak menetapkan had badan secara lalai, jadi permintaan akan sampai ke aplikasi anda dan had aplikasi anda sendiri yang akan menentukan hasilnya.
  • Caching respons. Nginx mempunyai proxy_cache, dan ia sangat matang. Caddy memerlukan pemalam yang perlu dikompilasi bersama. Binaan sumber terbuka Traefik tidak mempunyai cache HTTP langsung, yang sering mengejutkan pengguna yang menganggap setiap proksi melakukan caching.
  • TCP atau UDP mentah, untuk port pangkalan data atau pelayan permainan. Nginx mempunyai modul stream. Traefik mempunyai router TCP dan UDP pada entrypoint masing-masing. Caddy memerlukan pemalam lain, yang bermaksud binaan tersuai yang lain.
  • Pelayan web yang sudah berada di belakang proksi. Jika servis tersebut adalah aplikasi PHP klasik, maka stack LAMP pada Ubuntu 24.04 sudah pun menyertakan Apache, dan meletakkan proksi di hadapannya akan memberikan anda dua lokasi yang menetapkan header dan dua lokasi yang boleh menulis semula URL. Tentukan yang mana satu akan menamatkan TLS, kemudian kekalkan yang satu lagi pada HTTP biasa yang terikat pada loopback.

Perangkap firewall yang menyusuli pilihan ini

Tujuan reverse proxy adalah untuk memastikan hanya port 80 dan 443 dibuka. Docker membatalkan perkara ini secara senyap. Menerbitkan port dengan -p 8080:80 akan menulis peraturan DNAT ke dalam jadual nat, dan peraturan tersebut dinilai sebelum peraturan INPUT yang diuruskan oleh ufw. Oleh itu, ufw deny 8080 tidak akan menyekatnya dan aplikasi anda berada di internet awam bersebelahan dengan proxy yang telah anda konfigurasikan dengan teliti. Ikat (bind) port yang diterbitkan ke loopback dengan 127.0.0.1:8080:80, atau gugurkan ports: sepenuhnya dan biarkan proxy mencapai container melalui rangkaian Docker, iaitu kaedah yang digunakan dalam contoh Traefik di atas. Mekanisme dan penyelesaiannya terdapat dalam mengapa port yang diterbitkan Docker memintas ufw.

Uji perkara ini daripada mesin yang bukan VPS tersebut, kerana semakan yang dijalankan pada pelayan itu sendiri akan sentiasa berjaya:

curl --max-time 5 http://your.server.address:8080

Connection refused atau tamat masa (timeout) adalah hasil yang anda mahukan. Respons HTTP bermakna aplikasi tersebut boleh dicapai tanpa melalui proxy anda, dan segala konfigurasi yang anda lakukan di atas hanyalah hiasan semata-mata.

Proksi mana yang patut anda pilih?

Laman statik, serta satu atau dua aplikasi: Caddy. HTTPS automatik menghapuskan tugasan berulang yang paling membebankan anda. Konfigurasinya cukup ringkas untuk dibaca dalam satu skrin, dan laman statik hanya memerlukan satu baris root dan satu baris file_server di dalam blok tapak yang sama. Kekurangannya ialah sumber rujukan atau penyelesaian masalah yang boleh disalin-tampal adalah lebih terhad apabila berlaku isu yang luar biasa.

Makmal rumah docker-compose yang sentiasa ditambah: Traefik. Selepas servis ketiga, penggunaan label adalah lebih mudah berbanding menyunting fail pusat, dan servis yang dipadam akan turut memadamkan laluan (route) miliknya. Peruntukkan satu petang untuk persediaan awal, kerana entrypoints, routers, services dan middlewares adalah istilah baharu yang perlu dipelajari. Kesilapan menaip pada label biasanya akan dipaparkan sebagai ralat 404 daripada Traefik dan bukannya kegagalan untuk bermula, jadi baca docker logs traefik untuk melihat ralat penghuraian (parse error) sebelum anda menganggap aplikasi tersebut rosak.

Konfigurasi Nginx sedia ada, atau sebarang keperluan daripada senarai di atas: Nginx. Ia sudah mempunyai penyelesaian untuk caching respons dan sijil klien, dan hampir setiap panduan pihak ketiga menggunakan Nginx sebagai rujukan. Kekurangannya ialah sijil dan sokongan websocket adalah perkara yang perlu anda konfigurasikan secara manual dan bukannya ciri yang tersedia secara automatik.

Satu peraturan tetap terpakai tidak kira apa yang anda pilih. Hanya satu proses yang mendengar pada antara muka awam, dan semua perkara lain mendengar pada loopback atau pada rangkaian Docker peribadi.

FAQ

Reverse proxy manakah yang terbaik untuk beberapa aplikasi Docker pada satu VPS?

Bagi tiga atau empat servis yang anda tambah dari semasa ke semasa, Traefik sangat berbaloi kerana setiap aplikasi membawa label penghalaan (routing labels) sendiri dan tidak memerlukan suntingan pada fail pusat. Jika servis tersebut stabil dan anda hanya mahu menyelesaikan isu HTTPS, Caddy lebih mudah dipelajari dan kurang risiko kerosakan. Pilih Nginx jika anda sudah mahir menggunakannya, atau jika anda memerlukan ciri yang tiada pada dua pilihan lain, seperti caching respons atau pendengar TCP biasa.

Adakah Caddy benar-benar tidak memerlukan konfigurasi sijil?

Untuk kes biasa, ya. Menamakan hostname awam sebagai alamat tapak adalah keseluruhan konfigurasi: Caddy meminta sijil melalui ACME, menguruskan redirect daripada port 80, dan memperbaharuinya sebelum tamat tempoh. Dua syarat perlu dipenuhi. Port 80 mesti boleh dicapai dari internet untuk cabaran HTTP-01, dan rekod DNS A atau AAAA bagi hostname tersebut mesti sudah menghala ke VPS, kerana pihak berkuasa sijil akan meleraikan nama tersebut dan menyambung semula ke arahnya.

Bolehkah saya menjalankan Nginx dan Traefik pada VPS yang sama?

Tidak boleh pada port yang sama. Mana-mana yang bermula kedua akan gagal untuk bind, dan Nginx akan mengeluarkan bind() to 0.0.0.0:443 failed (98: Address already in use) manakala Traefik akan mencatat ralat bind yang serupa dan berhenti. Jalankan satu proksi pada port 80 dan 443, dan letakkan segala yang lain di belakangnya. Jika anda sedang melakukan migrasi, pindahkan hostname satu demi satu: biarkan proksi hadapan menghalakan trafik ke proksi lama pada port loopback sehingga tapak terakhir selesai dipindahkan.

Mengapa websocket saya terputus selepas 60 saat di belakang Nginx?

proxy_read_timeout menetapkan nilai lalai kepada 60 saat dan ia terpakai pada terowong sebaik sahaja naik taraf (upgrade) selesai, jadi sambungan tanpa trafik selama seminit akan ditutup oleh proksi dan bukannya oleh aplikasi anda. Tingkatkan nilainya pada lokasi tersebut dengan proxy_read_timeout 3600s;, atau pastikan aplikasi menghantar bingkai ping setiap 30 saat. Caddy dan Traefik tidak menutup sambungan yang dinaik taraf dan melahu berdasarkan pemasa satu minit, itulah sebabnya aplikasi yang sama kelihatan stabil di belakangnya tetapi tidak stabil di belakang Nginx.