@@ -19,6 +19,7 @@ import (
19
19
"errors"
20
20
"flag"
21
21
"fmt"
22
+ "io"
22
23
"io/ioutil"
23
24
"log"
24
25
"os"
@@ -50,6 +51,7 @@ func init() {
50
51
flag .StringVar (& disabledMetrics , "disabled-metrics" , "" , "Comma-separated list of telemetry metrics to disable" )
51
52
flag .StringVar (& conf , "conf" , "" , "Caddyfile to load (default \" " + caddy .DefaultConfigFile + "\" )" )
52
53
flag .StringVar (& cpu , "cpu" , "100%" , "CPU cap" )
54
+ flag .StringVar (& envFile , "env" , "" , "Path to file with environment variables to load in KEY=VALUE format" )
53
55
flag .BoolVar (& plugins , "plugins" , false , "List installed plugins" )
54
56
flag .StringVar (& caddytls .DefaultEmail , "email" , "" , "Default ACME CA account email address" )
55
57
flag .DurationVar (& acme .HTTPClient .Timeout , "catimeout" , acme .HTTPClient .Timeout , "Default ACME CA HTTP timeout" )
@@ -90,6 +92,11 @@ func Run() {
90
92
})
91
93
}
92
94
95
+ //Load all additional envs as soon as possible
96
+ if err := LoadEnvFromFile (envFile ); err != nil {
97
+ mustLogFatalf ("%v" , err )
98
+ }
99
+
93
100
// initialize telemetry client
94
101
if enableTelemetry {
95
102
err := initTelemetry ()
@@ -409,13 +416,88 @@ func initTelemetry() error {
409
416
return nil
410
417
}
411
418
419
+ // LoadEnvFromFile loads additional envs if file provided and exists
420
+ // Envs in file should be in KEY=VALUE format
421
+ func LoadEnvFromFile (envFile string ) error {
422
+ if envFile == "" {
423
+ return nil
424
+ }
425
+
426
+ file , err := os .Open (envFile )
427
+ if err != nil {
428
+ return err
429
+ }
430
+ defer file .Close ()
431
+
432
+ envMap , err := ParseEnvFile (file )
433
+ if err != nil {
434
+ return err
435
+ }
436
+
437
+ for k , v := range envMap {
438
+ if err := os .Setenv (k , v ); err != nil {
439
+ return err
440
+ }
441
+ }
442
+
443
+ return nil
444
+ }
445
+
446
+ // ParseEnvFile implements parse logic for environment files
447
+ func ParseEnvFile (envInput io.Reader ) (map [string ]string , error ) {
448
+ envMap := make (map [string ]string )
449
+
450
+ scanner := bufio .NewScanner (envInput )
451
+ var line string
452
+ lineNumber := 0
453
+
454
+ for scanner .Scan () {
455
+ line = strings .TrimSpace (scanner .Text ())
456
+ lineNumber ++
457
+
458
+ // skip lines starting with comment
459
+ if strings .HasPrefix (line , "#" ) {
460
+ continue
461
+ }
462
+
463
+ // skip empty line
464
+ if len (line ) == 0 {
465
+ continue
466
+ }
467
+
468
+ fields := strings .SplitN (line , "=" , 2 )
469
+ if len (fields ) != 2 {
470
+ return nil , fmt .Errorf ("Can't parse line %d; line should be in KEY=VALUE format" , lineNumber )
471
+ }
472
+
473
+ if strings .Contains (fields [0 ], " " ) {
474
+ return nil , fmt .Errorf ("Can't parse line %d; KEY contains whitespace" , lineNumber )
475
+ }
476
+
477
+ key := fields [0 ]
478
+ val := fields [1 ]
479
+
480
+ if key == "" {
481
+ return nil , fmt .Errorf ("Can't parse line %d; KEY can't be empty string" , lineNumber )
482
+ }
483
+ envMap [key ] = val
484
+ }
485
+
486
+ if err := scanner .Err (); err != nil {
487
+ return nil , err
488
+ }
489
+
490
+ return envMap , nil
491
+ }
492
+
412
493
const appName = "Caddy"
413
494
414
495
// Flags that control program flow or startup
415
496
var (
416
497
serverType string
417
498
conf string
418
499
cpu string
500
+ envFile string
419
501
logfile string
420
502
revoke string
421
503
version bool
0 commit comments