نحوه نوشتن پلاگین اختصاصی Traefik برای فایل robots.txt
فرض کنید که در ترافیک سرویس داریم که روی دامنه یا زیر دامنه ای فعال است و کار ریورس پروکسی را انجام می دهد و نمی خواهیم دسترسی ربات ها برای کراول این سرویس را ببندیم. از طرفی امکان ایجاد فایل robots.txt در سرویس مورد نظر را هم نداریم تا بتوانیم فایل مورد نظر را در خود سرویس ایجاد کرده و سرو کنیم.
راه حل اول برای این کار استفاده از یک سرویس مجزا برای سرو کردن فایل robots.txt است. کد زیر بخشی از داکر کامپوز مربوط به سرویس سرو فایل های استاتیک است که بوسیله NGinx انجام میشود و اگر درخواستی برای فایل robots.txt بیاید، فایل robots.txt درون فولدر static را باز می گرداند.
services:
static-file-service:
image: nginx:alpine
volumes:
- ./static:/usr/share/nginx/html
labels:
- "traefik.enable=true"
- "traefik.http.routers.static-file.rule=Path(`/robots.txt`)"
- "traefik.http.services.static-file.loadbalancer.server.port=80"
networks:
- web
networks:
web:
driver: bridge
راه حل دوم برای رفع این مشکل نوشتن یک پلاگین اختصاصی برای ترافیک است تا بدون راه انداختن سرویس مجزا این کار را انجام دهیم:
فولدری به اسم staticcontentplugin درست می کنیم و فایل های staticcontentplugin.go، go.mod و .traefik.yml را درون آن ایجاد می کنیم. نکته مهم نام ماژول است که می توانید از نام دلخواه خود استفاده کنید: github.com/smohsenm/staticcontentplugin. در مثال ما نام کاربری گیت هاب smohsenm و پروژه staticcontentplugin است ولی نیازی به درست کردن پروژه گیت هاب نمی باشد و نام فرضی است.
فایل .traefik.yml را مطابق زیر ایجاد می کنیم:
# The name of your plugin as displayed in the Plugins Catalog web UI.
displayName: Name of your plugin
# For now, `middleware` is the only type available.
type: middleware
# The import path of your plugin.
import: github.com/smohsenm/staticcontentplugin
# A brief description of what your plugin is doing.
summary: Description of what my plugin is doing
# Medias associated to the plugin (optional)
iconPath: foo/icon.png
bannerPath: foo/banner.png
# Configuration data for your plugin.
# This is mandatory,
# and Plugins Catalog will try to execute the plugin with the data you provide as part of its startup validity tests.
testData:
Headers:
Foo: Bar
فایل go.mod:
module github.com/smohsenm/staticcontentplugin
go 1.23.0
فایل staticcontentplugin.go:
package staticcontentplugin
import (
"context"
"fmt"
"net/http"
)
// Config holds the plugin configuration.
type Config struct {
Content string `json:"content"`
StatusCode int `json:"statusCode"`
ContentType string `json:"contentType"`
}
// CreateConfig creates the default plugin configuration.
func CreateConfig() *Config {
return &Config{
Content: "",
StatusCode: 200,
ContentType: "text/plain", // Default content type
}
}
// StaticContentPlugin is a struct that holds the middleware instance.
type StaticContentPlugin struct {
next http.Handler
content string
statusCode int
contentType string
name string
}
// New creates a new StaticContentPlugin middleware.
func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error) {
if config.Content == "" {
return nil, fmt.Errorf("content cannot be empty")
}
if config.StatusCode < 100 || config.StatusCode > 599 {
return nil, fmt.Errorf("invalid statusCode: must be between 100 and 599")
}
if config.ContentType == "" {
config.ContentType = "text/plain" // Ensure a default value is set
}
return &StaticContentPlugin{
next: next,
content: config.Content,
statusCode: config.StatusCode,
contentType: config.ContentType,
name: name,
}, nil
}
func (s *StaticContentPlugin) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// Set the content type
rw.Header().Set("Content-Type", s.contentType)
// Write the custom status code and content
rw.WriteHeader(s.statusCode)
rw.Write([]byte(s.content))
}
حال برای فعال کردن پلاگین باید کد زیر را به تنظیمات Traefik اضافه کنیم:
experimental:
localPlugins:
staticcontentplugin:
moduleName: github.com/smohsenm/staticcontentplugin
در نهایت باید مسیر و سرویس مورد نظر را به فایل تنظیمات اضافه کنیم:
http:
routers:
robots-router:
rule: "Host(`test.example.com`) && PathPrefix(`/robots.txt`)"
entryPoints:
- web
service: reverse-proxy-service
middlewares:
- "robots-middleware"
middlewares:
robots-middleware:
plugin:
staticcontentplugin:
content: "User-agent: *\nDisallow: /"
statusCode: 200
contentType: "text/plain"
در نهایت باید ترافیک را ری استارت کنیم:
docker compose down
docker compose up -d