diff --git a/cmd/proxy/actions/app_proxy.go b/cmd/proxy/actions/app_proxy.go index 0b9cd00db..777ad4ca6 100644 --- a/cmd/proxy/actions/app_proxy.go +++ b/cmd/proxy/actions/app_proxy.go @@ -32,7 +32,7 @@ func addProxyRoutes( l *log.Logger, c *config.Config, ) error { - r.HandleFunc("/", proxyHomeHandler) + r.HandleFunc("/", proxyHomeHandler(c)) r.HandleFunc("/healthz", healthHandler) r.HandleFunc("/readyz", getReadinessHandler(s)) r.HandleFunc("/version", versionHandler) diff --git a/cmd/proxy/actions/app_proxy_test.go b/cmd/proxy/actions/app_proxy_test.go index 7b2b37415..735aea4dd 100644 --- a/cmd/proxy/actions/app_proxy_test.go +++ b/cmd/proxy/actions/app_proxy_test.go @@ -7,6 +7,7 @@ import ( "net/http/httptest" "strings" "testing" + "text/template" "github.com/gomods/athens/pkg/build" "github.com/gomods/athens/pkg/config" @@ -21,7 +22,7 @@ type routeTest struct { method string path string body string - test func(t *testing.T, resp *http.Response) + test func(t *testing.T, req *http.Request, resp *http.Response) } func TestProxyRoutes(t *testing.T) { @@ -40,22 +41,43 @@ func TestProxyRoutes(t *testing.T) { baseURL := "https://athens.azurefd.net" + c.PathPrefix testCases := []routeTest{ - {"GET", "/", "", func(t *testing.T, resp *http.Response) { + {"GET", "/", "", func(t *testing.T, req *http.Request, resp *http.Response) { assert.Equal(t, http.StatusOK, resp.StatusCode) body, err := io.ReadAll(resp.Body) require.NoError(t, err) - assert.Equal(t, `"Welcome to The Athens Proxy"`, string(body)) + tmp, err := template.New("home").Parse(homepage) + assert.NoError(t, err) + + var templateData = make(map[string]string) + + templateData["Host"] = req.Host + + if !strings.HasPrefix(templateData["Host"], "http://") && !strings.HasPrefix(templateData["Host"], "https://") { + if req.TLS != nil { + templateData["Host"] = "https://" + templateData["Host"] + } else { + templateData["Host"] = "http://" + templateData["Host"] + } + } + + templateData["NoSumPatterns"] = strings.Join(c.NoSumPatterns, ",") + + var expected strings.Builder + err = tmp.ExecuteTemplate(&expected, "home", templateData) + require.NoError(t, err) + + assert.Equal(t, expected.String(), string(body)) }}, - {"GET", "/badz", "", func(t *testing.T, resp *http.Response) { + {"GET", "/badz", "", func(t *testing.T, req *http.Request, resp *http.Response) { assert.Equal(t, http.StatusNotFound, resp.StatusCode) }}, - {"GET", "/healthz", "", func(t *testing.T, resp *http.Response) { + {"GET", "/healthz", "", func(t *testing.T, req *http.Request, resp *http.Response) { assert.Equal(t, http.StatusOK, resp.StatusCode) }}, - {"GET", "/readyz", "", func(t *testing.T, resp *http.Response) { + {"GET", "/readyz", "", func(t *testing.T, req *http.Request, resp *http.Response) { assert.Equal(t, http.StatusOK, resp.StatusCode) }}, - {"GET", "/version", "", func(t *testing.T, resp *http.Response) { + {"GET", "/version", "", func(t *testing.T, req *http.Request, resp *http.Response) { assert.Equal(t, http.StatusOK, resp.StatusCode) details := build.Details{} err := json.NewDecoder(resp.Body).Decode(&details) @@ -64,13 +86,13 @@ func TestProxyRoutes(t *testing.T) { }}, // Default sumdb is sum.golang.org - {"GET", "/sumdb/sum.golang.org/supported", "", func(t *testing.T, resp *http.Response) { + {"GET", "/sumdb/sum.golang.org/supported", "", func(t *testing.T, req *http.Request, resp *http.Response) { assert.Equal(t, http.StatusOK, resp.StatusCode) }}, - {"GET", "/sumdb/sum.rust-lang.org/supported", "", func(t *testing.T, resp *http.Response) { + {"GET", "/sumdb/sum.rust-lang.org/supported", "", func(t *testing.T, req *http.Request, resp *http.Response) { assert.Equal(t, http.StatusNotFound, resp.StatusCode) }}, - {"GET", "/sumdb/sum.golang.org/lookup/github.com/gomods/athens", "", func(t *testing.T, resp *http.Response) { + {"GET", "/sumdb/sum.golang.org/lookup/github.com/gomods/athens", "", func(t *testing.T, req *http.Request, resp *http.Response) { assert.Equal(t, http.StatusForbidden, resp.StatusCode) }}, } @@ -84,7 +106,7 @@ func TestProxyRoutes(t *testing.T) { t.Run(req.RequestURI, func(t *testing.T) { w := httptest.NewRecorder() r.ServeHTTP(w, req) - tc.test(t, w.Result()) + tc.test(t, req, w.Result()) }) } diff --git a/cmd/proxy/actions/home.go b/cmd/proxy/actions/home.go index 94fb545f2..8f41b979e 100644 --- a/cmd/proxy/actions/home.go +++ b/cmd/proxy/actions/home.go @@ -1,9 +1,137 @@ package actions import ( + "errors" + "html/template" "net/http" + "os" + "strings" + + "github.com/gomods/athens/pkg/config" + "github.com/gomods/athens/pkg/log" ) -func proxyHomeHandler(w http.ResponseWriter, r *http.Request) { - _, _ = w.Write([]byte(`"Welcome to The Athens Proxy"`)) +const homepage = ` + +
+GOPROXY={{ .Host }},direct+ {{ if .NoSumPatterns }} +
Use the following GONOSUM environment variable to exclude checksum database:
+GONOSUM={{ .NoSumPatterns }}+ {{ end }} + +
Use the catalog endpoint to get a list of all modules in the proxy
+ +This endpoint returns a list of versions that Athens knows about for acidburn/htp
:
GET {{ .Host }}/github.com/acidburn/htp/@v/list+ +
This endpoint returns information about a specific version of a module:
+GET {{ .Host }}/github.com/acidburn/htp/@v/v1.0.0.info+
This returns JSON with information about v1.0.0. It looks like this: +
{ + "Name": "v1.0.0", + "Short": "v1.0.0", + "Version": "v1.0.0", + "Time": "1972-07-18T12:34:56Z" +}+ +
This endpoint returns the go.mod file for a specific version of a module:
+GET {{ .Host }}/github.com/acidburn/htp/@v/v1.0.0.mod+
This returns the go.mod file for version v1.0.0. If {{ .Host }}/github.com/acidburn/htp version v1.0.0 has no dependencies, the response body would look like this:
+module github.com/acidburn/htp+ +
GET {{ .Host }}/github.com/acidburn/htp/@v/v1.0.0.zip+
This is what it sounds like — it sends back a zip file with the source code for the module in version v1.0.0.
+ +GET {{ .Host }}/github.com/acidburn/htp/@latest+
This endpoint returns the latest version of the module. If the version does not exist it should retrieve the hash of latest commit.
+ + + +` + +func proxyHomeHandler(c *config.Config) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + lggr := log.EntryFromContext(r.Context()) + + templateData := make(map[string]string) + + templateContents := homepage + + // load the template from the file system if it exists, otherwise revert to default + rawTemplateFileContents, err := os.ReadFile(c.HomeTemplatePath) + if err != nil { + if !errors.Is(err, os.ErrNotExist) { + // this is some other error, log it and revert to default + lggr.SystemErr(err) + } + } else { + templateContents = string(rawTemplateFileContents) + } + + // This should be correct in most cases. If it is not, users can supply their own template + templateData["Host"] = r.Host + + // if the host does not have a scheme, add one based on the request + if !strings.HasPrefix(templateData["Host"], "http://") && !strings.HasPrefix(templateData["Host"], "https://") { + if r.TLS != nil { + templateData["Host"] = "https://" + templateData["Host"] + } else { + templateData["Host"] = "http://" + templateData["Host"] + } + } + + templateData["NoSumPatterns"] = strings.Join(c.NoSumPatterns, ",") + + tmp, err := template.New("home").Parse(templateContents) + if err != nil { + lggr.SystemErr(err) + w.WriteHeader(http.StatusInternalServerError) + } + + w.Header().Add("Content-Type", "text/html") + w.WriteHeader(http.StatusOK) + + err = tmp.ExecuteTemplate(w, "home", templateData) + if err != nil { + lggr.SystemErr(err) + w.WriteHeader(http.StatusInternalServerError) + } + } } diff --git a/config.dev.toml b/config.dev.toml index 16f11779c..d04df2fea 100755 --- a/config.dev.toml +++ b/config.dev.toml @@ -169,6 +169,10 @@ BasicAuthUser = "" # Env override: BASIC_AUTH_PASS BasicAuthPass = "" +# A path on disk to a Go HTML template to be used on the homepage +# Env override: ATHENS_HOME_TEMPLATE_PATH +HomeTemplatePath = "/var/lib/athens/home.html" + # Set to true to force an SSL redirect # Env override: PROXY_FORCE_SSL ForceSSL = false diff --git a/docs/content/configuration/home-template.md b/docs/content/configuration/home-template.md new file mode 100644 index 000000000..cbb55a2a8 --- /dev/null +++ b/docs/content/configuration/home-template.md @@ -0,0 +1,101 @@ +--- +title: Home template configuration +description: How to customize the home template +weight: 8 +--- + +As of v0.14.0 Athens ships with a default, minimal HTML home page that advises users on how to connect to the proxy. It factors in whether `GoNoSumPatterns` is configured, and attempts +to build configuration for `GO_PROXY`. It relies on the users request Host header (on HTTP 1.1) or the Authority header (on HTTP 2) as well as whether the request was over TLS to advise +on configuring `GO_PROXY`. Lastly, the homepage provides a quick guide on how users can leverage the Athens API. + +Of course, not all instructions will be this simple. Some installations may be reachable at different addresses in CI than for desktop users. In this case, and others where the default +home page does not make sense it is possible to override the template. + +Do so by configuring `HomeTemplatePath` via the config or `ATHENS_HOME_TEMPLATE_PATH` to a location on disk with a Go HTML template or placing a template file at `/var/lib/athens/home.html`. + +Athens automatically injects the following variables in templates: + +| Setting | Source | +| :------ | :----- | +| `Host` | Built from the request Host (HTTP1) or Authority (HTTP2) header and presence of TLS. Includes ports. | +| `NoSumPatterns` | Comes directly from the configuration. | + +Using these values is done by wrapping them in bracers with a dot prepended. Example: `{{ .Host }}` + +For more advanced formatting read more about [Go HTML templates](https://pkg.go.dev/html/template). + +```html + + + +GOPROXY={{ .Host }},direct+ {{ if .NoSumPatterns }} +
Use the following GONOSUM environment variable to exclude checksum database:
+GONOSUM={{ .NoSumPatterns }}+ {{ end }} + +
Use the catalog endpoint to get a list of all modules in the proxy
+ +This endpoint returns a list of versions that Athens knows about for acidburn/htp
:
GET {{ .Host }}/github.com/acidburn/htp/@v/list+ +
This endpoint returns information about a specific version of a module:
+GET {{ .Host }}/github.com/acidburn/htp/@v/v1.0.0.info+
This returns JSON with information about v1.0.0. It looks like this: +
{ + "Name": "v1.0.0", + "Short": "v1.0.0", + "Version": "v1.0.0", + "Time": "1972-07-18T12:34:56Z" +}+ +
This endpoint returns the go.mod file for a specific version of a module:
+GET {{ .Host }}/github.com/acidburn/htp/@v/v1.0.0.mod+
This returns the go.mod file for version v1.0.0. If {{ .Host }}/github.com/acidburn/htp version v1.0.0 has no dependencies, the response body would look like this:
+module github.com/acidburn/htp+ +
GET {{ .Host }}/github.com/acidburn/htp/@v/v1.0.0.zip+
This is what it sounds like — it sends back a zip file with the source code for the module in version v1.0.0.
+ +GET {{ .Host }}/github.com/acidburn/htp/@latest+
This endpoint returns the latest version of the module. If the version does not exist it should retrieve the hash of latest commit.
+ + + +``` \ No newline at end of file diff --git a/go.sum b/go.sum index 843969e0a..4ce6080d5 100644 --- a/go.sum +++ b/go.sum @@ -687,7 +687,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -771,12 +770,10 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -786,7 +783,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/pkg/config/config.go b/pkg/config/config.go index 35aaccc1d..9f070e5b1 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -42,6 +42,7 @@ type Config struct { UnixSocket string `envconfig:"ATHENS_UNIX_SOCKET"` BasicAuthUser string `envconfig:"BASIC_AUTH_USER"` BasicAuthPass string `envconfig:"BASIC_AUTH_PASS"` + HomeTemplatePath string `envconfig:"ATHENS_HOME_TEMPLATE_PATH"` ForceSSL bool `envconfig:"PROXY_FORCE_SSL"` ValidatorHook string `envconfig:"ATHENS_PROXY_VALIDATOR"` PathPrefix string `envconfig:"ATHENS_PATH_PREFIX"` @@ -157,6 +158,7 @@ func defaultConfig() *Config { PprofPort: ":3001", StatsExporter: "prometheus", TimeoutConf: TimeoutConf{Timeout: 300}, + HomeTemplatePath: "/var/lib/athens/home.html", StorageType: "memory", Port: ":3000", SingleFlightType: "memory", diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index e10a2afbe..c2897b568 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -79,23 +79,24 @@ func TestEnvOverrides(t *testing.T) { TimeoutConf: TimeoutConf{ Timeout: 30, }, - StorageType: "minio", - GlobalEndpoint: "mytikas.gomods.io", - Port: ":7000", - EnablePprof: false, - PprofPort: ":3001", - BasicAuthUser: "testuser", - BasicAuthPass: "testpass", - ForceSSL: true, - ValidatorHook: "testhook.io", - PathPrefix: "prefix", - NETRCPath: "/test/path/.netrc", - HGRCPath: "/test/path/.hgrc", - Storage: &Storage{}, - GoBinaryEnvVars: []string{"GOPROXY=direct"}, - SingleFlight: &SingleFlight{}, - RobotsFile: "robots.txt", - Index: &Index{}, + StorageType: "minio", + GlobalEndpoint: "mytikas.gomods.io", + HomeTemplatePath: "/tmp/athens/home.html", + Port: ":7000", + EnablePprof: false, + PprofPort: ":3001", + BasicAuthUser: "testuser", + BasicAuthPass: "testpass", + ForceSSL: true, + ValidatorHook: "testhook.io", + PathPrefix: "prefix", + NETRCPath: "/test/path/.netrc", + HGRCPath: "/test/path/.hgrc", + Storage: &Storage{}, + GoBinaryEnvVars: []string{"GOPROXY=direct"}, + SingleFlight: &SingleFlight{}, + RobotsFile: "robots.txt", + Index: &Index{}, } envVars := getEnvMap(expConf) @@ -269,6 +270,7 @@ func TestParseExampleConfig(t *testing.T) { StorageType: "memory", NetworkMode: "strict", GlobalEndpoint: "http://localhost:3001", + HomeTemplatePath: "/var/lib/athens/home.html", Port: ":3000", EnablePprof: false, PprofPort: ":3001", @@ -322,6 +324,7 @@ func getEnvMap(config *Config) map[string]string { envVars["BASIC_AUTH_USER"] = config.BasicAuthUser envVars["BASIC_AUTH_PASS"] = config.BasicAuthPass envVars["PROXY_FORCE_SSL"] = strconv.FormatBool(config.ForceSSL) + envVars["ATHENS_HOME_TEMPLATE_PATH"] = config.HomeTemplatePath envVars["ATHENS_PROXY_VALIDATOR"] = config.ValidatorHook envVars["ATHENS_PATH_PREFIX"] = config.PathPrefix envVars["ATHENS_NETRC_PATH"] = config.NETRCPath diff --git a/pkg/download/protocol.go b/pkg/download/protocol.go index b9d5945ee..a6942a9c7 100644 --- a/pkg/download/protocol.go +++ b/pkg/download/protocol.go @@ -298,7 +298,7 @@ func union(list1, list2 []string) []string { func copyContextWithCustomTimeout(ctx context.Context, timeout time.Duration) (context.Context, context.CancelFunc) { ctxCopy, cancel := context.WithTimeout(context.Background(), timeout) - requestid.SetInContext(ctxCopy, requestid.FromContext(ctx)) - log.SetEntryInContext(ctxCopy, log.EntryFromContext(ctx)) + ctxCopy = requestid.SetInContext(ctxCopy, requestid.FromContext(ctx)) + ctxCopy = log.SetEntryInContext(ctxCopy, log.EntryFromContext(ctx)) return ctxCopy, cancel } diff --git a/pkg/download/protocol_test.go b/pkg/download/protocol_test.go index 40134a497..d2f910684 100644 --- a/pkg/download/protocol_test.go +++ b/pkg/download/protocol_test.go @@ -17,6 +17,7 @@ import ( "github.com/gomods/athens/pkg/download/mode" "github.com/gomods/athens/pkg/errors" "github.com/gomods/athens/pkg/index/nop" + "github.com/gomods/athens/pkg/log" "github.com/gomods/athens/pkg/module" "github.com/gomods/athens/pkg/stash" "github.com/gomods/athens/pkg/storage" @@ -495,3 +496,38 @@ func (ml *mockLister) List(ctx context.Context, mod string) (*storage.RevInfo, [ ml.called = true return nil, ml.list, ml.err } + +type testEntry struct { + msg string +} + +var _ log.Entry = &testEntry{} + +func (e *testEntry) Debugf(format string, args ...any) { + e.msg = format +} +func (*testEntry) Infof(format string, args ...any) {} +func (*testEntry) Warnf(format string, args ...any) {} +func (*testEntry) Errorf(format string, args ...any) {} +func (*testEntry) WithFields(fields map[string]any) log.Entry { return nil } +func (*testEntry) SystemErr(err error) {} + +func Test_copyContextWithCustomTimeout(t *testing.T) { + testEntry := &testEntry{} + + // create a context with a logger entry + logctx := log.SetEntryInContext(context.Background(), testEntry) + + // check the log work as expected + log.EntryFromContext(logctx).Debugf("first test") + require.Equal(t, "first test", testEntry.msg) + + // use copyContextWithCustomTimeout to create a new context with a custom timeout, + // and the returned context should have the same logger entry + newCtx, cancel := copyContextWithCustomTimeout(logctx, 10*time.Second) + defer cancel() + + // check the log work as expected + log.EntryFromContext(newCtx).Debugf("second test") + require.Equal(t, "second test", testEntry.msg) +} diff --git a/scripts/service/athens.service b/scripts/service/athens.service index 06de46a39..7d39bb264 100644 --- a/scripts/service/athens.service +++ b/scripts/service/athens.service @@ -14,8 +14,6 @@ Nice=5 User=www-data Group=www-data -Environment=ATHENS_DISK_STORAGE_ROOT=/var/run/athens - ; The full path and the arguments of the command to be executed to start the process. ExecStart=/usr/local/bin/athens -config_file=/etc/athens/config.toml diff --git a/scripts/systemd.sh b/scripts/systemd.sh index 7bb4c2dd4..a877825e5 100755 --- a/scripts/systemd.sh +++ b/scripts/systemd.sh @@ -41,12 +41,6 @@ function doInstallConfig fi sudo mkdir -p /etc/athens sudo install -v -o root -g root -m 644 config.toml /etc/athens - - # if storage is on disk, this is where the database goes (see scripts/service/athens.service) - ATHENS_DISK_STORAGE_ROOT=/var/run/athens - sudo mkdir -p $ATHENS_DISK_STORAGE_ROOT - sudo chown www-data $ATHENS_DISK_STORAGE_ROOT - sudo chgrp www-data $ATHENS_DISK_STORAGE_ROOT } # doInstallBinary copies the Athens binary to /usr/local/bin with the necessary settings. @@ -69,6 +63,9 @@ function doInstallBinary # doInstallSystemd sets up the SystemD service unit. function doInstallSystemd { + local rootPath=$(sed -nr 's/(RootPath) = (".*")/\2/p' /etc/athens/config.toml | xargs) + sed -i "/ReadWritePaths/ s|=.*|=$rootPath|" scripts/service/athens.service + sudo install -v -o root -g root -m 644 scripts/service/athens.service /etc/systemd/system sudo systemctl daemon-reload sudo systemctl enable athens