How to fix environment variables not working while running from system-d service in Go
Asked Answered
D

5

14

I am using os.Getenv("APP_PATH") to read from the system environment variables and it works fine when running the build of the application normally. But I need to run this Go program as a service which I have done using systemd in which case it cannot read the environment variables. Is there any way of resolving this?

Detroit answered 31/1, 2019 at 8:24 Comment(2)
Why you cannot read variable in case of systemd?Unaccountedfor
Add your service definition file to the question, otherwise we can only guess.Husserl
C
9

You can follow along from here to make the use of the environment variables. The way I am using to implement environment variables in my project is GODOTENV go library. It is very easy to implement and platform independent.

Simply run

err = godotenv.Load(filepath.Join(path_dir, ".env"))

and you are done. Now you can use you code os.Getenv("APP_PATH") to read the keys from your .env file and it works perfectly fine with systemd service.

Compaction answered 31/1, 2019 at 8:38 Comment(2)
What is the filePath and path_dir?Mallen
filePath you need to import using import "path/filepath" and path_dir is where your .env file isKeloid
U
9

It depends on how you're running your systemd service. Systemd provide a bunch of derictive you should use:

[Unit]
Description=My service
After=network.target

[Service]
Type=simple
User=user
Group=user
EnvironmentFile=/home/user/env_file
ExecStart=/bin/bash -c -l '/home/user/go_program'
# ... other directive goes here

[Install]
WantedBy=multi-user.target
  • EnvironmentFile - the file with ENV variables, that file will be loaded for you by systemd.

  • User, Group - under which user and group the program should run.

  • ExecStart=/bin/bash -c -l '/home/user/go_program' - the -l options makes bash act as if it had been invoked as a login shell, so the variable in your .bash_profile will be loaded(see User and Group section).
Unaccountedfor answered 31/1, 2019 at 8:48 Comment(0)
S
6

We have our environment variables in a .env file and use godotenv

    import {
       "github.com/joho/godotenv"
    }

    func main() {

        dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
        if err != nil {
            log.Fatal(err)
        }
        environmentPath := filepath.Join(dir, ".env")
        err = godotenv.Load(environmentPath)
        fatal(err)
    }

and it works when we run our apps in daemon mode

Scandalmonger answered 31/1, 2019 at 8:31 Comment(0)
A
0

If you got an error Error loading .env file when you use godotenv package, that means you have to pass full path to .env file to Load function.

If your main.go file located at /cmd/main.go and .env file located in root folder /.env use this example

import (
    "fmt"
    "github.com/joho/godotenv"
    "log"
    "os"
    "path/filepath"
)

func main() {
    pwd, err := os.Getwd()
    if err != nil {
        panic(err)
    }
    
    //use ../.env because main.go inside /cmd
    err = godotenv.Load(filepath.Join(pwd, "../.env"))
    if err != nil {
        log.Fatal("Error loading .env file")
    }
    fmt.Println(fmt.Sprintf("MYVAR=%s", os.Getenv("MYVAR")))
}
Acarid answered 29/4 at 7:49 Comment(0)
H
0

Here is my solution:

func LoadENV() {
    path := ".env"
    for {
        err := godotenv.Load(path)
        if err == nil {
            break
        }
        path = "../" + path
    }
}
Hinckley answered 20/7 at 9:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.