Skip to content

Instantly share code, notes, and snippets.

@fadlee
Last active July 27, 2026 23:05
Show Gist options
  • Select an option

  • Save fadlee/6aa8826addd7ee736ba5bb6dfa4c7bd8 to your computer and use it in GitHub Desktop.

Select an option

Save fadlee/6aa8826addd7ee736ba5bb6dfa4c7bd8 to your computer and use it in GitHub Desktop.
Tutorial Deploy MeshCentral di EasyPanel + Fix Agent Bad Web Cert Hash

Tutorial Deploy MeshCentral di EasyPanel + Fix Agent Bad Web Cert Hash

Panduan ini dibuat berdasarkan kasus real deployment MeshCentral di EasyPanel dengan Docker/Swarm dan reverse proxy bawaan EasyPanel/Traefik.

Target akhir:

  • MeshCentral bisa diakses via domain sendiri, contoh: https://mesh.darsya.my.id
  • Agent bisa install normal dari command dashboard MeshCentral
  • Tidak muncul error:
    • Agent bad web cert hash
    • invalid origin in HTTP request

1. Kenapa MeshCentral di EasyPanel sering error?

EasyPanel biasanya menjalankan app di belakang reverse proxy/TLS offload.

Artinya:

Browser / Mesh Agent
        |
        | HTTPS cert publik dari EasyPanel / Cloudflare / Let's Encrypt
        v
EasyPanel Reverse Proxy
        |
        | koneksi internal ke container MeshCentral
        v
MeshCentral container

MeshCentral sangat sensitif terhadap hash sertifikat web. Agent yang di-download dari dashboard membawa informasi hash cert server. Kalau agent melihat cert publik dari proxy, tapi MeshCentral mengira cert internal/self-signed yang dipakai, maka agent akan ditolak.

Gejalanya di log:

Agent bad web cert hash (Agent:xxxx != Server:yyyy or zzzz), holding connection
Agent reported web cert hash: xxxxxxxxxx...

Solusinya: MeshCentral harus diberi tahu URL publik yang dipakai agent lewat config certUrl.


2. Deploy container MeshCentral di EasyPanel

Gunakan image resmi:

ghcr.io/ylianst/meshcentral:latest-slim

Recommended volume persistent:

/opt/meshcentral/meshcentral-data
/opt/meshcentral/meshcentral-files
/opt/meshcentral/meshcentral-backups
/opt/meshcentral/meshcentral-web

Minimal yang wajib dipersistent-kan adalah:

/opt/meshcentral/meshcentral-data

Karena folder ini berisi:

  • config.json
  • database lokal
  • sertifikat MeshCentral
  • signing cert agent

Kalau volume ini hilang, agent lama bisa rusak koneksinya.


3. Environment variables di EasyPanel

Contoh env untuk domain mesh.example.com:

HOSTNAME=mesh.example.com
PORT=443
ALLOW_NEW_ACCOUNTS=true
TZ=Asia/Jakarta
REVERSE_PROXY=10.0.1.0/24
REVERSE_PROXY_TLS_PORT=443

Catatan:

  • HOSTNAME harus sama dengan domain publik final.
  • ALLOW_NEW_ACCOUNTS=true hanya untuk setup awal. Setelah admin dibuat, sebaiknya ubah ke false.
  • REVERSE_PROXY bawaan EasyPanel bisa berbeda range IP-nya. Pada kasus saya, proxy masuk dari network 10.11.x.x, jadi perlu ditambahkan juga di config MeshCentral.

4. Setup domain di EasyPanel

Di EasyPanel:

  1. Buka app MeshCentral.
  2. Tambahkan domain, contoh:
mesh.example.com
  1. Arahkan DNS domain ke server EasyPanel.
  2. Pastikan HTTPS/SSL aktif di EasyPanel.

Kalau pakai Cloudflare:

  • DNS boleh proxied/orange cloud jika halaman web berjalan normal.
  • Untuk debugging, bisa pakai DNS only sementara.
  • Pastikan SSL mode Cloudflare tidak membuat loop/error. Umumnya Full atau Full (strict) jika origin cert valid.

Tes dari server:

curl -I https://mesh.example.com/

Harus dapat HTTP/2 200 atau minimal response dari MeshCentral, bukan 502.


5. Edit config.json MeshCentral

Masuk ke container:

docker ps | grep meshcentral

Contoh nama container:

prod_darsya-mesh.1.xxxxx

Buka config:

docker exec -it <nama-container> sh
vi /opt/meshcentral/meshcentral-data/config.json

Atau edit dari host jika volume bisa diakses.

Contoh config final yang disarankan:

{
  "$schema": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json",
  "settings": {
    "plugins": {
      "enabled": false
    },
    "cert": "mesh.example.com",
    "port": 443,
    "redirPort": 80,
    "AgentPong": 300,
    "tlsOffload": "10.0.1.0/24,10.11.0.0/16",
    "trustedProxy": "10.0.1.0/24,10.11.0.0/16",
    "SelfUpdate": false,
    "AllowFraming": false,
    "WebRTC": false
  },
  "domains": {
    "": {
      "minify": false,
      "NewAccounts": true,
      "localSessionRecording": true,
      "allowedOrigin": false,
      "certUrl": "https://mesh.example.com/"
    }
  }
}

Ganti semua mesh.example.com dengan domain kamu.

Poin paling penting:

"cert": "mesh.example.com"
"certUrl": "https://mesh.example.com/"
"tlsOffload": "10.0.1.0/24,10.11.0.0/16"
"trustedProxy": "10.0.1.0/24,10.11.0.0/16"

Kenapa 10.11.0.0/16? Pada kasus EasyPanel saya, request agent masuk ke MeshCentral dari IP internal 10.11.x.x. Jika log kamu menunjukkan IP internal lain, sesuaikan range-nya.

Contoh log:

holding connection (10.11.0.4:59646)

Maka masukkan 10.11.0.0/16.


5A. Cara mendapatkan IP internal reverse proxy EasyPanel

Bagian ini penting karena nilai tlsOffload dan trustedProxy harus mencakup IP internal reverse proxy yang benar. Kalau salah, MeshCentral bisa salah membaca header proxy dan agent/websocket bisa bermasalah.

Ada beberapa cara untuk mengetahuinya.

Cara 1: Lihat dari log Agent bad web cert hash

Ini cara paling mudah kalau agent sudah pernah mencoba connect.

Jalankan:

docker logs <nama-container> 2>&1 | grep -i "Agent bad web cert hash"

Contoh output:

Agent bad web cert hash (Agent:a3b321a97d != Server:9974a5ee65 or 8c50ad4960), holding connection (10.11.0.4:59646).

Perhatikan bagian akhir:

(10.11.0.4:59646)

Itu adalah IP yang terlihat oleh MeshCentral saat koneksi agent masuk. Dalam contoh ini IP-nya 10.11.0.4, jadi range yang aman untuk dimasukkan adalah:

"tlsOffload": "10.11.0.0/16",
"trustedProxy": "10.11.0.0/16"

Kalau sebelumnya sudah ada range lain, gabungkan dengan koma:

"tlsOffload": "10.0.1.0/24,10.11.0.0/16",
"trustedProxy": "10.0.1.0/24,10.11.0.0/16"

Cara 2: Inspect network container MeshCentral

Jalankan:

docker inspect <nama-container> --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{$v.IPAddress}}{{"\n"}}{{end}}'

Contoh output:

easypanel 10.11.218.144
easypanel-prod 10.0.1.233

Dari sini terlihat container terhubung ke network 10.11.x.x dan 10.0.1.x. Maka config yang masuk akal:

"tlsOffload": "10.0.1.0/24,10.11.0.0/16",
"trustedProxy": "10.0.1.0/24,10.11.0.0/16"

Catatan: IP container MeshCentral bukan selalu IP proxy, tapi network range-nya biasanya sama dengan network tempat proxy EasyPanel berkomunikasi. Untuk memastikan, tetap lebih akurat memakai Cara 1 dari log koneksi masuk.

Cara 3: Inspect service/network di Docker Swarm

Kalau EasyPanel deploy sebagai Docker Swarm service:

docker service inspect <nama-service> --pretty

Cari bagian:

Networks:

Lalu inspect network tersebut:

docker network inspect <nama-network> | grep -A 5 -i subnet

Contoh output:

"Subnet": "10.11.0.0/16"

Masukkan subnet itu ke tlsOffload dan trustedProxy.

Cara 4: Lihat semua network Docker yang berkaitan dengan EasyPanel

docker network ls

Lalu inspect network yang namanya mirip easypanel atau network app kamu:

docker network inspect <nama-network>

Cari bagian IPAM/Subnet:

"IPAM": {
  "Config": [
    {
      "Subnet": "10.11.0.0/16"
    }
  ]
}

Tips memilih range

Kalau IP yang muncul adalah:

10.11.0.4

Pakai:

10.11.0.0/16

Kalau IP yang muncul adalah:

10.0.1.233

Pakai:

10.0.1.0/24

Kalau ragu, masukkan dua-duanya seperti ini:

"tlsOffload": "10.0.1.0/24,10.11.0.0/16",
"trustedProxy": "10.0.1.0/24,10.11.0.0/16"

Jangan isi terlalu luas seperti 0.0.0.0/0, karena itu berarti mempercayai forwarded headers dari semua sumber.


6. Restart service/container

Jika EasyPanel pakai Docker Swarm:

docker service update --force <nama-service>

Contoh:

docker service update --force prod_darsya-mesh

Jika container biasa:

docker restart <nama-container>

Lihat log:

docker logs -f <nama-container>

Log yang diharapkan:

Loaded web certificate from "https://mesh.example.com/", host: "mesh.example.com"
  SHA384 cert hash: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MeshCentral HTTP server running on port 443.

Kalau sudah muncul Loaded web certificate from ..., berarti certUrl sudah bekerja.


7. Buat admin account

Buka:

https://mesh.example.com

Buat account admin pertama.

Setelah itu, untuk keamanan, ubah:

"NewAccounts": false

atau env:

ALLOW_NEW_ACCOUNTS=false

Lalu restart lagi.


8. Install agent

Penting: setelah config domain dan cert sudah benar, generate/copy ulang command install dari dashboard MeshCentral.

Jangan pakai command lama dari domain lama.

Langkah:

  1. Login ke https://mesh.example.com
  2. Buat device group.
  3. Klik Add Agent.
  4. Pilih OS client.
  5. Copy command install terbaru.
  6. Jalankan di client.

Kalau sebelumnya agent sudah pernah install dari domain lama, uninstall dulu agent lama lalu install ulang.


9. Cara cek hash cert publik

Dari host/server:

printf '' | openssl s_client -connect mesh.example.com:443 -servername mesh.example.com 2>/dev/null \
  | openssl x509 -noout -fingerprint -sha384

Contoh output:

sha384 Fingerprint=30:63:05:8B:85:24:96:BD:...

MeshCentral log harus menampilkan hash yang sama setelah certUrl loaded.


10. Troubleshooting

A. Error: Agent bad web cert hash

Contoh:

Agent bad web cert hash (Agent:a3b321a97d != Server:9974a5ee65 or 8c50ad4960)
Agent reported web cert hash:a3b321a97d...

Penyebab:

  • MeshCentral belum tahu sertifikat publik reverse proxy.
  • certUrl belum ada atau salah.
  • Agent masih install dari command/domain lama.

Fix:

  1. Pastikan config punya:
"certUrl": "https://mesh.example.com/"
  1. Restart MeshCentral.
  2. Pastikan log menampilkan:
Loaded web certificate from "https://mesh.example.com/"
  1. Copy ulang command agent dari dashboard.
  2. Reinstall agent.

B. Error: invalid origin in HTTP request

Penyebab umum:

  • Domain yang diakses browser berbeda dengan settings.cert di MeshCentral.
  • Baru pindah domain tapi config masih domain lama.
  • Reverse proxy mengirim header Host/Origin berbeda.

Fix:

Pastikan:

"cert": "mesh.example.com"

Dan:

"certUrl": "https://mesh.example.com/"

Lalu restart.

Jika masih error, pastikan domain di EasyPanel benar-benar forward ke app yang sama dan header Host tidak diubah ke domain internal.


C. Setelah ganti domain, agent lama tidak connect

Ini normal. Agent lama kemungkinan membawa hash/URL dari domain lama.

Fix:

  1. Login dashboard via domain baru.
  2. Copy ulang command install agent.
  3. Uninstall agent lama di client.
  4. Install agent baru.

D. EasyPanel / Cloudflare memberi 502

Cek:

docker logs <nama-container>

Pastikan MeshCentral benar-benar running:

MeshCentral HTTP server running on port 443.

Jika MeshCentral masih generate certificate/sign agent, tunggu beberapa menit.

Cek juga apakah domain di EasyPanel mengarah ke port container yang benar.


11. Contoh command edit cepat dari dalam container

Kalau container punya Node.js, bisa edit otomatis seperti ini:

docker exec <nama-container> sh -lc '
CFG=/opt/meshcentral/meshcentral-data/config.json
cp "$CFG" "$CFG.bak.$(date +%Y%m%d-%H%M%S)"
node - <<"NODE"
const fs = require("fs");
const cfg = "/opt/meshcentral/meshcentral-data/config.json";
const domain = "mesh.example.com";
const data = JSON.parse(fs.readFileSync(cfg, "utf8"));
data.settings = data.settings || {};
data.settings.cert = domain;
data.settings.tlsOffload = "10.0.1.0/24,10.11.0.0/16";
data.settings.trustedProxy = "10.0.1.0/24,10.11.0.0/16";
data.domains = data.domains || {};
data.domains[""] = data.domains[""] || {};
data.domains[""].certUrl = `https://${domain}/`;
fs.writeFileSync(cfg, JSON.stringify(data, null, 2) + "\n");
NODE
'

Lalu restart:

docker service update --force <nama-service>

atau:

docker restart <nama-container>

12. Checklist final

  • Domain publik sudah resolve ke EasyPanel.
  • HTTPS domain sudah aktif.
  • settings.cert sama dengan domain publik.
  • domains[""].certUrl mengarah ke URL publik HTTPS.
  • tlsOffload dan trustedProxy mencakup IP/range reverse proxy EasyPanel.
  • Log menampilkan Loaded web certificate from ....
  • Dashboard dibuka via domain final.
  • Command install agent dicopy ulang setelah config benar.
  • Agent lama dari domain lama di-uninstall/reinstall.

13. Referensi config minimal

{
  "$schema": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json",
  "settings": {
    "cert": "mesh.example.com",
    "port": 443,
    "redirPort": 80,
    "tlsOffload": "10.0.1.0/24,10.11.0.0/16",
    "trustedProxy": "10.0.1.0/24,10.11.0.0/16"
  },
  "domains": {
    "": {
      "NewAccounts": false,
      "certUrl": "https://mesh.example.com/"
    }
  }
}

Selesai.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment