# آموزش راه‌اندازی ELK Stack در سازمان؛ از معماری تا مانیتورینگ و امنیت

راهنمای عملی نصب امن Elastic Stack روی Ubuntu؛ TLS، Fleet، جمع‌آوری لاگ، Data Stream، ILM، کلاستر، Snapshot و عیب‌یابی سرویس‌های سازمانی.

## از لاگ گمشده شروع کنید، نه از فایل نصب

حساب Windows ساعت ۹:۱۲ قفل می‌شود، برنامه خطای 502 می‌دهد و Firewall چند ارتباط را رد می‌کند. اگر خط زمانی مشترکی نداشته باشیم، همین رخداد ممکن است به سه تیکت جدا تبدیل شود. در سناریوی فرضی این راهنما، اولین آزمون تحویل این است که هر سه رویداد با Host، زمان اصلی و Source درست پیدا شوند. باز شدن صفحه Kibana به‌تنهایی این آزمون را پاس نمی‌کند.

مبنای قابل بازتولید، Elastic Stack و Elastic Agent نسخه 9.5.6 روی Ubuntu Server 24.04 LTS با معماری amd64 است. راهنمای جاری نصب Debian همین نسخه را معرفی می‌کند و Ubuntu 24.04 در ماتریس پشتیبانی آمده است. Elasticsearch، Kibana، Logstash و Agent را هم‌نسخه نگه دارید و پیش از اجرای واقعی، اصلاحات امنیتی انتشارهای بعدی را بررسی کنید. Integration Packageها نسخه و حداقل Kibana مستقل دارند؛ آن‌ها را جدا ثبت کنید. نمونه‌ها با مستندات رسمی تطبیق داده شده‌اند؛ اجرای Cluster واقعی یا Benchmark عملیاتی برایشان ادعا نمی‌شود.

[Elastic: نصب بسته Debian و انتخاب نسخه](https://www.elastic.co/docs/deploy-manage/deploy/self-managed/install-elasticsearch-with-debian-package)

[ماتریس پشتیبانی Elastic؛ سیستم‌عامل، JVM و Agent](https://www.elastic.co/support/matrix)

[یادداشت انتشار و دوره پشتیبانی Ubuntu 24.04 LTS](https://documentation.ubuntu.com/release-notes/24.04/)

## قبل از تخصیص ماشین، مسئولیت هر جزء را مشخص کنید

![مسیر داده Elastic از Agent یا Relay تا Ingest و Elasticsearch؛ ‏Fleet سیاست Agent را مدیریت می‌کند](/assets/img/articles/content/elk-stack-enterprise-installation-guide/ingestion.svg)

Elasticsearch ذخیره‌سازی، Index و جست‌وجو را انجام می‌دهد؛ Kibana رابط بررسی، نمودار، مدیریت و Rule است. Ingest Pipeline پردازنده‌هایی است که داخل Elasticsearch اجرا می‌شوند. Logstash سرویس مستقلی برای تبدیل و مسیریابی داده است و وقتی Parsing پیچیده، چند خروجی یا Persistent Queue لازم باشد ارزش دارد. وجودش اجباری نیست؛ اضافه‌کردن یک Hop به مسیر همه Sourceها بدون نیاز مشخص، یک صف دیگر برای نگهداری ایجاد می‌کند.

Elastic Agent روی Host یا Collector، Integrationها را اجرا می‌کند. Fleet در Kibana مسئول Policy و Enrollment است و Fleet Server این وضعیت مدیریتی را به Agentها می‌رساند. وقتی خروجی Elasticsearch است، خود Agent داده رویداد را مستقیم به Elasticsearch می‌فرستد؛ Fleet Server واسط عبور همه لاگ‌ها نیست. Beats برای نصب‌های موجود یا نیازهای خاص همچنان گزینه‌اند؛ Filebeat فایل و Winlogbeat رخداد Windows را جمع می‌کنند. خواندن هم‌زمان یک فایل با Agent و Beats، بدون قصد مشخص، داده تکراری می‌سازد.

| مدل | توپولوژی و دسترس‌پذیری | منابع شروع؛ پیش از خرید اندازه‌گیری کنید |
| --- | --- | --- |
| Lab | یک VM با همه سرویس‌ها و یک Node؛ فاقد HA | ۴ تا ۸ vCPU، رم ۱۶ GB و SSD؛ فقط داده آزمایشی |
| Production کوچک | سه Node با نقش ترکیبی در Failure Domainهای جدا؛ Kibana و Collector مستقل | برای Pilot هر ES Node حدود ۸ vCPU و رم ۳۲ GB؛ دیسک بر اساس حجم واقعی |
| Production سازمانی | سه Master مستقل، حداقل دو Data Node با نقش Hot/Content و در صورت نیاز Ingest مستقل؛ دو Kibana و Fleet | منابع Master و Data جدا اندازه‌گیری شوند؛ Warm فقط با نیاز مشخص Retention |

سه VM روی یک ESXi یا یک Failure Domain مشترک ذخیره‌سازی، سه نسخه مستقل سرویس نیستند. Placement را توزیع کنید و ظرفیت زمان خارج بودن یک Data Node برای نگهداری را هم حساب کنید. سازمان کوچکی که قطعی را می‌پذیرد می‌تواند یک Node عملیاتی همراه Snapshot داشته باشد، اما این استثنای دسترس‌پذیری باید ثبت شود؛ افزایش RAM، HA ایجاد نمی‌کند.

## نام‌ها، دیسک‌ها و مسیر شبکه را آماده کنید

نمونه Production کوچک از es01.logs.example.net با IP برابر 10.20.30.11، ‏es02 با .12 و es03 با .13 استفاده می‌کند؛ Kibana روی .21 و Fleet روی .22 است. پیش از اجرا تمام IPها، نام‌ها و SANهای Certificate را جایگزین کنید. DNS باید از سرورها و Collectorها پاسخ یکسان بدهد و NTP پیش از مقایسه زمان رویداد با زمان ورود داده درست باشد. Ubuntu، RHEL و توزیع‌های دیگر ردیف‌های پشتیبانی متفاوت دارند؛ این دستورالعمل برای Ubuntu 24.04 است، نه هر لینوکسی.

| مسیر | پورت | محدودیت |
| --- | --- | --- |
| Agent / Kibana / Logstash به Elasticsearch | TCP 9200 | فقط مبدأهای مجاز؛ HTTPS |
| ارتباط Nodeهای Elasticsearch | TCP 9300 | فقط Nodeهای Cluster؛ ‏Transport TLS |
| مرورگر به Kibana | TCP 5601 | شبکه مدیریت یا Reverse Proxy دارای HTTPS |
| Agent به Fleet Server | TCP 8220 | Endpointهای مدیریت‌شده؛ HTTPS |
| تجهیز به Collector | UDP/TCP 514 or configured port | ACL برای هر مبدأ؛ UDP فاقد تضمین تحویل و رمزگذاری است |
| Collector به vCenter / SQL / Registry | TCP 443 / 1433 / HTTPS | 1433 پورت رایج SQL است، نه پورت همه Named Instanceها؛ فقط سرویس لازم مجاز باشد |

```bash
hostnamectl
getent hosts es01.logs.example.net es02.logs.example.net es03.logs.example.net
timedatectl status
lsblk -f
df -hT
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg unzip sysstat
printf 'vm.max_map_count=1048576
' | sudo tee /etc/sysctl.d/99-elasticsearch.conf
sudo sysctl --system
sysctl vm.max_map_count
iostat -xz 1 5
```

انتظار داریم ساعت همگام باشد، Mount مربوط به SSD درست دیده شود و vm.max_map_count حداقل 1048576 باشد. iostat ابزار مشاهده است، نه Benchmark مصنوعی؛ تأخیر و صف دیسک هنگام Ingest و Search نماینده بار واقعی، از نام مدل دیسک مهم‌تر است. تا حد امکان Data را از فایل‌سیستم Root جدا و Mount را قبل از شروع سرویس برقرار کنید. از JDK همراه بسته استفاده کنید؛ نصب Java دلخواه سیستم لازم نیست. ابتدا Heap Sizing خودکار را نگه دارید؛ Heap دستی باید برای File System Cache جا بگذارد و معمولاً از نصف RAM در دسترس فراتر نرود.

[Elastic: مقدار پیشنهادی فعلی vm.max_map_count](https://www.elastic.co/docs/deploy-manage/deploy/self-managed/vm-max-map-count)

[Elastic: تنظیمات JVM و Heap](https://www.elastic.co/docs/reference/elasticsearch/jvm-settings)

## یک انتشار یکسان برای همه نقش‌ها نصب کنید

Repository را روی هر Ubuntu Host تنظیم کنید. فقط بسته نقش همان Host را نصب کنید: Elasticsearch روی es01 تا es03، ‏Kibana روی .21 و Logstash فقط روی Host تبدیل داده اختیاری. apt امضای Repository را بررسی می‌کند؛ پیش از اعتماد به کلید تازه‌دریافت‌شده، Fingerprint آن را با مستند فروشنده تطبیق دهید. اگر نسخه Pinشده موجود نبود، متوقف شوید و نسخه دیگری را بی‌سروصدا جایگزین نکنید.

```bash
curl -fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch -o /tmp/elastic-signing-key.asc
gpg --show-keys --with-fingerprint /tmp/elastic-signing-key.asc
sudo gpg --dearmor --output /usr/share/keyrings/elasticsearch-keyring.gpg /tmp/elastic-signing-key.asc
echo 'deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/9.x/apt stable main' | sudo tee /etc/apt/sources.list.d/elastic-9.x.list
sudo apt-get update
apt-cache policy elasticsearch kibana logstash
# Run the appropriate line on its designated host, not all three everywhere.
sudo apt-get install elasticsearch=9.5.6
sudo apt-mark hold elasticsearch
# On the Kibana host:
sudo apt-get install kibana=9.5.6
sudo apt-mark hold kibana
# On an optional Logstash host:
LOGSTASH_DEB_VERSION=$(apt-cache madison logstash | awk '$3 ~ /(^|:)9[.]5[.]6(-|$)/ {print $3; exit}')
test -n "$LOGSTASH_DEB_VERSION" || { echo 'Pinned Logstash release is absent'; exit 1; }
sudo apt-get install "logstash=$LOGSTASH_DEB_VERSION"
sudo apt-mark hold logstash
```

نسخه بسته Elasticsearch و Kibana برابر 9.5.6 است. فرمان Logstash فقط انتشار بالادستی 9.5.6 را انتخاب می‌کند و Epoch/Revision واقعی Debian را از Metadata مخزن نگه می‌دارد؛ نبود نسخه باعث توقف می‌شود. قبل از تأیید apt مقدار انتخاب‌شده را بخوانید. Hold جلوی Upgrade ناخواسته یکی از اجزا را می‌گیرد؛ در مقابل، اعمال اصلاحات امنیتی باید وظیفه صریح تیم عملیات باشد. خروجی dpkg-query را در فهرست نصب نگه دارید.

```bash
dpkg-query -W -f='${Package} ${Version}
' elasticsearch
# Run on the corresponding hosts:
dpkg-query -W -f='${Package} ${Version}
' kibana
dpkg-query -W -f='${Package} ${Version}
' logstash
```

## قبل از روشن‌کردن Cluster، ‏Certificate صادر کنید

این نصب از اولین Start، ‏TLS دستی دارد؛ تنظیمات آن را با بلوک امنیتی خودکار Nodeی که قبلاً اجرا شده ادغام نکنید. نمونه از سیستم صدور Certificate با دسترسی محدود و ابزارهای همین Elasticsearch استفاده می‌کند. PKI سازمان هم می‌تواند Certificateهای معادل صادر کند. هر Node کلید خصوصی مستقل و DNS SAN خودش را لازم دارد. کلید خصوصی صادرکننده روی سیستم صدور می‌ماند و به Data Node یا Agent منتقل نمی‌شود. نسخه رمزگذاری‌شده آفلاین CA و مسئول تمدید آن مشخص باشد.

```bash
sudo -i
sudo install -d -m 0700 /root/elastic-pki
cd /root/elastic-pki
sudo /usr/share/elasticsearch/bin/elasticsearch-certutil ca --pem --out ca.zip
sudo unzip ca.zip
sudo chmod 0600 ca/ca.key
sudo tee instances.yml >/dev/null <<'YAML'
instances:
  - name: es01
    dns: [es01.logs.example.net]
    ip: [10.20.30.11]
  - name: es02
    dns: [es02.logs.example.net]
    ip: [10.20.30.12]
  - name: es03
    dns: [es03.logs.example.net]
    ip: [10.20.30.13]
  - name: kibana
    dns: [kibana.logs.example.net]
    ip: [10.20.30.21]
  - name: fleet
    dns: [fleet.logs.example.net]
    ip: [10.20.30.22]
YAML
sudo /usr/share/elasticsearch/bin/elasticsearch-certutil cert --pem \
  --in instances.yml --ca-cert ca/ca.crt --ca-key ca/ca.key --out instances.zip
sudo unzip instances.zip
exit
```

فقط ca.crt و Certificate/Key همان Host را از مسیر دارای احراز هویت منتقل کنید. در هر Elasticsearch Node آن‌ها را با نام‌های ca.crt، ‏node.crt و node.key در /etc/elasticsearch/certs/ قرار دهید؛ مالک root:elasticsearch، مجوز پوشه 0750 و فایل‌ها 0640 باشد. در Kibana مسیر /etc/kibana/certs/ و گروه kibana را به کار ببرید. برای Fleet، پوشه root:root با 0700 و کلید خصوصی 0600 مناسب است. نمونه کلید سرویس بدون Passphrase و با مجوز محدود دارد؛ اگر سیاست سازمان کلید رمزگذاری‌شده می‌خواهد، تنظیم Secure Passphrase مربوط را هم پیاده کنید تا Boot منتظر ورودی تعاملی نماند.

[Elastic certutil: ‏SAN مستقل و Certificateهای PEM](https://www.elastic.co/docs/reference/elasticsearch/command-line-tools/certutil)

## Cluster سه‌Node برای Production کوچک بسازید

روی es01 تازه، فایل /etc/elasticsearch/elasticsearch.yml زیر را بنویسید. در es02 و es03، ‏node.name و network.host را برای همان Host تغییر دهید و کلید مستقل آن را قرار دهید. cluster.initial_master_nodes فقط در اولین Bootstrap این سه Master-eligible Node جدید، یکسان است؛ فهرست Restartهای آینده نیست. Cluster موجود را هرگز دوباره Bootstrap نکنید.

```yaml
cluster.name: meetaj-logs-prod
node.name: es01
network.host: 10.20.30.11
http.port: 9200
transport.port: 9300
node.roles: [master, data, ingest, transform]
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
discovery.seed_hosts: [es01.logs.example.net, es02.logs.example.net, es03.logs.example.net]
cluster.initial_master_nodes: [es01, es02, es03]
xpack.security.enabled: true
xpack.security.autoconfiguration.enabled: false
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: full
xpack.security.transport.ssl.certificate_authorities: [certs/ca.crt]
xpack.security.transport.ssl.certificate: certs/node.crt
xpack.security.transport.ssl.key: certs/node.key
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.certificate_authorities: [certs/ca.crt]
xpack.security.http.ssl.certificate: certs/node.crt
xpack.security.http.ssl.key: certs/node.key
```

```bash
sudo systemctl edit elasticsearch
# Enter the following drop-in, save, then exit:
# [Service]
# LimitNOFILE=65535
sudo systemctl daemon-reload
sudo systemctl enable --now elasticsearch
sudo systemctl status elasticsearch --no-pager
sudo journalctl -u elasticsearch -n 80 --no-pager
sudo /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic -i
systemctl show elasticsearch -p LimitNOFILE
```

هر سه Node را Start کنید و سپس Reset Password را یک‌بار روی عضو سالم اجرا کنید. رمز Administrator تولیدشده را تعاملی وارد و در Vault سازمان ثبت کنید. این ابزار در داخل از File Realm استفاده می‌کند؛ آن را پیش از Bootstrap غیرفعال نکنید. در Shell مدیریتی محدود از curl -u elastic استفاده کنید تا رمز Prompt شود و در History ننشیند. فقط ca.crt عمومی را به آن سیستم مدیریتی منتقل کنید.

```bash
curl --cacert ./ca.crt -u elastic https://es01.logs.example.net:9200/
curl --cacert ./ca.crt -u elastic 'https://es01.logs.example.net:9200/_cat/nodes?v'
curl --cacert ./ca.crt -u elastic 'https://es01.logs.example.net:9200/_cluster/health?pretty'
```

شاهد مورد انتظار یک cluster_uuid مشترک، سه Node و علامت یک Master منتخب در _cat/nodes است و نباید Primary Shard گم‌شده وجود داشته باشد. وضعیت واقعی را بخوانید؛ Cluster خالی ممکن است Green باشد و یک Index با Replica تخصیص‌نیافته آن را Yellow کند. پس از تشکیل Cluster، ‏cluster.initial_master_nodes را از هر سه فایل حذف کنید. در Restart، تعویض Node یا بازیابی بحران آن را برنگردانید؛ discovery.seed_hosts باقی می‌ماند.

### تفاوت Lab

برای VM آموزشی ایزوله، TLS را حفظ کنید، یک Node با discovery.type: single-node داشته باشید و discovery.seed_hosts و cluster.initial_master_nodes را ننویسید. Replica را فقط در Templateهای همان Lab صفر کنید و بپذیرید نسخه دوم Shard وجود ندارد. انتقال YAML یک Lab پُر از داده به Production، مهاجرت محسوب نمی‌شود؛ Cluster مقصد را بسازید و از مسیر پشتیبانی‌شده انتقال داده یا Snapshot استفاده کنید.

[Elastic: ‏Bootstrap اولیه و حذف تنظیم Masterهای اولیه](https://www.elastic.co/docs/deploy-manage/distributed-architecture/discovery-cluster-formation/modules-discovery-bootstrap-cluster)

## Kibana را با HTTPS در دسترس بگذارید

روی یکی از اعضای Elasticsearch رمز kibana_system را تعاملی تعیین کنید. این کاربر برای ارتباط Backend سرویس Kibana است و حساب ورود مرورگر نیست. روی Host مربوط به Kibana همان CA و Certificate صادرشده با نام kibana را قرار دهید. فایل /etc/kibana/kibana.yml را به شکل زیر بنویسید و از کاربر elastic در آن استفاده نکنید.

```bash
sudo /usr/share/elasticsearch/bin/elasticsearch-reset-password -u kibana_system -i
```

```yaml
server.name: meetaj-kibana
server.host: 10.20.30.21
server.publicBaseUrl: https://kibana.logs.example.net:5601
server.ssl.enabled: true
server.ssl.certificate: /etc/kibana/certs/kibana.crt
server.ssl.key: /etc/kibana/certs/kibana.key
elasticsearch.hosts:
  - https://es01.logs.example.net:9200
  - https://es02.logs.example.net:9200
  - https://es03.logs.example.net:9200
elasticsearch.username: kibana_system
elasticsearch.ssl.certificateAuthorities: [/etc/kibana/certs/ca.crt]
elasticsearch.ssl.verificationMode: full
xpack.security.secureCookies: true
```

```bash
sudo env KBN_PATH_CONF=/etc/kibana /usr/share/kibana/bin/kibana-keystore create
sudo env KBN_PATH_CONF=/etc/kibana /usr/share/kibana/bin/kibana-keystore add elasticsearch.password
sudo -u kibana /usr/share/kibana/bin/kibana-encryption-keys generate
# Add each generated value interactively; do not paste real keys into a ticket.
sudo env KBN_PATH_CONF=/etc/kibana /usr/share/kibana/bin/kibana-keystore add xpack.security.encryptionKey
sudo env KBN_PATH_CONF=/etc/kibana /usr/share/kibana/bin/kibana-keystore add xpack.encryptedSavedObjects.encryptionKey
sudo env KBN_PATH_CONF=/etc/kibana /usr/share/kibana/bin/kibana-keystore add xpack.reporting.encryptionKey
sudo chown root:kibana /etc/kibana/kibana.keystore
sudo chmod 0640 /etc/kibana/kibana.keystore
sudo systemctl enable --now kibana
sudo journalctl -u kibana -n 80 --no-pager
curl --cacert ./ca.crt -I https://kibana.logs.example.net:5601/login
```

مقادیر Encryption تولیدشده را در Prompt متناظر وارد و برای بازیابی امن نگهداری کنید. پاسخ 200 یا Redirect ورود با Certificate معتبر، مسیر وب را تأیید می‌کند، نه سلامت Ingest را. ابتدا با Administrator راه‌اندازی وارد شوید، سپس حساب‌های نام‌دار و Roleهای کم‌اختیار بسازید و elastic را برای بازیابی کنار بگذارید. Role خواندن را به Datasetهای لازم در logs-* و Spaceهای موردنیاز محدود کنید. SSO مبتنی بر Identity Provider، ‏Audit Logging تفصیلی و قابلیت‌های امنیتی پیشرفته باید با جدول Subscription تطبیق داده شوند؛ همه را Basic فرض نکنید.

[Elastic: ‏Secure Settings و Keystore](https://www.elastic.co/docs/deploy-manage/security/secure-settings)

[جدول قابلیت‌های Subscription برای Elastic Self-managed](https://www.elastic.co/subscriptions)

## Enrollment مدیریتی را از تحویل لاگ جدا کنید

در Kibana وارد Fleet → Settings شوید و Fleet Server hosts را روی https://fleet.logs.example.net:8220 بگذارید. برای Default Elasticsearch Output هر سه Endpoint از نوع HTTPS و CA را در تنظیم SSL پیشرفته تعیین کنید: ssl.certificate_authorities: ["/etc/elastic-agent/certs/ca.crt"]. این مسیر باید روی تک‌تک Agentها وجود داشته باشد؛ راه دیگر، قراردادن متن PEM عمومی CA در YAML خروجی است. Flag مربوط به certificate-authorities هنگام نصب، اعتماد به Fleet Server را تعیین می‌کند و خودبه‌خود اعتماد خروجی داده به Elasticsearch را حل نمی‌کند.

از Add Fleet Server و مسیر Production/Advanced یک Fleet Server Policy و Service Token بسازید و ID واقعی Policy را ثبت کنید. آرشیو Linux x86_64 نسخه 9.5.6 Agent و SHA-512 منتشرشده را از صفحه رسمی دریافت و قبل از Extract تطبیق دهید. در Fleet Host فایل‌های fleet.crt، ‏fleet.key و ca.crt را با مجوزهای گفته‌شده در /etc/elastic-agent/certs/ بگذارید. مسیر نمونه زیر به آرشیوی اشاره می‌کند که قبلاً از منبع رسمی گرفته و بررسی شده است.

```bash
sha512sum elastic-agent-9.5.6-linux-x86_64.tar.gz
tar -xzf elastic-agent-9.5.6-linux-x86_64.tar.gz
cd elastic-agent-9.5.6-linux-x86_64
read -r -p 'Fleet policy ID: ' FLEET_POLICY_ID
read -r -s -p 'Fleet service token: ' FLEET_SERVICE_TOKEN
printf '
'
sudo ./elastic-agent install \
  --url=https://fleet.logs.example.net:8220 \
  --fleet-server-es=https://es01.logs.example.net:9200 \
  --fleet-server-service-token="$FLEET_SERVICE_TOKEN" \
  --fleet-server-policy="$FLEET_POLICY_ID" \
  --fleet-server-es-ca=/etc/elastic-agent/certs/ca.crt \
  --certificate-authorities=/etc/elastic-agent/certs/ca.crt \
  --fleet-server-cert=/etc/elastic-agent/certs/fleet.crt \
  --fleet-server-cert-key=/etc/elastic-agent/certs/fleet.key \
  --fleet-server-port=8220
unset FLEET_SERVICE_TOKEN
sudo elastic-agent status
```

Token در فایل یا History ثابت نشده، اما آرگومان بازشده CLI ممکن است برای پردازش‌های دارای دسترسی محلی قابل مشاهده باشد. Enrollment را در Session مدیریتی محدود انجام دهید؛ برای اتوماسیون، پس از بررسی Command Reference همان انتشار، از گزینه Token File پشتیبانی‌شده یا انتقال محافظت‌شده Secret استفاده کنید. Token را داخل مخزن اسکریپت مشترک نگذارید. برای پنهان‌کردن خطای CA یا SAN، ‏--insecure اضافه نکنید.

### Enrollment یک Ubuntu Endpoint

یک Policy مستقل برای Agentهای زیرساخت بسازید، System Integration را اضافه کنید و Enrollment Token همان Policy را بگیرید. CA عمومی را در مسیر یکسان /etc/elastic-agent/certs/ca.crt قرار دهید. آرشیو هم‌نسخه و تأییدشده را باز و از پوشه آن دستور زیر را اجرا کنید. وضعیت Fleet باید Healthy باشد و Endpoint هم سند جدید بفرستد؛ Healthy بدون ورود رویداد کافی نیست.

```bash
read -r -s -p 'Agent enrollment token: ' ENROLLMENT_TOKEN
printf '
'
sudo ./elastic-agent install \
  --url=https://fleet.logs.example.net:8220 \
  --enrollment-token="$ENROLLMENT_TOKEN" \
  --certificate-authorities=/etc/elastic-agent/certs/ca.crt
unset ENROLLMENT_TOKEN
sudo elastic-agent status
logger -t meetaj-acceptance 'elastic collection acceptance marker'
```

[بسته‌ها و Checksum رسمی Elastic Agent](https://www.elastic.co/downloads/elastic-agent)

[Fleet: ‏Certificate و TLS مسیر مدیریت و داده](https://www.elastic.co/docs/reference/fleet/secure-connections)

[مرجع فرمان install و enroll در Elastic Agent](https://www.elastic.co/docs/reference/fleet/agent-command-reference)

## هر Source را از رابط پشتیبانی‌شده جمع کنید

### Ubuntu و Windows Server

در Ubuntu، ‏Datasetهای auth/syslog مربوط به System را فعال و وجود واقعی /var/log/auth.log و /var/log/syslog را بررسی کنید. Image حداقلی ممکن است فقط journald داشته باشد؛ ورودی journald پشتیبانی‌شده یا rsyslog را تنظیم کنید، نه مانیتور فایلی که وجود ندارد. دسترسی خواندن بی‌قید به همه /var/log ندهید. Marker مربوط به logger باید با host.name همان Endpoint و @timestamp جدید دیده شود.

روی Windows Server از بسته تأییدشده Windows x86_64 نسخه 9.5.6 در PowerShell با دسترسی Administrator استفاده کنید. فرمان تولیدشده Fleet را با CA در C:\ProgramData\Elastic\certs\ca.crt اجرا کنید؛ CA خروجی داده نیز باید مسیر Windows داشته باشد یا PEM در Policy قرار گرفته باشد. کانال‌های Application، ‏System و Security از System Integration یا Datasetهای لازم Windows Integration را فعال کنید. خواندن Security به مجوز سرویس و Audit Policy درست نیاز دارد؛ Event 4625 فقط با فعال بودن Audit مربوط تولید می‌شود.

```powershell
Get-Service 'Elastic Agent'
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625} -MaxEvents 5
& 'C:\Program Files\Elastic\Agent\elastic-agent.exe' status
```

### Nginx و Docker

Nginx Integration را به Policy وب‌سرور اضافه و مسیر access/error و فرمت پشتیبانی‌شده را تعیین کنید. فقط اگر روی آن سرور همین مسیرها وجود دارند، با /var/log/nginx/access.log و error.log شروع کنید. یک درخواست کنترل‌شده با Status مشخص بفرستید و همان رویداد را پیدا کنید؛ فرمت سفارشی چندخطی Parsing صریح می‌خواهد. Endpoint مربوط به stub_status برای Metrics اختیاری است و باید داخلی بماند.

برای Docker، ‏Dataset مربوط به container_logs را فعال و دسترسی فایل‌های متناسب با Logging Driver واقعی را فراهم کنید. مسیر پیش‌فرض json-file برابر /var/lib/docker/containers/*/*-json.log است؛ journald یا Driver راه دور، روش جمع‌آوری دیگری لازم دارد. Discovery و Metrics ممکن است Socket محلی Docker را بخواهند؛ حتی Mount با :ro روی docker.sock، ‏API قدرتمندی در دسترس می‌گذارد و دسترسی ساده فایل نیست. Multiline مربوط به Exception را محدود کنید و باقی‌ماندن container.id بعد از Parsing را کنترل کنید.

[Nginx Integration: مسیرها، فرمت و Datasetها](https://www.elastic.co/docs/reference/integrations/nginx)

[Docker Integration: فایل‌ها و نیازمندی Socket](https://www.elastic.co/docs/reference/integrations/docker)

### Cisco، ‏MikroTik و ESXi؛ جمع‌آوری روی Relay

Agent را روی Linux Collector مستقل نصب کنید، نه روی سوئیچ IOS یا ESXi. برای Cisco IOS Integration یک Listener مستقل، مثلاً TCP 9002، با ACL محدود به IP تجهیزات مجاز بدهید. در IOS/IOS XE پشتیبانی‌شده، service timestamps log datetime msec localtime show-timezone و logging host 10.20.30.22 transport tcp port 9002 را تنظیم کنید؛ logging source-interface ثابت و Severity متناسب با نیاز رخداد انتخاب شود. نام Interface و پشتیبانی Transport به انتشار سوئیچ وابسته است. با رخداد Interface کنترل‌شده در پنجره آزمون، لاگ واقعی را بررسی کنید.

برای MikroTik از Remote Logging Action به Listener مستقل Custom UDP Logs، مثلاً پورت 9514، یا Syslog Relay محلی استفاده کنید. این راهنما وجود Parser رسمی اختصاصی MikroTik را فرض نمی‌کند. نمونه زیر روی RouterOS دارای این فیلدها، Topicهای info و warning را می‌فرستد. debug را سراسری فعال نکنید؛ پیام خام را نگه دارید و Parser بازبینی‌شده برای Topic، هویت تجهیز و Timestamp بسازید. UDP نه تأیید تحویل دارد نه TLS؛ آن را در Management Segment یا Tunnel محافظت‌شده نگه دارید و Loss روی Relay را پایش کنید.

```routeros
/system logging action add name=elasticremote target=remote remote=10.20.30.22 remote-port=9514 remote-log-format=syslog
/system logging add topics=info action=elasticremote
/system logging add topics=warning action=elasticremote
/system logging print
/system logging action print detail
```

VMware vSphere Integration، ‏Metrics را از API مربوط به vCenter/ESXi و لاگ را از Syslog Receiver می‌گیرد؛ این دو مسیر جدا هستند. Log Listener را روی Collector فعال و Remote Syslog مربوط به ESXi را برای همان Listener تنظیم کنید؛ Ruleset فایروال Syslog روی ESXi را باز، سرویس را Reload و با ESXCLI پشتیبانی‌شده همان انتشار، پیام تست بفرستید. هویت لاگ vmkernel و hostd را حفظ کنید. کاربر API برای Metrics باید Read-only باشد؛ API Polling به‌تنهایی همه فایل‌های لاگ ESXi را منتقل نمی‌کند. پشتیبانی TLS و CA مورد اعتماد باید برای انتشار دقیق ESXi بررسی شود.

[Cisco IOS Integration و Inputهای پشتیبانی‌شده](https://www.elastic.co/docs/reference/integrations/cisco_ios)

[تنظیم Logging در مستندات RouterOS](https://help.mikrotik.com/docs/spaces/ROS/pages/328094/Log)

[مرجع جاری Logging Action در RouterOS؛ ‏remote-log-format و Transport](https://manual.mikrotik.com/docs/cli-reference/system/logging/action/)

[vSphere Integration: مسیرهای مستقل لاگ و Metrics](https://www.elastic.co/docs/reference/integrations/vsphere)

برای Collectorی که Log Listener مربوط به vSphere روی UDP 514 تنظیم شده، ترتیب ESXCLI زیر آزمون روی Management Segment را نشان می‌دهد. این مسیر رمزگذاری و تضمین تحویل ندارد و فقط باید روی مسیر مدیریت محافظت‌شده باشد؛ اگر سیاست شواهد انتقال رمزگذاری‌شده می‌خواهد، ‏TLS Syslog Relay تأییدشده و اعتماد Certificate در ESXi را پیاده کنید. Syslog Mark باید با هویت ESXi در Collector دیده شود تا جمع‌آوری تأیید شود.

```bash
esxcli system syslog config get
esxcli system syslog config set --loghost='udp://10.20.30.22:514'
esxcli network firewall ruleset set --ruleset-id=syslog --enabled=true
esxcli network firewall refresh
esxcli system syslog reload
esxcli system syslog mark --message='meetaj-esxi-acceptance'
esxcli system syslog config get
```

[Broadcom: ‏Remote Syslog، فایروال و پیام تست در ESXi](https://knowledge.broadcom.com/external/article/318939/configuring-syslog-on-esxi.html)

### SQL Server Audit یک Source نیازمند تنظیم است

از Microsoft SQL Server Integration برای Datasetهای مستند Audit، ‏Error Log و Metrics استفاده کنید؛ transaction_log Metrics را با Backup فایل Transaction Log اشتباه نگیرید. Dataset مربوط به Audit، کانال Windows Event تعریف‌شده را می‌خواند؛ ابتدا SQL Server Audit و Specificationها را با Target مناسب Event Log و مجوز لازم بسازید و فعال کنید. فایل باینری .sqlaudit با مانیتور پوشه به‌عنوان متن، خودکار Parse نمی‌شود. جمع‌آوری Error Log تابع تنظیم فایل همان Package است؛ Package نسخه 2.18.0 رفتار filestream برای UTF-16LE-BOM را مستند کرده است. نسخه Package را ثبت و با Failed Login کنترل‌شده دیتابیس، کانال و فیلدهای واقعی رویداد را تأیید کنید.

[SQL Server Integration: ‏Audit Target، لاگ و مجوزها](https://www.elastic.co/docs/reference/integrations/microsoft_sqlserver)

[Microsoft: معماری و Targetهای SQL Server Audit](https://learn.microsoft.com/en-us/sql/relational-databases/security/auditing/sql-server-audit-database-engine)

## شاهد خام را حفظ و یک نمونه کوچک را نرمال کنید

ECS قرارداد نام و نوع فیلدهاست: host.name هویت Host، ‏source.ip از نوع IP، ‏event.outcome نتیجه موفق/ناموفق و @timestamp زمان رخداد است. ECS، ‏Parser جادویی همه فرمت‌های فروشنده نیست. Grok الگوی متنی معلوم را استخراج می‌کند و Date Parsing باید Timezone صریح داشته باشد. Mapping نوع فیلد را تعیین می‌کند و بعد از ورود داده ناسازگار، به‌سادگی قابل تغییر نیست. پیش از افزایش Throughput، ‏Parser را با رخداد درست، ناموفق و خراب امتحان کنید.

نمونه زیر قرارداد یک برنامه سفارشی است و فرمت پیش‌فرض Cisco یا Nginx نیست: 2026-11-07T09:12:00Z WARN auth-gateway source=192.0.2.15 outcome=failure. REST Exampleها را در Kibana Dev Tools → Console با Role موقت Provisioning اجرا کنید. Data Streamهای Integration مدیریت‌شده Template و Pipeline خودشان را دارند؛ logs-*-* را بازنویسی نکنید و Pipeline مدیریت‌شده را مستقیم تغییر ندهید.

```http
PUT _ingest/pipeline/meetaj-app-v1
{
  "processors": [
    {"set": {"field": "event.original", "copy_from": "message", "override": false}},
    {"grok": {"field": "message", "patterns": ["%{TIMESTAMP_ISO8601:tmp_time} %{LOGLEVEL:log.level} %{NOTSPACE:service.name} source=%{IP:source.ip} outcome=%{WORD:event.outcome}"]}},
    {"date": {"field": "tmp_time", "formats": ["ISO8601"], "target_field": "@timestamp"}},
    {"remove": {"field": "tmp_time"}}
  ],
  "on_failure": [{"set": {"field": "error.message", "value": "{{ _ingest.on_failure_message }}"}}]
}
POST _ingest/pipeline/meetaj-app-v1/_simulate
{"docs":[{"_source":{"message":"2026-11-07T09:12:00Z WARN auth-gateway source=192.0.2.15 outcome=failure"}}]}
```

انتظار داریم source.ip استخراج شود، ‏event.outcome برابر failure باشد و زمان UTC اصلی حفظ شود؛ خط خراب باید event.original را نگه دارد و error.message بگیرد. نمونه، خطاها را برای بررسی در همان Stream حفظ می‌کند؛ در بار زیاد باید برای خطاها Routing یا Alert داشته باشید تا Regression مربوط به Parser پنهان نشود. تاریخ ثابت نمونه عمدی است؛ بازه Discover را متناسب با همان تاریخ انتخاب کنید.

[Ingest Pipeline و شبیه‌سازی پردازش](https://www.elastic.co/docs/manage-data/ingest/transform-enrich/ingest-pipelines)

## Retention سیاست نگهداری است، نه وعده دیسک خالی

![داده Hot پس از Rollover در صورت وجود به Warm می‌رود و سپس حذف می‌شود؛ Snapshot مسیر مستقل دارد](/assets/img/articles/content/elk-stack-enterprise-installation-guide/lifecycle.svg)

Data Stream نامی برای داده Append-oriented است که پشت آن چند Index قرار دارد و @timestamp لازم دارد. Index Template، ‏Mapping، تعداد Shard و ILM Policy را به آن می‌دهد. Primary Shard واحد Indexing و Search است؛ Replica کپی دیگری روی Node متفاوت است. Shard بیشتر سربار دارد و Dataset کوچک را خودکار سریع‌تر نمی‌کند. Rollover را بر اساس اندازه Primary Shard و سن تنظیم و اندازه واقعی و Query Latency را اندازه‌گیری کنید.

Namespace سفارشی زیر ۳۰ روز Retention و یک Primary/یک Replica دارد و روی Streamهای متعلق به Integration اعمال نمی‌شود. Warm Phase عمداً حذف شده چون توپولوژی Production کوچک، Tier مستقل Warm ندارد. پس از ساخت Nodeهای دارای نقش مربوط، ‏Warm Phase را اضافه کنید. سن ILM بعد از Rollover از زمان Rollover محاسبه می‌شود؛ Delete در ۳۰ روز، سازوکار انقضای قانونی دقیق تک‌تک اسناد نیست.

```http
PUT _ilm/policy/meetaj-logs-30d
{
  "policy": {"phases": {
    "hot": {"actions": {"rollover": {"max_primary_shard_size": "30gb", "max_age": "1d"}}},
    "delete": {"min_age": "30d", "actions": {"delete": {}}}
  }}
}
PUT _index_template/meetaj-app-template
{
  "index_patterns": ["logs-meetaj.app-*"],
  "priority": 501,
  "data_stream": {},
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 1,
      "index.lifecycle.name": "meetaj-logs-30d",
      "index.default_pipeline": "meetaj-app-v1"
    },
    "mappings": {"properties": {
      "@timestamp": {"type": "date"},
      "source": {"properties": {"ip": {"type": "ip"}}},
      "event": {"properties": {"outcome": {"type": "keyword"}}},
      "service": {"properties": {"name": {"type": "keyword"}}}
    }}
  }
}
POST logs-meetaj.app-prod/_doc?refresh=wait_for
{"@timestamp":"2026-11-07T09:12:00Z","message":"2026-11-07T09:12:00Z WARN auth-gateway source=192.0.2.15 outcome=failure"}
GET logs-meetaj.app-prod/_ilm/explain
GET _cat/shards/logs-meetaj.app-prod?v
```

### برآورد ذخیره‌سازی برای ۱۰۰ GB در روز

فرض کنیم روزانه ۱۰۰ GB ده‌دهی قبل از Parsing داریم، ضریب اندازه Primary Index پس از اندازه‌گیری 1.2 است، ۳۰ روز داده Searchable می‌خواهیم، یک Replica داریم و هدف مصرف دیسک ۷۵٪ است. ظرفیت Searchable می‌شود 100 × 1.2 × 30 × 2 ÷ 0.75 = 9600 GB، یعنی حدود 9.6 TB ده‌دهی. ضریب 1.2 نتیجه فرضی Pilot است، نه تضمین Elastic؛ بعضی Mappingها بزرگ‌تر و بعضی Datasetها فشرده‌تر می‌شوند. Translog، ‏Merge، تأخیر Rollover، ‏System Index و بازیابی موقت هم فضا مصرف می‌کنند. این عدد ظرفیت قابل استفاده کل Cluster است، نه 9.6 TB برای هر Node.

با ۱۲۰ GB داده Primary در روز و هدف ۳۰ GB برای هر Primary Shard، در مجموع Dataset حدود چهار Primary Shard روزانه لازم می‌شود؛ زمان Rollover و تفکیک Sourceها تعداد واقعی را تغییر می‌دهد. Stream دارای یک Primary با این بار در روز چند بار Rollover می‌شود. در سه Data Node هم‌ظرفیت، برای تحمل خرابی یکی و حفظ هدف مصرف ۷۵٪ روی دو Node باقی‌مانده، حدود 14.4 TB ظرفیت قابل استفاده قبل از خرابی لازم است، چون فقط دوسوم ظرفیت می‌ماند. Snapshot Repository را جدا حساب کنید؛ Snapshot افزایشی است و اندازه آن به Segmentهای تغییرکرده و Retention وابسته است، نه ضرب ساده کل Dataset در تعداد Snapshotها.

[Elastic: اندازه Shard و راهنمای Rollover](https://www.elastic.co/docs/deploy-manage/production-guidance/optimize-performance/size-shards)

[Elastic: ‏Index Lifecycle Management](https://www.elastic.co/docs/manage-data/lifecycle/index-lifecycle-management)

## Logstash را برای Buffer یا Routing مشخص اضافه کنید

ممکن است Relay محلی، خط‌های نرمال‌شده برنامه را در /var/log/meetaj/app.log بنویسد. Pipeline اختیاری زیر فقط همان فایل را می‌خواند، از Ingest Pipeline سفارشی بالا استفاده و در Data Stream سفارشی می‌نویسد. مجوز فایل و Rotation روی Relay باید قبلاً تنظیم شده باشد. این مسیر برای Streamهای مدیریت‌شده Fleet نیست؛ Dataset و Pipeline آن‌ها باید حفظ شود. در /etc/logstash/logstash.yml، ‏queue.type: persisted و بودجه دیسک، مثلاً queue.max_bytes: 8gb بگذارید؛ Persistent Queue قطعی محدود را Buffer می‌کند، اما جای دوام Source یا HA را نمی‌گیرد.

```ruby
input {
  file {
    path => ["/var/log/meetaj/app.log"]
    start_position => "beginning"
    sincedb_path => "/var/lib/logstash/meetaj-app.sincedb"
  }
}
output {
  elasticsearch {
    hosts => ["https://es01.logs.example.net:9200", "https://es02.logs.example.net:9200"]
    ssl_certificate_authorities => ["/etc/logstash/certs/ca.crt"]
    api_key => "${ES_API_KEY}"
    ecs_compatibility => "v8"
    data_stream => true
    data_stream_type => "logs"
    data_stream_dataset => "meetaj.app"
    data_stream_namespace => "prod"
    pipeline => "meetaj-app-v1"
    manage_template => false
    ilm_enabled => false
  }
}
```

آن را در /etc/logstash/conf.d/meetaj-app.conf ذخیره کنید. Template و Pipeline را جدا با Role مدیریتی Provision کنید. API Key مربوط به Logstash به create_doc برای logs-meetaj.app-* محدود شود و فقط اگر لازم است Stream بسازد، ‏auto_configure بگیرد؛ Cluster Privilege نیز فقط در حد Checkهای لازم Output Plugin همان نسخه باشد. مقدار id:api_key را تعاملی در Logstash Keystore بگذارید، نه در فایل .conf. سرویس Logstash نباید manage_security یا امکان خواندن Indexهای نامرتبط داشته باشد.

```bash
sudo /usr/share/logstash/bin/logstash-keystore --path.settings /etc/logstash create
sudo /usr/share/logstash/bin/logstash-keystore --path.settings /etc/logstash add ES_API_KEY
sudo chown logstash:root /etc/logstash/logstash.keystore
sudo chmod 0600 /etc/logstash/logstash.keystore
sudo -u logstash /usr/share/logstash/bin/logstash --path.settings /etc/logstash --config.test_and_exit
sudo systemctl enable --now logstash
sudo journalctl -u logstash -n 80 --no-pager
```

فرمان اعتبارسنجی باید معتبر بودن Configuration را اعلام کند؛ این Check نحو است، نه دسترسی و Parsing سرتاسری. یک خط نمونه تأییدشده اضافه کنید، سندش را پیدا کنید، ‏Logstash را Restart و جلوگیری Checkpoint فایل از Replay تکراری را کنترل کنید. start_position فقط در نبود Checkpoint قبلی sincedb اثر دارد. رشد صف و تأخیر قدیمی‌ترین رویداد را پایش کنید؛ صفی که همیشه بزرگ‌تر می‌شود مشکل ظرفیت دارد.

[Logstash Elasticsearch Output: ‏TLS، ‏API Key و Data Stream](https://www.elastic.co/docs/reference/logstash/plugins/plugins-outputs-elasticsearch)

[Persistent Queue در Logstash و محدودیت دوام](https://www.elastic.co/docs/reference/logstash/persistent-queues)

## داشبوردی بسازید که نبود داده را هم نشان دهد

در Discover یک Data View برای logs-* با فیلد زمانی @timestamp بسازید و سپس با Dataset محدودش کنید. برای نمونه ثابت بالا، بازه ۷ نوامبر ۲۰۲۶ UTC را انتخاب کنید. برای Source زنده بازه اخیر را بگذارید و اگر Integration فیلد event.ingested دارد، آن را با @timestamp مقایسه کنید. نمودار صفر خطا بین برنامه سالم و Collector متوقف تفاوتی نمی‌بیند. تعداد رویداد به تفکیک Host، ‏Last Seen و خطای Parsing را کنار خطای سرویس نمایش دهید.

```kql
data_stream.dataset : "system.auth" and event.outcome : "failure"
data_stream.dataset : "nginx.access" and http.response.status_code >= 500
data_stream.dataset : "meetaj.app" and error.message : *
host.name : "web01" and @timestamp >= now-15m
```

این‌ها چهار فیلتر مستقل KQL هستند، نه یک Query چندخطی. قبل از استفاده از فیلتر اول، فیلد ECS رویداد دریافتی را بررسی کنید؛ همه Integrationها هر نوع خطا را یکسان دسته‌بندی نمی‌کنند. در Lens تعداد Status Codeهای Nginx را در بازه پنج دقیقه رسم کنید، جدول host.name پرتکرار را اضافه و در Dashboard عملیات ذخیره کنید. Rule کاربردی می‌تواند بیش از ۲۰ رویداد HTTP 5xx برای یک Host طی پنج دقیقه باشد، هر دقیقه ارزیابی شود و Look-back آن از تأخیر قابل انتظار Ingest بلندتر باشد. عدد را با ترافیک و پنجره نگهداری تنظیم کنید.

برای Hostهای فعال مورد انتظار، ‏Rule مستقل نبود داده بسازید؛ Grouping روی host.name باشد و معنی سکوت برای سرور کم‌ترافیک تعریف شود. آزمون Alert کنترل‌شده و پیام Recovery آن را ثبت کنید. Connector و Rule Type به Subscription وابسته‌اند؛ از Connector موجود در مجوز واقعی استفاده کنید و هر Email، ‏Webhook یا ML Rule را Basic فرض نکنید. Log Management به‌تنهایی مالک Triage، پوشش Detection و پاسخ به رخداد SOC ایجاد نمی‌کند.

[اتصال داشبوردهای Metrics به مسیر بررسی لاگ](/articles/grafana-installation-zabbix-integration)

[راهنمای Zabbix؛ پایش Host در کنار جمع‌آوری رویداد](/articles/zabbix-server-linux-windows-agents-backup)

## نقش‌ها را بعد از اندازه‌گیری رقابت منابع جدا کنید

![نقش‌های سازمانی؛ سه Master، داده Hot/Content، ‏Warm و Ingest اختیاری، ‏Kibana و Fleet افزونه و Snapshot مستقل](/assets/img/articles/content/elk-stack-enterprise-installation-guide/production.svg)

در Cluster بزرگ‌تر، وظیفه Master را روی سه Node با node.roles: [master] جدا کنید. Data Nodeها نقش‌های data_hot و data_content یا نقش عمومی data می‌خواهند؛ data_warm فقط برای Pool واقعی Warm اضافه شود. اگر Ingest را از همه Data Nodeها حذف و Masterها را Master-only کنید، حداقل یک Ingest Node جدا برای Pipeline لازم می‌شود؛ برای دسترس‌پذیری دو عدد در نظر بگیرید. Query معمول کلاینت را به Master مستقل نفرستید. سه Master-eligible Node برای Election و انتشار Cluster State به اکثریت دو عضو نیاز دارند؛ دو Master همان تحمل خرابی تک‌عضوی را ندارند.

دو Kibana را پشت HTTPS Load Balancer دارای Health Check قرار دهید؛ Encryption Keyهای لازم یکسان و هویت سرورها مستقل باشد و Elasticsearch Endpointها را توزیع کنید. دو Fleet Server در Failure Domain جدا بسازید و Host List پشتیبانی‌شده یا Endpoint دارای Health Check معرفی کنید. Agent موجود معمولاً در قطعی مدیریت Fleet با آخرین Policy به جمع‌آوری ادامه می‌دهد، اما Policy جدید نمی‌گیرد و Host جدید Enrollment نمی‌شود. خرابی Control Plane و Data Plane را جدا آزمایش کنید.

یک Cluster را بدون طراحی روی WAN پر‌تأخیر نکشید. برای قطعی شعبه، ‏Relay دارای دوام یا Collector با ظرفیت کافی کنار Source بگذارید، Buffer را با اوج Byte/sec × مدت قطعی قابل تحمل حساب و قدیمی‌ترین رویداد صف را مانیتور کنید. Clusterهای منطقه‌ای با Snapshot و طراحی بازبینی‌شده Remote Search ممکن است از Quorum جغرافیایی شکننده مناسب‌تر باشند. Cross-cluster Replication و Searchable Snapshot شرایط Subscription دارند؛ وجودشان در نمودار مجوز استفاده نمی‌دهد.

[نقش‌های Node و Data Roleهای ضروری](https://www.elastic.co/docs/reference/elasticsearch/configuration-reference/node-settings)

در تفکیک نقش سازمانی ظرفیت transform را حفظ کنید؛ Fleet و جریان‌های مربوط به Elastic Security به این Role نیاز دارند. نصب ترکیبی بالا آن را دارد؛ هنگام تفکیک، روی Data Node مناسب نگه دارید یا Pool مستقل Transform بسازید. نقش‌های ml یا remote_cluster_client هم بر اساس قابلیت فعال تعیین می‌شوند، نه با حذف یک‌جای Defaultها.

## پیش از اتکا به Replica، ‏Restore را ثابت کنید

Replica برای دسترس‌پذیری است؛ حذف داده، تغییر اشتباه یا دسترسی سرقت‌شده می‌تواند هر دو کپی را تحت تأثیر قرار دهد. Snapshot روش پشتیبانی‌شده Backup داده Elasticsearch است؛ کپی Data Directory زنده یا Snapshot مستقل VMها، ‏Backup پشتیبانی‌شده Cluster نیست. Repository از نوع Object Storage مستقل یا Shared File System درست‌پیاده‌شده با Failure Domain جدا و Credential محدود انتخاب کنید.

برای نمونه File System زیر، مسیر مشترک /mnt/elastic-snapshots را روی همه Master/Data Nodeها Mount کنید، دسترسی UID/GID مربوط به Elasticsearch و File Locking درست فراهم شود، سپس path.repo: ["/mnt/elastic-snapshots"] را به YAML آن‌ها اضافه و Rolling Restart کنترل‌شده انجام دهید. این مسیر واقعاً Mount مشترک است، نه چند پوشه محلی بی‌ارتباط. فقط یک Cluster در Repository می‌نویسد؛ Cluster بازیابی آن را Read-only ثبت می‌کند.

```http
PUT _snapshot/meetaj_backup
{"type":"fs","settings":{"location":"/mnt/elastic-snapshots","compress":true}}
POST _snapshot/meetaj_backup/_verify
PUT _slm/policy/meetaj-nightly
{
  "schedule":"0 30 1 * * ?",
  "name":"<meetaj-{now/d}>",
  "repository":"meetaj_backup",
  "config":{"indices":["logs-*"],"include_global_state":true},
  "retention":{"expire_after":"30d","min_count":3,"max_count":40}
}
POST _slm/policy/meetaj-nightly/_execute
GET _slm/stats
GET _snapshot/meetaj_backup/_all
```

Cron ساعت 01:30 UTC است، نه ساعت محلی مرورگر. Verify باید Nodeهای قابل دسترسی Repository را نشان دهد و Snapshot تکمیل‌شده باید SUCCESS با صفر Failed Shard داشته باشد. پوشش Feature State برای System Data موردنیاز را بررسی کنید؛ include_global_state، ‏YAML هر Node، ‏Keystore یا PKI بیرونی را Backup نمی‌گیرد. تنظیم سرویس، نسخه Integrationها، روش بازیابی Enrollment و Encryption Keyها را جدا نگهداری کنید. برای سن آخرین Snapshot و خطای Backup، ‏Alert بسازید.

```http
POST _snapshot/meetaj_backup/REPLACE_WITH_COMPLETED_SNAPSHOT/_restore
{
  "indices":"logs-meetaj.app-prod",
  "include_global_state":false,
  "rename_pattern":"(.+)",
  "rename_replacement":"restored-$1"
}
GET _cat/recovery/restored-*?v
GET restored-logs-meetaj.app-prod/_count
```

Restore را فقط در Cluster بازیابی ایزوله و سازگار، با Template لازم برای Data Stream بازیابی‌شده و فضای کافی اجرا کنید و Placeholder نام Snapshot را عوض کنید. منتظر Recovery بمانید، Marker شناخته‌شده را جست‌وجو و Count و پوشش زمانی را با پرونده تحویل مقایسه کنید. Green بودن به‌تنهایی ثابت نمی‌کند داده درست برگشته است. RPO/RTO اندازه‌گیری‌شده را ثبت کنید؛ Snapshot صرفاً شبانه ممکن است نزدیک یک روز از دست رفتن داده بدهد.

[Elastic: ‏Snapshot/Restore پشتیبانی‌شده و پوشش Feature State](https://www.elastic.co/docs/deploy-manage/tools/snapshot-and-restore)

[Elastic: نیازمندی Shared File System Repository](https://www.elastic.co/docs/deploy-manage/tools/snapshot-and-restore/shared-file-system-repository)

[طراحی مستقل HA، ‏Backup و Disaster Recovery](/articles/high-availability-backup-disaster-recovery-enterprise-guide)

## از شاهد به اصلاح محدود برسید

فرمان‌های زیر شاهد مورد انتظار را توضیح می‌دهند و خروجی اجرای ثبت‌شده نیستند. درخواست REST را در Kibana Console اجرا کنید، مگر آنکه فرمان Shell آمده باشد. بازه زمانی، ‏Source مشکل‌دار و آخرین رویداد سالم را کنار هر رخداد ثبت کنید. برای سبزکردن Status، ‏Index حذف نکنید، ‏Stale Primary را Force نکنید و TLS Verification را برندارید.

### سرویس Elasticsearch Start نمی‌شود

```bash
sudo systemctl status elasticsearch --no-pager
sudo journalctl -u elasticsearch -b -n 120 --no-pager
sudo tail -n 100 /var/log/elasticsearch/meetaj-logs-prod.log
systemctl show elasticsearch -p LimitNOFILE
sysctl vm.max_map_count
```

Unit ناموفق و اولین Exception مربوط به Configuration یا Bootstrap باید کلید YAML اشتباه، Certificate ناخوانا، Limit کم یا Mount خراب را مشخص کنند. همان خطا را اصلاح، مالک فایل یا Mount را درست و سپس Restart کنید؛ active بودن Unit و حفظ cluster UUID را بررسی کنید. journalctl ممکن است فقط زمینه Start را نشان دهد؛ لاگ خود برنامه ضروری است.

### Cluster زرد شده است

```http
GET _cluster/health
GET _cat/shards?v
GET _cluster/allocation/explain
```

Yellow یعنی Primaryها تخصیص دارند ولی حداقل یک Replica ندارد. در ردیف Replica انتظار UNASSIGNED داریم؛ Allocation Explain کمبود Node، ‏Tier Filter یا Disk Limit را جدا می‌کند. ظرفیت را برگردانید یا Policy جای‌گذاری را اصلاح کنید و تخصیص Replicaها را تأیید کنید. صفرکردن Replica عملیاتی مشکل دسترس‌پذیری را پنهان می‌کند.

### Cluster قرمز شده است

```http
GET _cluster/health
GET _cat/shards?v
POST _cluster/allocation/explain
{"index":"REPLACE_WITH_AFFECTED_INDEX","shard":0,"primary":true}
```

Red یعنی Primary تخصیص‌نیافته و دسترسی ناقص داده. تصمیم تخصیص Shard واقعی را بخوانید؛ نام Index و شماره Shard هر دو باید درست باشند. در صورت ایمنی، ‏Node/Storage اصلی را برگردانید یا Snapshot معتبر Restore کنید. نبود کپی معتبر یعنی احتمال از دست رفتن داده و نیاز به تصمیم صریح بازیابی؛ Force کردن Stale Primary می‌تواند Write تأییدشده را از بین ببرد. پس از Recovery پوشش زمانی داده را بررسی کنید.

### Shard تخصیص نمی‌گیرد

```http
GET _cat/allocation?v
GET _cluster/settings?include_defaults=true&flat_settings=true
GET _cluster/allocation/explain
```

نام Decider و دلیل NO/THROTTLE را انتظار داریم. Filter مربوط به Warm بدون Warm Node، ‏Awareness Constraint و Recovery Throttle درمان متفاوتی با پرشدن دیسک دارند. علت مشخص را اصلاح و منتظر Recovery بمانید؛ همه Routing Settingها را پاک نکنید. STARTED شدن و Placement در Failure Domain درست را تأیید کنید.

### Disk Watermark رد شده است

```http
GET _cat/allocation?v
GET _cluster/settings?include_defaults=true&flat_settings=true
GET logs-*/_settings/index.blocks.read_only_allow_delete
```

disk.percent بالا یا Read-only Block ناشی از Flood Stage را انتظار داریم. مصرف فایل‌سیستم Host مشکل‌دار را کنترل کنید؛ Storage را افزایش دهید یا پس از کنترل Backup/Retention، داده را از فرایند مصوب Retention حذف کنید. بالا‌بردن Watermark راه عقب‌انداختن دیسک پُر نیست. بعد از پایین‌آمدن مصرف از High Watermark مربوط، ‏Flood-stage Block معمولاً خودکار برداشته می‌شود؛ ورود رویداد آزمایشی جدید را تأیید کنید.

### Kibana به Elasticsearch وصل نمی‌شود

```bash
sudo journalctl -u kibana -n 120 --no-pager
getent hosts es01.logs.example.net
curl --cacert /etc/kibana/certs/ca.crt -I https://es01.logs.example.net:9200/
```

پاسخ 401 به curl بدون Credential، دسترسی HTTP/TLS را ثابت می‌کند، نه رمز Kibana را. Timeout به Route/Firewall، خطای TLS به Trust/SAN و 401 در لاگ Kibana به Service Password یا Keystore اشاره دارد. لایه مربوط را اصلاح کنید، در صورت تغییر Secure Setting سرویس را Restart و ورود همراه Query واقعی Discover را بررسی کنید.

### لاگ وارد نمی‌شود

```text
sudo elastic-agent status
sudo elastic-agent diagnostics
ss -lntup
GET logs-*/_search
{"size":1,"sort":[{"@timestamp":"desc"}],"query":{"term":{"host.name":"REPLACE_WITH_HOST"}}}
```

سه فرمان اول Shell و GET/Body مربوط به Console هستند. انتظار داریم Unit مربوط به Integration سالم، Listener تنظیم‌شده روی Collector فعال و سند جدید موجود باشد. Agent سالم بدون سند ممکن است مسیر فایل اشتباه، فایل Rotateشده ناخوانا، ‏Audit Policy غایب، رد Parsing یا خطای Output/API Key داشته باشد. یک مسیر را اصلاح و Marker یکتا بفرستید و سرتاسری بررسی کنید. Diagnostics Archive ممکن است Secret داشته باشد و باید محدود بماند.

### خطای TLS یا Certificate

```bash
openssl s_client -connect es01.logs.example.net:9200 -servername es01.logs.example.net -CAfile ./ca.crt -verify_return_error </dev/null
openssl x509 -in ./node.crt -noout -dates -ext subjectAltName
```

اعتبار Chain موفق و SAN منطبق با DNS درخواستی را انتظار داریم. Unknown Authority یعنی Chain صادرکننده درست موجود نیست؛ تاریخ منقضی یا Name Mismatch نیاز به تمدید/صدور مجدد دارد، نه verification_mode: none. Chain عمومی درست را توزیع، ‏Certificate سرویس را از مسیر Reload/Restart پشتیبانی‌شده Rotate و همان ارتباط دارای Verification را تکرار کنید.

### خطای احراز هویت یا مجوز

```http
GET _security/_authenticate
GET _security/user/_privileges
```

Principal موردنظر و فقط مجوزهای لازم را انتظار داریم. HTTP 401 به Credential نامعتبر/منقضی یا Realm اشتباه و 403 به Principal احراز‌شده فاقد مجوز Action اشاره دارد. Credential را با Role محدود Rotate/بازصادر، ‏Secure Store را به‌روز و همان Action ناموفق Ingest/Search را تأیید کنید. Superuser راه‌حل دائمی نیست.

### فشار پایدار JVM Heap

```http
GET _nodes/stats/jvm,breaker
GET _nodes/hot_threads
GET _cat/nodes?v&h=name,heap.percent,ram.percent,cpu,load_1m
```

Heap با الگوی دندانه‌اره‌ای کوتاه طبیعی است؛ فشار پایدار همراه GC مکرر Old Generation، ‏Circuit Breaker یا رشد صف طبیعی نیست. Aggregation پرهزینه، تعداد Shard و Burst ورود داده را با منابع Node مقایسه کنید. گستره Query یا Cardinality فیلد را کم، ‏Shardها را متعادل و بر اساس شاهد ظرفیت اضافه کنید. افزایش Heap ممکن است Cache فایل‌سیستم را کم و تأخیر را بدتر کند. کاهش فشار پایدار را زیر همان بار نماینده تأیید کنید.

### جست‌وجوی کند

```http
GET _nodes/stats/thread_pool,indices
GET _tasks?detailed=true&actions=*search
GET _cat/shards?v&s=store:desc
```

به دنبال Search Queue/Reject، ‏Task طولانی یا Shard Size نامتوازن باشید؛ هیچ‌کدام به‌تنهایی علت قطعی نیستند. بازه زمانی را محدود، ‏Query واقعی را بخوانید و Profile را روی نمونه کنترل‌شده بگیرید چون سربار دارد. بر اساس شاهد، ‏Wildcard سنگین، ‏Shard اضافی یا Storage اشباع را اصلاح کنید. همان Query را قبل و بعد با کنترل کامل‌بودن داده و هم‌زمانی Ingest مقایسه کنید.

[Elastic: تشخیص Red/Yellow و تخصیص Shard](https://www.elastic.co/docs/troubleshoot/elasticsearch/red-yellow-cluster-status)

[Elastic: ‏Disk Watermark و Read-only Block](https://www.elastic.co/docs/troubleshoot/elasticsearch/fix-watermark-errors)

## قبل از تحویل به عملیات چه چیزی باید درست باشد؟

| کنترل | شاهد پذیرش |
| --- | --- |
| فهرست نسخه و تنظیمات | نسخه دقیق بسته/Integration، تنظیم بازبینی‌شده، ماتریس پشتیبانی و مسئول مشخص |
| امنیت | TLS معتبر در هر Hop، پایش SAN/انقضا، پورت محدود، ‏User/API Key کم‌اختیار و Rotation |
| جمع‌آوری و Parsing | Marker قابل پیگیری از هر Source، زمان و Host و فیلد درست، رفتار معلوم خط خراب |
| دسترس‌پذیری | آزمون کنترل‌شده خروج یک Node واجد شرایط و Collector با فضای کافی Recovery |
| Retention و ظرفیت | رشد واقعی Primary/Replica، ‏ILM Explain، ‏Rollover و Retention مصوب؛ آستانه Alert فضای ذخیره‌سازی |
| بازیابی | Snapshot مستقل تکمیل‌شده، آزمون Restore/Search ایزوله، ‏RPO/RTO اندازه‌گیری‌شده و تنظیم/کلید امن |
| مانیتورینگ و تحویل | Alert با مسئول و مسیر Escalation برای Last Seen، تأخیر Ingest، خطای Parse، ‏JVM، دیسک، Cluster و Snapshot |

پیش از Upgrade، ‏Snapshot سازگار بگیرید و اعتبارش را کنترل کنید، تنظیم و Secure Setting را Backup بگیرید، پیش‌نیازهای Upgrade همان انتشار را بخوانید و Integration/Search را روی نسخه Staging نماینده امتحان کنید. Hold بسته‌ها فقط داخل Change برنامه‌ریزی‌شده برداشته شود. Elasticsearch، ‏Downgrade درجا روی Data Directory را پشتیبانی نمی‌کند؛ Rollback یعنی Restore کردن Snapshot سازگار پیش از Upgrade در Cluster مستقل سازگار و هدایت Clientها به آن، با تصمیم روشن درباره Writeهای پذیرفته‌شده بعد از آن Snapshot. Endpoint قبلی و برنامه Buffering را تا پایان پذیرش حفظ کنید.

[Elastic: ‏Upgrade پشتیبانی‌شده و محدودیت Rollback](https://www.elastic.co/docs/deploy-manage/upgrade/deployment-or-cluster/elasticsearch)

[پیش از انتخاب پلتفرم، مدل عملیاتی Elastic و Splunk را مقایسه کنید](/articles/elk-stack-vs-splunk-enterprise)

[راه‌اندازی Splunk Enterprise و مدل جایگزین جمع‌آوری و عملیات](/articles/splunk-enterprise-installation-guide)

## پرسش‌هایی که طراحی را تغییر می‌دهند

### آیا Logstash اجباری است؟

خیر. Elastic Agent می‌تواند داده Integration را مستقیم به Elasticsearch بفرستد و از Ingest Pipeline استفاده کند. Logstash را برای نیاز مشخص تبدیل، Routing یا Buffer اضافه کنید.

### Replica جای Backup را می‌گیرد؟

خیر. Replica دسترس‌پذیری را بهتر می‌کند ولی حذف منطقی و خرابی را هم دنبال می‌کند. Snapshot Repository مستقل و آزمون Restore لازم است.

### این نصب یک SIEM کامل می‌سازد؟

این نصب بستر لاگ امن می‌سازد. Elastic Security جریان‌های امنیتی اضافه می‌کند، اما پوشش Source، ‏Detection تنظیم‌شده، قابلیت دارای مجوز و فرایند پاسخ به رخداد باید جدا پیاده شوند.

[نسخه Markdown فارسی](/downloads/elk-stack-enterprise-installation-guide/article.fa.md)

[نسخه Markdown انگلیسی](/downloads/elk-stack-enterprise-installation-guide/article.en.md)
