Skip to content

Commit de0b580

Browse files
committed
Added winget install instructions
1 parent a6dbdae commit de0b580

8 files changed

Lines changed: 243 additions & 62 deletions

File tree

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,17 @@ brew services start openrun
228228

229229
To install on Windows, run
230230

231+
```
232+
winget install OpenRunDev.OpenRun
233+
```
234+
235+
or use the install script:
236+
231237
```
232238
powershell -Command "irm https://openrun.dev/install.ps1 | iex"
233239
```
234240

235-
Start a new command window (to get the updated env) and run `openrun server start` to start the OpenRun service.
241+
Start a new command window (to get the updated env) and run `openrun server start` to start the OpenRun service. On the first start, OpenRun generates an admin password and prints it; note it down.
236242

237243
### Kubernetes Install
238244

cmd/openrun/main.go

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ func globalFlags(globalConfig *types.GlobalConfig, clientConfig *types.ClientCon
7474
// Uses OPENRUN_HOME env if set. Otherwise uses binaries parent path. Setting OPENRUN_HOME is
7575
// the easiest way to configure. Uses some extra heuristics to help avoid having to setup
7676
// OPENRUN_HOME in the env, by using the binaries parent folder as the default.
77-
// On mac, looks for brew install locations also.
78-
func getConfigPath(cCtx *cli.Context) (string, string, bool, error) {
77+
// On mac, looks for brew install locations also. When nothing is found, falls back to
78+
// $HOME/openrun (the install script default), with homeDefaulted set to true.
79+
func getConfigPath(cCtx *cli.Context) (clHomeRet, configFileRet string, clHomeEnvSet, homeDefaulted bool, errRet error) {
7980
configFile := cCtx.String(configFileFlagName)
8081
clHome := os.Getenv(types.OPENRUN_HOME)
8182
if configFile == "" {
@@ -86,21 +87,21 @@ func getConfigPath(cCtx *cli.Context) (string, string, bool, error) {
8687
}
8788
if clHome != "" {
8889
// Found OPENRUN_HOME
89-
return clHome, configFile, true, nil
90+
return clHome, configFile, true, false, nil
9091
}
9192
if configFile != "" {
9293
// OPENRUN_HOME not set and config file is set, use config dir path as OPENRUN_HOME
9394
clHome = filepath.Dir(configFile)
94-
return clHome, configFile, false, nil
95+
return clHome, configFile, false, false, nil
9596
}
9697

9798
binFile, err := os.Executable()
9899
if err != nil {
99-
return "", "", false, fmt.Errorf("unable to find executable path: %w", err)
100+
return "", "", false, false, fmt.Errorf("unable to find executable path: %w", err)
100101
}
101102
binAbsolute, err := filepath.EvalSymlinks(binFile)
102103
if err != nil {
103-
return "", "", false, fmt.Errorf("unable to resolve symlink: %w", err)
104+
return "", "", false, false, fmt.Errorf("unable to resolve symlink: %w", err)
104105
}
105106

106107
binParent := filepath.Dir(binAbsolute)
@@ -112,34 +113,43 @@ func getConfigPath(cCtx *cli.Context) (string, string, bool, error) {
112113
if system.FileExists(binParentConfig) && (strings.Contains(binParent, "openrun") || strings.Contains(binParent, "clhome")) {
113114
// Config file found in parent directory of the executable, use that as path
114115
// To avoid clobbering /usr, check if the path contains the string openrun/clhome
115-
return binParent, binParentConfig, false, nil
116+
return binParent, binParentConfig, false, false, nil
116117
}
117118

118119
// Running `brew --prefix` would be another option
119120
if runtime.GOOS == "darwin" { //nolint:staticcheck
120121
// brew OSX specific checks
121122
if system.FileExists("/opt/homebrew/etc/openrun.toml") {
122-
return "/opt/homebrew/var/openrun", "/opt/homebrew/etc/openrun.toml", false, nil
123+
return "/opt/homebrew/var/openrun", "/opt/homebrew/etc/openrun.toml", false, false, nil
123124
} else if system.FileExists("/usr/local/etc/openrun.toml") {
124-
return "/usr/local/var/openrun", "/usr/local/etc/openrun.toml", false, nil
125+
return "/usr/local/var/openrun", "/usr/local/etc/openrun.toml", false, false, nil
125126
}
126127
} else if runtime.GOOS == "linux" {
127128
// brew linux specific checks
128129
if system.FileExists("/home/linuxbrew/.linuxbrew/etc/openrun.toml") {
129-
return "/home/linuxbrew/.linuxbrew/var/openrun", "/home/linuxbrew/.linuxbrew/etc/openrun.toml", false, nil
130+
return "/home/linuxbrew/.linuxbrew/var/openrun", "/home/linuxbrew/.linuxbrew/etc/openrun.toml", false, false, nil
130131
} else if system.FileExists("/usr/local/etc/openrun.toml") {
131-
return "/usr/local/var/openrun", "/usr/local/etc/openrun.toml", false, nil
132+
return "/usr/local/var/openrun", "/usr/local/etc/openrun.toml", false, false, nil
132133
} else if system.FileExists("/var/lib/openrun/openrun.toml") {
133134
// Linux system level installation
134-
return "/var/lib/openrun", "/var/lib/openrun/openrun.toml", false, nil
135+
return "/var/lib/openrun", "/var/lib/openrun/openrun.toml", false, false, nil
135136
}
136137
}
137-
return "", "", false, fmt.Errorf("unable to find OPENRUN_HOME or config file")
138+
139+
// Nothing configured or discovered: default to $HOME/openrun, the same
140+
// location the install scripts use. Package managers like winget cannot
141+
// run an install script, so this is the normal path for such installs
142+
homeDir, err := os.UserHomeDir()
143+
if err != nil {
144+
return "", "", false, false, fmt.Errorf("unable to find OPENRUN_HOME or config file: %w", err)
145+
}
146+
defaultHome := filepath.Join(homeDir, "openrun")
147+
return defaultHome, filepath.Join(defaultHome, "openrun.toml"), false, true, nil
138148
}
139149

140150
func parseConfig(cCtx *cli.Context, globalConfig *types.GlobalConfig, clientConfig *types.ClientConfig, serverConfig *types.ServerConfig) error {
141151
// Find OPENRUN_HOME and config file, update OPENRUN_HOME in env
142-
clHome, filePath, clHomeEnvSet, err := getConfigPath(cCtx)
152+
clHome, filePath, clHomeEnvSet, homeDefaulted, err := getConfigPath(cCtx)
143153
if err != nil {
144154
return err
145155
}
@@ -149,13 +159,37 @@ func parseConfig(cCtx *cli.Context, globalConfig *types.GlobalConfig, clientConf
149159
}
150160
os.Setenv(types.OPENRUN_HOME, clHome) //nolint:errcheck
151161

162+
if homeDefaulted && !system.FileExists(filePath) {
163+
if system.IsRunningAsService() {
164+
// The default home resolves to the service account profile (e.g.
165+
// C:\Windows\System32\config\systemprofile), not the installing
166+
// user's home, and a bootstrapped admin password would be printed
167+
// where nobody can see it. Fail fast instead of silently creating
168+
// a second config under the service profile
169+
return fmt.Errorf("no config file found (looked for %s): when running as an OS service, set OPENRUN_HOME in the service environment or register the service with --config-file", filePath)
170+
}
171+
if cCtx.Args().Get(0) == "server" && cCtx.Args().Get(1) == "start" {
172+
// First server start with no config setup (e.g. installed through
173+
// winget, which cannot run the install script): initialize the
174+
// config with a generated admin password, like the install scripts do
175+
if err := bootstrapConfigFile(clHome, filePath); err != nil {
176+
return err
177+
}
178+
}
179+
}
180+
152181
//fmt.Fprintf(os.Stderr, "Loading config file: %s, clHome %s\n", filePath, clHome)
153182
buf, err := os.ReadFile(filePath)
154183
if err != nil {
155184
if clHomeEnvSet {
156185
fmt.Fprintf(os.Stderr, "Warning: unable to read config file %s, using default config\n", err)
157186
return nil
158187
}
188+
if homeDefaulted {
189+
// No install setup found anywhere; run with the default config so
190+
// commands like help and version work without any setup
191+
return nil
192+
}
159193
return err
160194
}
161195

cmd/openrun/misc_cmds.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,31 @@ func generatePassword(cCtx *cli.Context) error {
7676
return nil
7777
}
7878

79+
// bootstrapConfigFile creates the OPENRUN_HOME directory and an initial config
80+
// file with a generated admin password, mirroring what the install scripts do.
81+
// Used on the first server start when no config setup was found.
82+
func bootstrapConfigFile(clHome, configFile string) error {
83+
if err := os.MkdirAll(clHome, 0o755); err != nil {
84+
return fmt.Errorf("unable to create OPENRUN_HOME %s: %w", clHome, err)
85+
}
86+
password, err := passwd.GeneratePassword()
87+
if err != nil {
88+
return err
89+
}
90+
bcryptPassword, err := bcrypt.GenerateFromPassword([]byte(password), passwd.BCRYPT_COST)
91+
if err != nil {
92+
return err
93+
}
94+
contents := fmt.Sprintf("# Generated by openrun on first server start\n[security]\nadmin_password_bcrypt = \"%s\"\n", bcryptPassword)
95+
if err := os.WriteFile(configFile, []byte(contents), 0o600); err != nil {
96+
return fmt.Errorf("unable to create config file %s: %w", configFile, err)
97+
}
98+
fmt.Fprintf(os.Stderr, "First run: created config file %s\n", configFile)
99+
fmt.Fprintf(os.Stderr, "Generated admin password: %s\n", password)
100+
fmt.Fprintf(os.Stderr, "Save this password, it will not be shown again. Login with username \"admin\".\n\n")
101+
return nil
102+
}
103+
79104
func promptPassword(prompt string) (string, error) {
80105
fmt.Print(prompt)
81106
password, err := readPassword()

docs/content/docs/Installation.md

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,21 @@ Apps are not affected: app containers keep running through the restart. In-place
9292

9393
## Install On Windows
9494

95-
To install the OpenRun application on Windows, run:
95+
To install OpenRun using [winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), run:
96+
97+
```powershell
98+
winget install OpenRunDev.OpenRun
99+
```
100+
101+
Open a new terminal so `openrun` is on the PATH, then run:
102+
103+
```powershell
104+
openrun server start
105+
```
106+
107+
On the first server start, OpenRun creates its config file under `$HOME\openrun` (or `$env:OPENRUN_HOME` if set) and generates an admin password. Note down the password printed.
108+
109+
Alternatively, install using the install script:
96110

97111
```powershell
98112
powershell -Command "irm https://openrun.dev/install.ps1 | iex"
@@ -115,12 +129,48 @@ sc.exe failure openrun reset= 86400 actions= restart/5000/restart/30000//
115129
sc.exe start openrun
116130
```
117131

118-
The paths from `$env:OPENRUN_HOME` are expanded when the service is created; re-create the service if the install location changes. The service runs as LocalSystem by default; for a network facing server, consider a less privileged account using `sc.exe config openrun obj= <account>`.
132+
The paths from `$env:OPENRUN_HOME` are expanded when the service is created; re-create the service if the install location changes. For winget installs, see [Winget Service Install](#winget-service-install) below. The service runs as LocalSystem by default; for a network facing server, consider a less privileged account using `sc.exe config openrun obj= <account>`.
119133

120134
When started this way, OpenRun reports service status to Windows and handles service stop, shutdown and pre-shutdown requests as graceful server shutdowns.
121135

122136
Open https://localhost:25223 to access the app listing UI.
123137

138+
### Winget Service Install
139+
140+
To run OpenRun as a Windows service on a machine where it was installed with winget, the recommended approach is a machine scoped install with the service registered against an explicit config file. From an elevated shell:
141+
142+
```powershell
143+
winget install --scope machine OpenRunDev.OpenRun
144+
```
145+
146+
Machine scope installs the binary under `Program Files\WinGet` instead of the installing user's profile, which is preferable for a service. Open a new elevated terminal so `openrun` is on the PATH, then create the config file with a generated admin password:
147+
148+
```powershell
149+
New-Item -ItemType Directory -Force C:\ProgramData\openrun | Out-Null
150+
openrun password | Out-File -Encoding utf8 C:\ProgramData\openrun\openrun.toml
151+
```
152+
153+
Note down the password printed. Then register and start the service:
154+
155+
```powershell
156+
$OpenRunExe = (Get-Command openrun.exe).Source
157+
$OpenRunConfig = 'C:\ProgramData\openrun\openrun.toml'
158+
sc.exe create openrun start= auto DisplayName= "OpenRun" binPath= "`"$OpenRunExe`" --config-file `"$OpenRunConfig`" server start"
159+
sc.exe description openrun "OpenRun application server https://openrun.dev/"
160+
sc.exe failure openrun reset= 86400 actions= restart/5000/restart/30000//
161+
sc.exe start openrun
162+
```
163+
164+
Passing `--config-file` pins the server home directory to the config file's directory (`C:\ProgramData\openrun` here), keeping the service independent of any user profile. Without it, a service would resolve its home under the service account profile (for LocalSystem, `C:\Windows\System32\config\systemprofile`), and OpenRun refuses to auto-create a config there. To use the `openrun` CLI against this server from a regular shell, set the env variable at machine scope so the CLI resolves the same home:
165+
166+
```powershell
167+
[Environment]::SetEnvironmentVariable('OPENRUN_HOME', 'C:\ProgramData\openrun', 'Machine')
168+
```
169+
170+
For a default user scoped winget install, keep everything under the user profile instead: run `openrun server start` once interactively to create `$HOME\openrun\openrun.toml` (note down the generated admin password), stop it with Ctrl+C, then register the service with `$OpenRunConfig = Join-Path $HOME 'openrun\openrun.toml'` in the `sc.exe create` command above. No env variable is needed in this setup: the CLI defaults to the same `$HOME\openrun` home.
171+
172+
In both flows, `(Get-Command openrun.exe).Source` resolves to the winget links shim, which stays valid across `winget upgrade`; after an upgrade, run `sc.exe stop openrun` and `sc.exe start openrun` to switch to the new binary.
173+
124174
## Brew Install
125175

126176
To install using [brew](https://brew.sh/), run

docs/content/docs/QuickStart.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,17 @@ brew services start openrun
3232

3333
To install on Windows, run
3434

35+
```
36+
winget install OpenRunDev.OpenRun
37+
```
38+
39+
or use the install script:
40+
3541
```
3642
powershell -Command "irm https://openrun.dev/install.ps1 | iex"
3743
```
3844

39-
Start a new command window (to get the updated env) and run `openrun server start` to start the OpenRun service.
45+
Start a new command window (to get the updated env) and run `openrun server start` to start the OpenRun service. On the first start, OpenRun generates an admin password and prints it; note it down.
4046

4147
### Install Apps
4248

0 commit comments

Comments
 (0)