SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-08-29

Cara Bina Pemendek URL Sendiri Menggunakan Shlink

Pasang pemendek URL Shlink 5.1 pada VPS menggunakan Docker Compose. Ketahui cara konfigurasi DNS, pangkalan data Postgres, kunci API, serta statistik klik untuk domain anda.

Apa yang anda bina

Pemendek URL yang dihoskan sendiri ialah pelayan kecil yang menukar pautan panjang kepada pautan pendek milik anda, serta mengira setiap klik padanya. Shlink ialah pilihan yang tepat: ia adalah sumber terbuka, diedarkan sebagai imej Docker, dan melaksanakan keseluruhan tugas dalam satu kontena berserta pangkalan data. Panduan ini memasangnya pada VPS di sebalik domain pendek sebenar, lengkap dengan HTTPS, kunci API, kod QR dan statistik klik.

Dua komponen menjadikannya berfungsi seperti perkhidmatan pemendek komersial. Pelayan API menjawab pengalihan (redirect) dan menyimpan data. Pelanggan web pula ialah aplikasi statik berasingan yang berhubung dengan API tersebut daripada pelayar anda. Anda boleh menjalankan kedua-duanya, atau menjalankan API sahaja dan mengawalnya melalui baris perintah.

Nombor versi di sini adalah yang terkini setakat Julai 2026: Shlink 5.1 dan shlink-web-client 4.8.

Halakan domain pendek ke pelayan terlebih dahulu

Domain ialah produk tersebut. s.example.com/abc123 ialah pautan yang dilihat oleh pengguna, jadi pilih nama yang pendek dan tetapkannya sebelum anda memasang apa-apa. Shlink menyimpan domain tersebut bersama setiap URL pendek, dan menukarnya kemudian akan menyebabkan setiap pautan yang telah anda edarkan tidak lagi berfungsi.

Cipta satu rekod DNS A untuk domain pendek tersebut, yang menghala ke alamat IPv4 awam VPS anda. Tambahkan juga rekod AAAA jika pelayan mempunyai IPv6. Kemudian, sahkan bahawa ia telah diselesaikan (resolve) sebelum anda meneruskan langkah seterusnya.

dig +short s.example.com A

Output yang terhasil mestilah alamat pelayan anda. Jika output kosong, rekod tersebut belum lagi disebarkan (propagate), dan setiap langkah seterusnya akan gagal dengan cara yang mengelirukan, kerana sijil TLS (transport layer security) tidak boleh dikeluarkan untuk nama yang tidak dapat diselesaikan.

Fail compose

Shlink memerlukan pangkalan data. SQLite sesuai untuk ujian, namun Postgres ialah pilihan yang tepat untuk sebarang data yang ingin disimpan, kerana baris lawatan akan terkumpul dan Postgres mengendalikan indeks serta penulisan serentak dengan lebih baik. Letakkan ini dalam /opt/shlink/compose.yaml.

services:
  shlink:
    image: shlinkio/shlink:stable
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      DEFAULT_DOMAIN: s.example.com
      IS_HTTPS_ENABLED: "true"
      DB_DRIVER: postgres
      DB_HOST: database
      DB_NAME: shlink
      DB_USER: shlink
      DB_PASSWORD: ${DB_PASSWORD}
    depends_on:
      - database

  database:
    image: postgres:17-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: shlink
      POSTGRES_USER: shlink
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - shlink_db:/var/lib/postgresql/data

  web-client:
    image: shlinkio/shlink-web-client:stable
    restart: unless-stopped
    ports:
      - "127.0.0.1:8081:8080"

volumes:
  shlink_db:

Kedua-dua port yang diterbitkan terikat pada 127.0.0.1, jadi tiada apa yang boleh dicapai dari internet sehingga reverse proxy di bahagian seterusnya disediakan. Docker menulis peraturan penghalaan (forwarding) sendiri mendahului firewall hos, yang bermaksud baris 8080:8080 biasa akan mendedahkan aplikasi walaupun pada kotak yang firewall-nya kelihatan tertutup. Mengikat pada alamat loopback mengelakkan perkara tersebut. Corak yang sama terpakai pada mana-mana aplikasi yang anda jalankan dengan cara ini, dan ia diterangkan dengan lebih terperinci dalam panduan Docker Compose pada VPS.

Kata laluan pangkalan data datang daripada fail .env di sebelah fail compose, jadi ia tidak akan tersimpan dalam YAML.

sudo mkdir -p /opt/shlink
printf 'DB_PASSWORD=%s\n' "$(openssl rand -base64 24)" | sudo tee /opt/shlink/.env
sudo chmod 600 /opt/shlink/.env

Mulakan ia dan perhatikan API diaktifkan.

cd /opt/shlink
sudo docker compose up -d
sudo docker compose logs -f shlink

Permulaan pertama menjalankan migrasi pangkalan data, jadi ia mengambil masa lebih lama berbanding permulaan seterusnya. Apabila ia stabil, periksa sama ada servis menjawab secara setempat.

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/rest/health

200 bermaksud API aktif dan sambungan pangkalan data berfungsi. 500 di sini hampir selalu berpunca daripada pangkalan data: DB_PASSWORD dalam .env tidak sepadan dengan apa yang digunakan semasa Postgres dicipta, kerana imej Postgres membaca POSTGRES_PASSWORD hanya apabila ia memulakan direktori data yang kosong. Mengedit kata laluan kemudian tidak akan memberi kesan sehingga anda membuang volume dan memulakannya semula.

Shlink menyediakan HTTP biasa pada port 8080. TLS sepatutnya dikendalikan oleh reverse proxy, dan tetapan paling penting ialah menghantar nama hos asal (original host name) melalui proksi tersebut. Shlink menentukan domain bagi sesuatu kod pendek dengan membaca header Host. Oleh itu, proksi yang menulis semula header ini akan menyebabkan respons 404 pada pautan yang wujud, serta statistik lawatan akan dikaitkan dengan domain yang salah.

server {
    server_name s.example.com;
    listen 80;

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

Seterusnya, jana sijil tersebut. Panduan lengkap, termasuk pemasa pembaharuan, terdapat dalam panduan Certbot untuk nginx pada Ubuntu 24.04.

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

IS_HTTPS_ENABLED: "true" dalam fail compose adalah tetapan yang menyebabkan Shlink mencetak https:// dalam URL pendek yang dikembalikan. Tetapan ini tidak mengaktifkan TLS secara automatik. Biarkan ia ditetapkan kepada false di belakang proksi HTTPS, kerana jika tidak, setiap pautan yang dikembalikan oleh API akan menjadi pautan http:// yang kemudiannya perlu dihalakan semula (redirect). Ini menambah satu pusingan perjalanan (round trip) rangkaian dan kelihatan tidak tepat pada web client.

Mencipta kunci API

Tiada apa-apa yang boleh berhubung dengan API tanpa kunci. Jana satu kunci melalui CLI di dalam kontena.

sudo docker compose exec shlink shlink api-key:generate --name "web client"

Perintah ini mencetak kunci tersebut sekali sahaja. Salin kunci itu sekarang, kerana ia disimpan dalam bentuk hash dan tidak boleh dipaparkan lagi. shlink api-key:list memaparkan nama dan status sama ada setiap kunci diaktifkan atau tidak, tetapi tidak memaparkan kunci itu sendiri. Batalkan kunci dengan shlink api-key:disable dan sertakan namanya.

Setiap panggilan REST membawa kunci tersebut dalam pengepala X-Api-Key.

curl -H "X-Api-Key: YOUR_KEY" https://s.example.com/rest/v3/short-urls

Objek JSON dengan kunci shortUrls bermakna kunci tersebut berfungsi. 401 yang membawa INVALID_API_KEY bermakna kunci tersebut salah, dinyahaktifkan, atau telah melepasi tarikh luputnya.

Mencipta pautan pendek daripada baris perintah

CLI ialah cara terpantas untuk membuat pautan, dan ia merupakan kaedah yang berfungsi dengan baik dalam skrip.

sudo docker compose exec shlink shlink short-url:create https://example.com/a/very/long/path
sudo docker compose exec shlink shlink short-url:create https://example.com/docs --custom-slug docs --tag reference

--custom-slug memberikan anda pautan yang boleh dibaca dan bukannya kod yang dijana secara rawak. Slug adalah unik bagi setiap domain, jadi percubaan kedua pada slug yang telah digunakan akan gagal dan bukannya menimpa pautan pertama secara senyap. --tag boleh diulang, dan tag ialah cara anda mengumpulkan pautan yang anda ingin lihat statistik gabungannya nanti.

Senaraikan pautan yang sedia ada, kemudian lihat trafik bagi satu pautan.

sudo docker compose exec shlink shlink short-url:list
sudo docker compose exec shlink shlink short-url:visits docs

short-url:visits mencetak satu baris bagi setiap klik dengan tarikh, perujuk (referrer) dan ejen pengguna (user agent). Lajur negara dan bandar akan kekal kosong melainkan anda menetapkan pemboleh ubah persekitaran GEOLITE_LICENSE_KEY, iaitu kunci MaxMind percuma yang digunakan oleh Shlink untuk memuat turun pangkalan data GeoLite2. Tanpanya, lawatan masih direkodkan, cuma ia tidak diletakkan lokasinya.

Pelanggan web dan kod QR

Pelanggan web kini berada pada 127.0.0.1:8081 dan memerlukan entri proksi sendiri, atau terowong SSH jika anda tidak mahu menerbitkannya. Ia akan meminta URL pelayan dan kunci API semasa muatan pertama. Masukkan https://s.example.com dan kunci yang telah anda jana. Pelanggan menyimpan kedua-duanya dalam storan pelayar dan memanggil API anda secara terus, jadi tiada data yang melalui pihak lain. Memisahkan antara muka daripada API adalah corak yang wajar diperhatikan, kerana ia merupakan corak yang sama yang membolehkan Halcyon mengubah pustaka Jellyfin menjadi kedai sewa video tahun 1990-an tanpa mengubah pelayan media di belakangnya.

Kod QR tidak memerlukan sebarang konfigurasi. Tambahkan /qr-code pada mana-mana URL pendek dan API akan mengembalikan imej tersebut.

https://s.example.com/docs/qr-code?size=500&format=svg&margin=20

size ialah lebar dalam piksel dan menerima nilai 50 hingga 1000, dengan 300 sebagai nilai lalai. format ialah png atau svg. margin ialah ruang senyap di sekeliling kod dalam piksel, dan imej akhir berukuran saiz tersebut ditambah dua kali ganda margin. Tambahkan errorCorrection=Q untuk kod yang masih boleh diimbas apabila dicetak kecil atau sebahagiannya tertutup.

Pastikan ia terus berjalan

Pemendek pautan gagal secara senyap. Pautan berhenti mengubah hala dan tiada sesiapa memberitahu anda, kerana pengguna yang mengklik menganggap pautan tersebut sudah mati. Halakan semakan uptime ke URL pendek yang sebenar dan bukannya ke halaman utama, serta berikan amaran untuk sebarang respons yang bukan pengalihan (redirect). Instans Uptime Kuma yang dihoskan sendiri melakukan perkara ini dengan baik, dan ia boleh memantau kod status tertentu.

Sandarkan pangkalan data, bukan kontena. Satu arahan akan melakukan dump pangkalan data tersebut.

sudo docker compose exec -T database pg_dump -U shlink shlink | gzip > shlink-$(date +%F).sql.gz

Fail tersebut berserta fail compose anda akan membina semula keseluruhan servis pada pelayan baharu. Setiap aplikasi pada pelayan memerlukan pasangan fail tersebut, dan pustaka foto merupakan kes yang rumit, kerana PhotoPrism dan Immich kedua-duanya menyimpan fail asal pada cakera selain baris data dalam pangkalan data, jadi dump sahaja tidak akan memulihkan apa-apa. Naik taraf dilakukan dengan sudo docker compose pull diikuti oleh sudo docker compose up -d, dan Shlink akan menjalankan sebarang migrasi baharu semasa permulaan. Lakukan dump sebelum anda melakukan pull, kerana migrasi tidak boleh dibatalkan (roll back).

FAQ

Mengapakah pautan pendek saya memaparkan ralat 404 selepas saya menambah reverse proxy?

Shlink memadankan kod pendek dengan domain dalam header Host. Proksi yang menghantar namanya sendiri, atau alamat dalaman, menyebabkan Shlink mencari kod tersebut di bawah domain yang tidak mempunyai pautan, lalu ia membalas dengan ralat 404. Tetapkan proxy_set_header Host $host; dalam blok lokasi nginx dan muat semula proksi tersebut. Pautan akan terus berfungsi serta-merta, tanpa perlu memulakan semula container.

Adakah saya perlukan Postgres, atau adakah SQLite sudah memadai?

SQLite memadai untuk mencuba Shlink dan tidak memerlukan container kedua. Beralihlah kepada Postgres sebelum anda menerbitkan pautan yang penting, kerana baris lawatan akan bertambah dengan setiap klik dan SQLite melakukan penulisan secara bersiri (serialize). Penukaran pada masa hadapan bermakna anda perlu mengeksport dan mengimport semula pautan anda, jadi memilih Postgres dari awal menjimatkan anda daripada proses migrasi tersebut.

Bolehkah saya mendapatkan semula API key yang terlupa untuk disalin?

Tidak. Shlink menyimpan hash bagi kunci tersebut, jadi api-key:list hanya memaparkan nama dan status tetapi tidak akan memaparkan nilainya. Jana kunci gantian dengan shlink api-key:generate, tampal ke dalam klien web, kemudian nyahaktifkan kunci lama dengan shlink api-key:disable supaya ia berhenti berfungsi.

Mengapakah lajur negara kosong dalam statistik lawatan saya?

Geolokasi memerlukan pangkalan data GeoLite2, yang hanya dimuat turun oleh Shlink apabila anda memberikan GEOLITE_LICENSE_KEY. Kunci tersebut adalah percuma daripada MaxMind. Tambahkannya ke dalam bahagian environment, bina semula container, dan lawatan baharu akan dikesan lokasinya. Lawatan yang direkodkan sebelum itu akan kekal kosong sehingga anda menjalankan shlink visit:locate.

Kekalkan domain dan pindahkan data. Lakukan dump pangkalan data dengan pg_dump, salin fail dump dan fail compose ke pelayan baharu, mulakan stack, kemudian pulihkan (restore) dump tersebut ke dalam pangkalan data yang kosong sebelum trafik sebenar tiba. Tukar rekod DNS pada langkah terakhir. Kod pendek dan sejarah lawatannya akan kekal terpelihara, kerana semuanya disimpan di dalam pangkalan data.

#shlink#url-shortener#self-hosting#docker#postgres