config.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. package config
  2. import (
  3. "errors"
  4. "flag"
  5. "fmt"
  6. "log/slog"
  7. "math"
  8. "os"
  9. "regexp"
  10. "runtime"
  11. "strings"
  12. "github.com/imgproxy/imgproxy/v3/config/configurators"
  13. "github.com/imgproxy/imgproxy/v3/imagetype"
  14. "github.com/imgproxy/imgproxy/v3/version"
  15. )
  16. func init() {
  17. // We need to reset config to defaults once on app start.
  18. // Tests could perform config.Reset() to ensure a clean state where required.
  19. // NOTE: this is temporary workaround until we finally move
  20. // to Config objects everywhere
  21. Reset()
  22. }
  23. type URLReplacement = configurators.URLReplacement
  24. var (
  25. Network string
  26. Bind string
  27. Timeout int
  28. GracefulStopTimeout int
  29. ReadRequestTimeout int
  30. WriteResponseTimeout int
  31. KeepAliveTimeout int
  32. ClientKeepAliveTimeout int
  33. DownloadTimeout int
  34. Workers int
  35. RequestsQueueSize int
  36. MaxClients int
  37. TTL int
  38. CacheControlPassthrough bool
  39. SetCanonicalHeader bool
  40. SoReuseport bool
  41. PathPrefix string
  42. MaxSrcResolution int
  43. MaxSrcFileSize int
  44. MaxAnimationFrames int
  45. MaxAnimationFrameResolution int
  46. MaxSvgCheckBytes int
  47. MaxRedirects int
  48. PngUnlimited bool
  49. SvgUnlimited bool
  50. MaxResultDimension int
  51. AllowedProcessingOptions []string
  52. AllowSecurityOptions bool
  53. JpegProgressive bool
  54. PngInterlaced bool
  55. PngQuantize bool
  56. PngQuantizationColors int
  57. AvifSpeed int
  58. JxlEffort int
  59. WebpEffort int
  60. WebpPreset string
  61. Quality int
  62. FormatQuality map[imagetype.Type]int
  63. StripMetadata bool
  64. KeepCopyright bool
  65. StripColorProfile bool
  66. AutoRotate bool
  67. EnforceThumbnail bool
  68. ReturnAttachment bool
  69. AutoWebp bool
  70. EnforceWebp bool
  71. AutoAvif bool
  72. EnforceAvif bool
  73. AutoJxl bool
  74. EnforceJxl bool
  75. EnableClientHints bool
  76. PreferredFormats []imagetype.Type
  77. SkipProcessingFormats []imagetype.Type
  78. UseLinearColorspace bool
  79. DisableShrinkOnLoad bool
  80. Keys [][]byte
  81. Salts [][]byte
  82. SignatureSize int
  83. TrustedSignatures []string
  84. Secret string
  85. AllowOrigin string
  86. UserAgent string
  87. IgnoreSslVerification bool
  88. DevelopmentErrorsMode bool
  89. AllowedSources []*regexp.Regexp
  90. AllowLoopbackSourceAddresses bool
  91. AllowLinkLocalSourceAddresses bool
  92. AllowPrivateSourceAddresses bool
  93. SanitizeSvg bool
  94. AlwaysRasterizeSvg bool
  95. CookiePassthrough bool
  96. CookieBaseURL string
  97. CookiePassthroughAll bool
  98. SourceURLQuerySeparator string
  99. LocalFileSystemRoot string
  100. S3Enabled bool
  101. S3Region string
  102. S3Endpoint string
  103. S3EndpointUsePathStyle bool
  104. S3AssumeRoleArn string
  105. S3AssumeRoleExternalID string
  106. S3DecryptionClientEnabled bool
  107. GCSEnabled bool
  108. GCSKey string
  109. GCSEndpoint string
  110. ABSEnabled bool
  111. ABSName string
  112. ABSKey string
  113. ABSEndpoint string
  114. SwiftEnabled bool
  115. SwiftUsername string
  116. SwiftAPIKey string
  117. SwiftAuthURL string
  118. SwiftDomain string
  119. SwiftTenant string
  120. SwiftAuthVersion int
  121. SwiftConnectTimeoutSeconds int
  122. SwiftTimeoutSeconds int
  123. ETagEnabled bool
  124. ETagBuster string
  125. LastModifiedEnabled bool
  126. BaseURL string
  127. URLReplacements []URLReplacement
  128. Base64URLIncludesFilename bool
  129. Presets []string
  130. OnlyPresets bool
  131. WatermarkData string
  132. WatermarkPath string
  133. WatermarkURL string
  134. WatermarkOpacity float64
  135. FallbackImageData string
  136. FallbackImagePath string
  137. FallbackImageURL string
  138. FallbackImageHTTPCode int
  139. FallbackImageTTL int
  140. DataDogEnable bool
  141. DataDogEnableMetrics bool
  142. NewRelicAppName string
  143. NewRelicKey string
  144. NewRelicLabels map[string]string
  145. PrometheusBind string
  146. PrometheusNamespace string
  147. OpenTelemetryEnable bool
  148. OpenTelemetryEnableMetrics bool
  149. OpenTelemetryServerCert string
  150. OpenTelemetryClientCert string
  151. OpenTelemetryClientKey string
  152. OpenTelemetryTraceIDGenerator string
  153. CloudWatchServiceName string
  154. CloudWatchNamespace string
  155. CloudWatchRegion string
  156. BugsnagKey string
  157. BugsnagStage string
  158. HoneybadgerKey string
  159. HoneybadgerEnv string
  160. SentryDSN string
  161. SentryEnvironment string
  162. SentryRelease string
  163. AirbrakeProjectID int
  164. AirbrakeProjectKey string
  165. AirbrakeEnv string
  166. ReportDownloadingErrors bool
  167. ReportIOErrors bool
  168. EnableDebugHeaders bool
  169. FreeMemoryInterval int
  170. DownloadBufferSize int
  171. BufferPoolCalibrationThreshold int
  172. HealthCheckPath string
  173. ArgumentsSeparator string
  174. )
  175. var (
  176. keyPath string
  177. saltPath string
  178. presetsPath string
  179. )
  180. func init() {
  181. Reset()
  182. flag.StringVar(&keyPath, "keypath", "", "path of the file with hex-encoded key")
  183. flag.StringVar(&saltPath, "saltpath", "", "path of the file with hex-encoded salt")
  184. flag.StringVar(&presetsPath, "presets", "", "path of the file with presets")
  185. }
  186. func Reset() {
  187. Network = "tcp"
  188. Bind = ":8080"
  189. Timeout = 10
  190. GracefulStopTimeout = 20
  191. ReadRequestTimeout = 10
  192. WriteResponseTimeout = 10
  193. KeepAliveTimeout = 10
  194. ClientKeepAliveTimeout = 90
  195. DownloadTimeout = 5
  196. Workers = runtime.GOMAXPROCS(0) * 2
  197. RequestsQueueSize = 0
  198. MaxClients = 2048
  199. TTL = 31536000
  200. CacheControlPassthrough = false
  201. SetCanonicalHeader = false
  202. SoReuseport = false
  203. PathPrefix = ""
  204. MaxSrcResolution = 50000000
  205. MaxSrcFileSize = 0
  206. MaxAnimationFrames = 1
  207. MaxAnimationFrameResolution = 0
  208. MaxSvgCheckBytes = 32 * 1024
  209. MaxRedirects = 10
  210. PngUnlimited = false
  211. SvgUnlimited = false
  212. MaxResultDimension = 0
  213. AllowedProcessingOptions = make([]string, 0)
  214. AllowSecurityOptions = false
  215. JpegProgressive = false
  216. PngInterlaced = false
  217. PngQuantize = false
  218. PngQuantizationColors = 256
  219. AvifSpeed = 8
  220. JxlEffort = 4
  221. WebpEffort = 4
  222. WebpPreset = "default"
  223. Quality = 80
  224. FormatQuality = map[imagetype.Type]int{
  225. imagetype.WEBP: 79,
  226. imagetype.AVIF: 63,
  227. imagetype.JXL: 77,
  228. }
  229. StripMetadata = true
  230. KeepCopyright = true
  231. StripColorProfile = true
  232. AutoRotate = true
  233. EnforceThumbnail = false
  234. ReturnAttachment = false
  235. AutoWebp = false
  236. EnforceWebp = false
  237. AutoAvif = false
  238. EnforceAvif = false
  239. AutoJxl = false
  240. EnforceJxl = false
  241. EnableClientHints = false
  242. PreferredFormats = []imagetype.Type{
  243. imagetype.JPEG,
  244. imagetype.PNG,
  245. imagetype.GIF,
  246. }
  247. SkipProcessingFormats = make([]imagetype.Type, 0)
  248. UseLinearColorspace = false
  249. DisableShrinkOnLoad = false
  250. Keys = make([][]byte, 0)
  251. Salts = make([][]byte, 0)
  252. SignatureSize = 32
  253. TrustedSignatures = make([]string, 0)
  254. Secret = ""
  255. AllowOrigin = ""
  256. UserAgent = "imgproxy/%current_version"
  257. IgnoreSslVerification = false
  258. DevelopmentErrorsMode = false
  259. AllowedSources = make([]*regexp.Regexp, 0)
  260. AllowLoopbackSourceAddresses = false
  261. AllowLinkLocalSourceAddresses = false
  262. AllowPrivateSourceAddresses = true
  263. SanitizeSvg = true
  264. AlwaysRasterizeSvg = false
  265. CookiePassthrough = false
  266. CookieBaseURL = ""
  267. CookiePassthroughAll = false
  268. SourceURLQuerySeparator = "?"
  269. LocalFileSystemRoot = ""
  270. S3Enabled = false
  271. S3Region = ""
  272. S3Endpoint = ""
  273. S3EndpointUsePathStyle = true
  274. S3AssumeRoleArn = ""
  275. S3AssumeRoleExternalID = ""
  276. S3DecryptionClientEnabled = false
  277. GCSEnabled = false
  278. GCSKey = ""
  279. ABSEnabled = false
  280. ABSName = ""
  281. ABSKey = ""
  282. ABSEndpoint = ""
  283. SwiftEnabled = false
  284. SwiftUsername = ""
  285. SwiftAPIKey = ""
  286. SwiftAuthURL = ""
  287. SwiftAuthVersion = 0
  288. SwiftTenant = ""
  289. SwiftDomain = ""
  290. SwiftConnectTimeoutSeconds = 10
  291. SwiftTimeoutSeconds = 60
  292. ETagEnabled = true
  293. ETagBuster = ""
  294. LastModifiedEnabled = true
  295. BaseURL = ""
  296. URLReplacements = make([]URLReplacement, 0)
  297. Base64URLIncludesFilename = false
  298. Presets = make([]string, 0)
  299. OnlyPresets = false
  300. WatermarkData = ""
  301. WatermarkPath = ""
  302. WatermarkURL = ""
  303. WatermarkOpacity = 1
  304. FallbackImageData = ""
  305. FallbackImagePath = ""
  306. FallbackImageURL = ""
  307. FallbackImageHTTPCode = 200
  308. FallbackImageTTL = 0
  309. DataDogEnable = false
  310. NewRelicAppName = ""
  311. NewRelicKey = ""
  312. NewRelicLabels = make(map[string]string)
  313. PrometheusBind = ""
  314. PrometheusNamespace = ""
  315. OpenTelemetryEnable = false
  316. OpenTelemetryEnableMetrics = false
  317. OpenTelemetryServerCert = ""
  318. OpenTelemetryClientCert = ""
  319. OpenTelemetryClientKey = ""
  320. OpenTelemetryTraceIDGenerator = "xray"
  321. CloudWatchServiceName = ""
  322. CloudWatchNamespace = "imgproxy"
  323. CloudWatchRegion = ""
  324. BugsnagKey = ""
  325. BugsnagStage = "production"
  326. HoneybadgerKey = ""
  327. HoneybadgerEnv = "production"
  328. SentryDSN = ""
  329. SentryEnvironment = "production"
  330. SentryRelease = fmt.Sprintf("imgproxy@%s", version.Version)
  331. AirbrakeProjectID = 0
  332. AirbrakeProjectKey = ""
  333. AirbrakeEnv = "production"
  334. ReportDownloadingErrors = true
  335. ReportIOErrors = false
  336. EnableDebugHeaders = false
  337. FreeMemoryInterval = 10
  338. DownloadBufferSize = 0
  339. BufferPoolCalibrationThreshold = 1024
  340. HealthCheckPath = ""
  341. ArgumentsSeparator = ":"
  342. }
  343. func Configure() error {
  344. if port := os.Getenv("PORT"); len(port) > 0 {
  345. Bind = fmt.Sprintf(":%s", port)
  346. }
  347. configurators.String(&Network, "IMGPROXY_NETWORK")
  348. configurators.String(&Bind, "IMGPROXY_BIND")
  349. if _, ok := os.LookupEnv("IMGPROXY_WRITE_TIMEOUT"); ok {
  350. slog.Warn("IMGPROXY_WRITE_TIMEOUT is deprecated, use IMGPROXY_TIMEOUT instead")
  351. configurators.Int(&Timeout, "IMGPROXY_WRITE_TIMEOUT")
  352. }
  353. configurators.Int(&Timeout, "IMGPROXY_TIMEOUT")
  354. GracefulStopTimeout = Timeout * 2
  355. configurators.Int(&GracefulStopTimeout, "IMGPROXY_GRACEFUL_STOP_TIMEOUT")
  356. if _, ok := os.LookupEnv("IMGPROXY_READ_TIMEOUT"); ok {
  357. slog.Warn("IMGPROXY_READ_TIMEOUT is deprecated, use IMGPROXY_READ_REQUEST_TIMEOUT instead")
  358. configurators.Int(&ReadRequestTimeout, "IMGPROXY_READ_TIMEOUT")
  359. }
  360. configurators.Int(&ReadRequestTimeout, "IMGPROXY_READ_REQUEST_TIMEOUT")
  361. configurators.Int(&WriteResponseTimeout, "IMGPROXY_WRITE_RESPONSE_TIMEOUT")
  362. configurators.Int(&KeepAliveTimeout, "IMGPROXY_KEEP_ALIVE_TIMEOUT")
  363. configurators.Int(&ClientKeepAliveTimeout, "IMGPROXY_CLIENT_KEEP_ALIVE_TIMEOUT")
  364. configurators.Int(&DownloadTimeout, "IMGPROXY_DOWNLOAD_TIMEOUT")
  365. if lambdaFn := os.Getenv("AWS_LAMBDA_FUNCTION_NAME"); len(lambdaFn) > 0 {
  366. Workers = 1
  367. slog.Info("AWS Lambda environment detected, setting workers to 1")
  368. } else {
  369. configurators.Int(&Workers, "IMGPROXY_CONCURRENCY")
  370. configurators.Int(&Workers, "IMGPROXY_WORKERS")
  371. }
  372. configurators.Int(&RequestsQueueSize, "IMGPROXY_REQUESTS_QUEUE_SIZE")
  373. configurators.Int(&MaxClients, "IMGPROXY_MAX_CLIENTS")
  374. configurators.Int(&TTL, "IMGPROXY_TTL")
  375. configurators.Bool(&CacheControlPassthrough, "IMGPROXY_CACHE_CONTROL_PASSTHROUGH")
  376. configurators.Bool(&SetCanonicalHeader, "IMGPROXY_SET_CANONICAL_HEADER")
  377. configurators.Bool(&SoReuseport, "IMGPROXY_SO_REUSEPORT")
  378. configurators.URLPath(&PathPrefix, "IMGPROXY_PATH_PREFIX")
  379. configurators.MegaInt(&MaxSrcResolution, "IMGPROXY_MAX_SRC_RESOLUTION")
  380. configurators.Int(&MaxSrcFileSize, "IMGPROXY_MAX_SRC_FILE_SIZE")
  381. configurators.Int(&MaxSvgCheckBytes, "IMGPROXY_MAX_SVG_CHECK_BYTES")
  382. configurators.Int(&MaxAnimationFrames, "IMGPROXY_MAX_ANIMATION_FRAMES")
  383. configurators.MegaInt(&MaxAnimationFrameResolution, "IMGPROXY_MAX_ANIMATION_FRAME_RESOLUTION")
  384. configurators.Int(&MaxRedirects, "IMGPROXY_MAX_REDIRECTS")
  385. configurators.Patterns(&AllowedSources, "IMGPROXY_ALLOWED_SOURCES")
  386. configurators.Bool(&AllowLoopbackSourceAddresses, "IMGPROXY_ALLOW_LOOPBACK_SOURCE_ADDRESSES")
  387. configurators.Bool(&AllowLinkLocalSourceAddresses, "IMGPROXY_ALLOW_LINK_LOCAL_SOURCE_ADDRESSES")
  388. configurators.Bool(&AllowPrivateSourceAddresses, "IMGPROXY_ALLOW_PRIVATE_SOURCE_ADDRESSES")
  389. configurators.Bool(&SanitizeSvg, "IMGPROXY_SANITIZE_SVG")
  390. configurators.Bool(&AlwaysRasterizeSvg, "IMGPROXY_ALWAYS_RASTERIZE_SVG")
  391. configurators.Bool(&PngUnlimited, "IMGPROXY_PNG_UNLIMITED")
  392. configurators.Bool(&SvgUnlimited, "IMGPROXY_SVG_UNLIMITED")
  393. configurators.Int(&MaxResultDimension, "IMGPROXY_MAX_RESULT_DIMENSION")
  394. configurators.StringSlice(&AllowedProcessingOptions, "IMGPROXY_ALLOWED_PROCESSING_OPTIONS")
  395. configurators.Bool(&AllowSecurityOptions, "IMGPROXY_ALLOW_SECURITY_OPTIONS")
  396. configurators.Bool(&JpegProgressive, "IMGPROXY_JPEG_PROGRESSIVE")
  397. configurators.Bool(&PngInterlaced, "IMGPROXY_PNG_INTERLACED")
  398. configurators.Bool(&PngQuantize, "IMGPROXY_PNG_QUANTIZE")
  399. configurators.Int(&PngQuantizationColors, "IMGPROXY_PNG_QUANTIZATION_COLORS")
  400. configurators.Int(&AvifSpeed, "IMGPROXY_AVIF_SPEED")
  401. configurators.Int(&JxlEffort, "IMGPROXY_JXL_EFFORT")
  402. configurators.Int(&WebpEffort, "IMGPROXY_WEBP_EFFORT")
  403. configurators.String(&WebpPreset, "IMGPROXY_WEBP_PRESET")
  404. configurators.Int(&Quality, "IMGPROXY_QUALITY")
  405. if err := configurators.ImageTypesQuality(FormatQuality, "IMGPROXY_FORMAT_QUALITY"); err != nil {
  406. return err
  407. }
  408. configurators.Bool(&StripMetadata, "IMGPROXY_STRIP_METADATA")
  409. configurators.Bool(&KeepCopyright, "IMGPROXY_KEEP_COPYRIGHT")
  410. configurators.Bool(&StripColorProfile, "IMGPROXY_STRIP_COLOR_PROFILE")
  411. configurators.Bool(&AutoRotate, "IMGPROXY_AUTO_ROTATE")
  412. configurators.Bool(&EnforceThumbnail, "IMGPROXY_ENFORCE_THUMBNAIL")
  413. configurators.Bool(&ReturnAttachment, "IMGPROXY_RETURN_ATTACHMENT")
  414. if _, ok := os.LookupEnv("IMGPROXY_ENABLE_WEBP_DETECTION"); ok {
  415. slog.Warn("IMGPROXY_ENABLE_WEBP_DETECTION is deprecated, use IMGPROXY_AUTO_WEBP instead")
  416. configurators.Bool(&AutoWebp, "IMGPROXY_ENABLE_WEBP_DETECTION")
  417. }
  418. if _, ok := os.LookupEnv("IMGPROXY_ENABLE_AVIF_DETECTION"); ok {
  419. slog.Warn("IMGPROXY_ENABLE_AVIF_DETECTION is deprecated, use IMGPROXY_AUTO_AVIF instead")
  420. configurators.Bool(&AutoAvif, "IMGPROXY_ENABLE_AVIF_DETECTION")
  421. }
  422. configurators.Bool(&AutoWebp, "IMGPROXY_AUTO_WEBP")
  423. configurators.Bool(&EnforceWebp, "IMGPROXY_ENFORCE_WEBP")
  424. configurators.Bool(&AutoAvif, "IMGPROXY_AUTO_AVIF")
  425. configurators.Bool(&EnforceAvif, "IMGPROXY_ENFORCE_AVIF")
  426. configurators.Bool(&AutoJxl, "IMGPROXY_AUTO_JXL")
  427. configurators.Bool(&EnforceJxl, "IMGPROXY_ENFORCE_JXL")
  428. configurators.Bool(&EnableClientHints, "IMGPROXY_ENABLE_CLIENT_HINTS")
  429. configurators.URLPath(&HealthCheckPath, "IMGPROXY_HEALTH_CHECK_PATH")
  430. configurators.String(&ArgumentsSeparator, "IMGPROXY_ARGUMENTS_SEPARATOR")
  431. if err := configurators.ImageTypes(&PreferredFormats, "IMGPROXY_PREFERRED_FORMATS"); err != nil {
  432. return err
  433. }
  434. if err := configurators.ImageTypes(&SkipProcessingFormats, "IMGPROXY_SKIP_PROCESSING_FORMATS"); err != nil {
  435. return err
  436. }
  437. configurators.Bool(&UseLinearColorspace, "IMGPROXY_USE_LINEAR_COLORSPACE")
  438. configurators.Bool(&DisableShrinkOnLoad, "IMGPROXY_DISABLE_SHRINK_ON_LOAD")
  439. if err := configurators.HexSlice(&Keys, "IMGPROXY_KEY"); err != nil {
  440. return err
  441. }
  442. if err := configurators.HexSlice(&Salts, "IMGPROXY_SALT"); err != nil {
  443. return err
  444. }
  445. configurators.Int(&SignatureSize, "IMGPROXY_SIGNATURE_SIZE")
  446. configurators.StringSlice(&TrustedSignatures, "IMGPROXY_TRUSTED_SIGNATURES")
  447. if err := configurators.HexSliceFile(&Keys, keyPath); err != nil {
  448. return err
  449. }
  450. if err := configurators.HexSliceFile(&Salts, saltPath); err != nil {
  451. return err
  452. }
  453. configurators.String(&Secret, "IMGPROXY_SECRET")
  454. configurators.String(&AllowOrigin, "IMGPROXY_ALLOW_ORIGIN")
  455. configurators.String(&UserAgent, "IMGPROXY_USER_AGENT")
  456. UserAgent = strings.ReplaceAll(UserAgent, "%current_version", version.Version)
  457. configurators.Bool(&IgnoreSslVerification, "IMGPROXY_IGNORE_SSL_VERIFICATION")
  458. configurators.Bool(&DevelopmentErrorsMode, "IMGPROXY_DEVELOPMENT_ERRORS_MODE")
  459. configurators.Bool(&CookiePassthrough, "IMGPROXY_COOKIE_PASSTHROUGH")
  460. configurators.String(&CookieBaseURL, "IMGPROXY_COOKIE_BASE_URL")
  461. configurators.Bool(&CookiePassthroughAll, "IMGPROXY_COOKIE_PASSTHROUGH_ALL")
  462. // Can't rely on configurators.String here because it ignores empty values
  463. if s, ok := os.LookupEnv("IMGPROXY_SOURCE_URL_QUERY_SEPARATOR"); ok {
  464. SourceURLQuerySeparator = s
  465. }
  466. configurators.String(&LocalFileSystemRoot, "IMGPROXY_LOCAL_FILESYSTEM_ROOT")
  467. configurators.Bool(&S3Enabled, "IMGPROXY_USE_S3")
  468. configurators.String(&S3Region, "IMGPROXY_S3_REGION")
  469. configurators.String(&S3Endpoint, "IMGPROXY_S3_ENDPOINT")
  470. configurators.Bool(&S3EndpointUsePathStyle, "IMGPROXY_S3_ENDPOINT_USE_PATH_STYLE")
  471. configurators.String(&S3AssumeRoleArn, "IMGPROXY_S3_ASSUME_ROLE_ARN")
  472. configurators.String(&S3AssumeRoleExternalID, "IMGPROXY_S3_ASSUME_ROLE_EXTERNAL_ID")
  473. configurators.Bool(&S3DecryptionClientEnabled, "IMGPROXY_S3_USE_DECRYPTION_CLIENT")
  474. configurators.Bool(&GCSEnabled, "IMGPROXY_USE_GCS")
  475. configurators.String(&GCSKey, "IMGPROXY_GCS_KEY")
  476. configurators.String(&GCSEndpoint, "IMGPROXY_GCS_ENDPOINT")
  477. configurators.Bool(&ABSEnabled, "IMGPROXY_USE_ABS")
  478. configurators.String(&ABSName, "IMGPROXY_ABS_NAME")
  479. configurators.String(&ABSKey, "IMGPROXY_ABS_KEY")
  480. configurators.String(&ABSEndpoint, "IMGPROXY_ABS_ENDPOINT")
  481. configurators.Bool(&SwiftEnabled, "IMGPROXY_USE_SWIFT")
  482. configurators.String(&SwiftUsername, "IMGPROXY_SWIFT_USERNAME")
  483. configurators.String(&SwiftAPIKey, "IMGPROXY_SWIFT_API_KEY")
  484. configurators.String(&SwiftAuthURL, "IMGPROXY_SWIFT_AUTH_URL")
  485. configurators.String(&SwiftDomain, "IMGPROXY_SWIFT_DOMAIN")
  486. configurators.String(&SwiftTenant, "IMGPROXY_SWIFT_TENANT")
  487. configurators.Int(&SwiftConnectTimeoutSeconds, "IMGPROXY_SWIFT_CONNECT_TIMEOUT_SECONDS")
  488. configurators.Int(&SwiftTimeoutSeconds, "IMGPROXY_SWIFT_TIMEOUT_SECONDS")
  489. configurators.Bool(&ETagEnabled, "IMGPROXY_USE_ETAG")
  490. configurators.String(&ETagBuster, "IMGPROXY_ETAG_BUSTER")
  491. configurators.Bool(&LastModifiedEnabled, "IMGPROXY_USE_LAST_MODIFIED")
  492. configurators.String(&BaseURL, "IMGPROXY_BASE_URL")
  493. if err := configurators.Replacements(&URLReplacements, "IMGPROXY_URL_REPLACEMENTS"); err != nil {
  494. return err
  495. }
  496. configurators.Bool(&Base64URLIncludesFilename, "IMGPROXY_BASE64_URL_INCLUDES_FILENAME")
  497. presetsSep := ","
  498. configurators.String(&presetsSep, "IMGPROXY_PRESETS_SEPARATOR")
  499. configurators.StringSliceSep(&Presets, "IMGPROXY_PRESETS", presetsSep)
  500. if err := configurators.StringSliceFile(&Presets, presetsPath); err != nil {
  501. return err
  502. }
  503. configurators.Bool(&OnlyPresets, "IMGPROXY_ONLY_PRESETS")
  504. configurators.String(&WatermarkData, "IMGPROXY_WATERMARK_DATA")
  505. configurators.String(&WatermarkPath, "IMGPROXY_WATERMARK_PATH")
  506. configurators.String(&WatermarkURL, "IMGPROXY_WATERMARK_URL")
  507. configurators.Float(&WatermarkOpacity, "IMGPROXY_WATERMARK_OPACITY")
  508. configurators.String(&FallbackImageData, "IMGPROXY_FALLBACK_IMAGE_DATA")
  509. configurators.String(&FallbackImagePath, "IMGPROXY_FALLBACK_IMAGE_PATH")
  510. configurators.String(&FallbackImageURL, "IMGPROXY_FALLBACK_IMAGE_URL")
  511. configurators.Int(&FallbackImageHTTPCode, "IMGPROXY_FALLBACK_IMAGE_HTTP_CODE")
  512. configurators.Int(&FallbackImageTTL, "IMGPROXY_FALLBACK_IMAGE_TTL")
  513. configurators.Bool(&DataDogEnable, "IMGPROXY_DATADOG_ENABLE")
  514. configurators.Bool(&DataDogEnableMetrics, "IMGPROXY_DATADOG_ENABLE_ADDITIONAL_METRICS")
  515. configurators.String(&NewRelicAppName, "IMGPROXY_NEW_RELIC_APP_NAME")
  516. configurators.String(&NewRelicKey, "IMGPROXY_NEW_RELIC_KEY")
  517. configurators.StringMap(&NewRelicLabels, "IMGPROXY_NEW_RELIC_LABELS")
  518. configurators.String(&PrometheusBind, "IMGPROXY_PROMETHEUS_BIND")
  519. configurators.String(&PrometheusNamespace, "IMGPROXY_PROMETHEUS_NAMESPACE")
  520. configurators.Bool(&OpenTelemetryEnable, "IMGPROXY_OPEN_TELEMETRY_ENABLE")
  521. configurators.Bool(&OpenTelemetryEnableMetrics, "IMGPROXY_OPEN_TELEMETRY_ENABLE_METRICS")
  522. configurators.String(&OpenTelemetryServerCert, "IMGPROXY_OPEN_TELEMETRY_SERVER_CERT")
  523. configurators.String(&OpenTelemetryClientCert, "IMGPROXY_OPEN_TELEMETRY_CLIENT_CERT")
  524. configurators.String(&OpenTelemetryClientKey, "IMGPROXY_OPEN_TELEMETRY_CLIENT_KEY")
  525. configurators.String(&OpenTelemetryTraceIDGenerator, "IMGPROXY_OPEN_TELEMETRY_TRACE_ID_GENERATOR")
  526. configurators.String(&CloudWatchServiceName, "IMGPROXY_CLOUD_WATCH_SERVICE_NAME")
  527. configurators.String(&CloudWatchNamespace, "IMGPROXY_CLOUD_WATCH_NAMESPACE")
  528. configurators.String(&CloudWatchRegion, "IMGPROXY_CLOUD_WATCH_REGION")
  529. configurators.String(&BugsnagKey, "IMGPROXY_BUGSNAG_KEY")
  530. configurators.String(&BugsnagStage, "IMGPROXY_BUGSNAG_STAGE")
  531. configurators.String(&HoneybadgerKey, "IMGPROXY_HONEYBADGER_KEY")
  532. configurators.String(&HoneybadgerEnv, "IMGPROXY_HONEYBADGER_ENV")
  533. configurators.String(&SentryDSN, "IMGPROXY_SENTRY_DSN")
  534. configurators.String(&SentryEnvironment, "IMGPROXY_SENTRY_ENVIRONMENT")
  535. configurators.String(&SentryRelease, "IMGPROXY_SENTRY_RELEASE")
  536. configurators.Int(&AirbrakeProjectID, "IMGPROXY_AIRBRAKE_PROJECT_ID")
  537. configurators.String(&AirbrakeProjectKey, "IMGPROXY_AIRBRAKE_PROJECT_KEY")
  538. configurators.String(&AirbrakeEnv, "IMGPROXY_AIRBRAKE_ENVIRONMENT")
  539. configurators.Bool(&ReportDownloadingErrors, "IMGPROXY_REPORT_DOWNLOADING_ERRORS")
  540. configurators.Bool(&ReportIOErrors, "IMGPROXY_REPORT_IO_ERRORS")
  541. configurators.Bool(&EnableDebugHeaders, "IMGPROXY_ENABLE_DEBUG_HEADERS")
  542. configurators.Int(&FreeMemoryInterval, "IMGPROXY_FREE_MEMORY_INTERVAL")
  543. configurators.Int(&DownloadBufferSize, "IMGPROXY_DOWNLOAD_BUFFER_SIZE")
  544. configurators.Int(&BufferPoolCalibrationThreshold, "IMGPROXY_BUFFER_POOL_CALIBRATION_THRESHOLD")
  545. if len(Keys) != len(Salts) {
  546. return fmt.Errorf("Number of keys and number of salts should be equal. Keys: %d, salts: %d", len(Keys), len(Salts))
  547. }
  548. if len(Keys) == 0 {
  549. slog.Warn("No keys defined, so signature checking is disabled")
  550. }
  551. if len(Salts) == 0 {
  552. slog.Warn("No salts defined, so signature checking is disabled")
  553. }
  554. if SignatureSize < 1 || SignatureSize > 32 {
  555. return fmt.Errorf("Signature size should be within 1 and 32, now - %d\n", SignatureSize)
  556. }
  557. if len(Bind) == 0 {
  558. return errors.New("Bind address is not defined")
  559. }
  560. if Timeout <= 0 {
  561. return fmt.Errorf("Timeout should be greater than 0, now - %d\n", Timeout)
  562. }
  563. if ReadRequestTimeout <= 0 {
  564. return fmt.Errorf("Read request timeout should be greater than 0, now - %d\n", ReadRequestTimeout)
  565. }
  566. if WriteResponseTimeout <= 0 {
  567. return fmt.Errorf("Write response timeout should be greater than 0, now - %d\n", WriteResponseTimeout)
  568. }
  569. if KeepAliveTimeout < 0 {
  570. return fmt.Errorf("KeepAlive timeout should be greater than or equal to 0, now - %d\n", KeepAliveTimeout)
  571. }
  572. if ClientKeepAliveTimeout < 0 {
  573. return fmt.Errorf("Client KeepAlive timeout should be greater than or equal to 0, now - %d\n", ClientKeepAliveTimeout)
  574. }
  575. if DownloadTimeout <= 0 {
  576. return fmt.Errorf("Download timeout should be greater than 0, now - %d\n", DownloadTimeout)
  577. }
  578. if Workers <= 0 {
  579. return fmt.Errorf("Workers number should be greater than 0, now - %d\n", Workers)
  580. }
  581. if RequestsQueueSize < 0 {
  582. return fmt.Errorf("Requests queue size should be greater than or equal 0, now - %d\n", RequestsQueueSize)
  583. }
  584. if MaxClients < 0 {
  585. return fmt.Errorf("Max clients number should be greater than or equal 0, now - %d\n", MaxClients)
  586. }
  587. if TTL < 0 {
  588. return fmt.Errorf("TTL should be greater than or equal to 0, now - %d\n", TTL)
  589. }
  590. if MaxSrcResolution <= 0 {
  591. return fmt.Errorf("Max src resolution should be greater than 0, now - %d\n", MaxSrcResolution)
  592. }
  593. if MaxSrcFileSize < 0 {
  594. return fmt.Errorf("Max src file size should be greater than or equal to 0, now - %d\n", MaxSrcFileSize)
  595. }
  596. if MaxAnimationFrames <= 0 {
  597. return fmt.Errorf("Max animation frames should be greater than 0, now - %d\n", MaxAnimationFrames)
  598. }
  599. if PngQuantizationColors < 2 {
  600. return fmt.Errorf("Png quantization colors should be greater than 1, now - %d\n", PngQuantizationColors)
  601. } else if PngQuantizationColors > 256 {
  602. return fmt.Errorf("Png quantization colors can't be greater than 256, now - %d\n", PngQuantizationColors)
  603. }
  604. if AvifSpeed < 0 {
  605. return fmt.Errorf("Avif speed should be greater than or equal to 0, now - %d\n", AvifSpeed)
  606. } else if AvifSpeed > 9 {
  607. return fmt.Errorf("Avif speed can't be greater than 9, now - %d\n", AvifSpeed)
  608. }
  609. if JxlEffort < 1 {
  610. return fmt.Errorf("JXL effort should be greater than 0, now - %d\n", JxlEffort)
  611. } else if JxlEffort > 9 {
  612. return fmt.Errorf("JXL effort can't be greater than 9, now - %d\n", JxlEffort)
  613. }
  614. if WebpEffort < 1 {
  615. return fmt.Errorf("Webp effort should be greater than 0, now - %d\n", WebpEffort)
  616. } else if WebpEffort > 6 {
  617. return fmt.Errorf("Webp effort can't be greater than 6, now - %d\n", WebpEffort)
  618. }
  619. if Quality <= 0 {
  620. return fmt.Errorf("Quality should be greater than 0, now - %d\n", Quality)
  621. } else if Quality > 100 {
  622. return fmt.Errorf("Quality can't be greater than 100, now - %d\n", Quality)
  623. }
  624. if len(PreferredFormats) == 0 {
  625. return errors.New("At least one preferred format should be specified")
  626. }
  627. if IgnoreSslVerification {
  628. slog.Warn("Ignoring SSL verification is very unsafe")
  629. }
  630. if LocalFileSystemRoot != "" {
  631. stat, err := os.Stat(LocalFileSystemRoot)
  632. if err != nil {
  633. return fmt.Errorf("Cannot use local directory: %s", err)
  634. }
  635. if !stat.IsDir() {
  636. return errors.New("Cannot use local directory: not a directory")
  637. }
  638. if LocalFileSystemRoot == "/" {
  639. slog.Warn("Exposing root via IMGPROXY_LOCAL_FILESYSTEM_ROOT is unsafe")
  640. }
  641. }
  642. if _, ok := os.LookupEnv("IMGPROXY_USE_GCS"); !ok && len(GCSKey) > 0 {
  643. slog.Warn("Set IMGPROXY_USE_GCS to true since it may be required by future versions to enable GCS support")
  644. GCSEnabled = true
  645. }
  646. if WatermarkOpacity <= 0 {
  647. return errors.New("Watermark opacity should be greater than 0")
  648. } else if WatermarkOpacity > 1 {
  649. return errors.New("Watermark opacity should be less than or equal to 1")
  650. }
  651. if FallbackImageTTL < 0 {
  652. return fmt.Errorf("Fallback image TTL should be greater than or equal to 0, now - %d\n", TTL)
  653. }
  654. if FallbackImageHTTPCode != 0 && (FallbackImageHTTPCode < 100 || FallbackImageHTTPCode > 599) {
  655. return errors.New("Fallback image HTTP code should be between 100 and 599")
  656. }
  657. if len(PrometheusBind) > 0 && PrometheusBind == Bind {
  658. return errors.New("Can't use the same binding for the main server and Prometheus")
  659. }
  660. if FreeMemoryInterval <= 0 {
  661. return errors.New("Free memory interval should be greater than zero")
  662. }
  663. if DownloadBufferSize < 0 {
  664. return errors.New("Download buffer size should be greater than or equal to 0")
  665. } else if DownloadBufferSize > math.MaxInt32 {
  666. return fmt.Errorf("Download buffer size can't be greater than %d", math.MaxInt32)
  667. }
  668. if BufferPoolCalibrationThreshold < 64 {
  669. return errors.New("Buffer pool calibration threshold should be greater than or equal to 64")
  670. }
  671. return nil
  672. }