部署含config.toml的Golang API(nrfapi):配置文件找不到问题求助
Looks like the issue is straightforward—when systemd runs your nrfapi service, it uses / (the root directory) as the default working directory. Your Go app is trying to read config.toml from the current working directory, which doesn't exist there, hence the "no such file or directory" error.
Here are a few solid solutions to fix this:
1. Fix the systemd service file (quickest fix, no code changes)
First, let's correct the typo in your nrf.service file—you have an extra closing parenthesis in ExecStart that will cause issues. Then, we'll tell systemd to run the service from the directory where your app and config file live.
Step 1: Update the service file
Edit /etc/systemd/system/nrf.service to look like this:
[Unit] Description=Instance to serve nrf API After=network.target [Service] User=root Group=www-data # Set working directory to where your app and config are stored WorkingDirectory=/var/www/go # Fix the typo (removed extra )) ExecStart=/var/www/go/nrfapi # Optional: Auto-restart the service if it crashes Restart=always [Install] WantedBy=multi-user.target
Step 2: Place your config file correctly
Copy your config.toml to /var/www/go/ (same directory as the compiled nrfapi binary):
scp config.toml your-vm-user@your-vm-ip:/var/www/go/
Step 3: Fix permissions (if needed)
Make sure the www-data group can read the config file:
sudo chown root:www-data /var/www/go/config.toml sudo chmod 640 /var/www/go/config.toml
Step 4: Reload systemd and restart the service
sudo systemctl daemon-reload sudo systemctl restart nrf.service
Check if it's running with sudo systemctl status nrf.service—it should now find the config file.
2. Use a dedicated config directory (Linux best practice)
If you want to follow standard Linux filesystem conventions (keeping configs separate from binaries), you can modify your app to accept a config file path via command line, then store the config in /etc.
Step 1: Update your Go code to accept a config path flag
Add command line argument parsing using the standard flag package:
package main import ( "flag" "log" "github.com/BurntSushi/toml" ) // Define your config structure here type AppConfig struct { // Example fields: Port int APIKey string } var configPath = flag.String("config", "config.toml", "Path to the configuration file") func main() { flag.Parse() var cfg AppConfig if _, err := toml.DecodeFile(*configPath, &cfg); err != nil { log.Fatalf("Failed to load config: %v", err) } // Rest of your app logic... }
Step 2: Recompile and re-deploy your app
GOOS=linux GOARCH=amd64 go build scp nrfapi your-vm-user@your-vm-ip:/var/www/go/
Step 3: Set up the config directory on the VM
sudo mkdir -p /etc/nrfapi sudo scp config.toml your-vm-user@your-vm-ip:/etc/nrfapi/ sudo chown root:www-data /etc/nrfapi/config.toml sudo chmod 640 /etc/nrfapi/config.toml
Step 4: Update the systemd service to use the config path
Modify the ExecStart line in /etc/systemd/system/nrf.service:
ExecStart=/var/www/go/nrfapi --config /etc/nrfapi/config.toml
Reload systemd and restart the service as before.
3. Hardcode the config path (not recommended, but works)
If you don't want to touch the systemd file or add flags, you can hardcode the absolute path to config.toml in your Go code. For example:
// Replace "config.toml" with "/var/www/go/config.toml" if _, err := toml.DecodeFile("/var/www/go/config.toml", &cfg); err != nil { log.Fatal(err) }
This is less flexible, but it'll solve the immediate issue.
内容的提问来源于stack exchange,提问作者Abraham

