added opt-in managed nginx/TLS container (ADR 0005, plan step 13): server.nginx.* config serves GitTally over HTTPS on hosts without a reverse proxy — two-phase startup (ACME webroot via certbot container, then full HTTPS config), daily certificate renewal with nginx reload, labelled container removed on shutdown; all failures are non-fatal, the plain HTTP server keeps running
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
fdbbd0516a
commit
b104eeee05
@@ -21,11 +21,24 @@ class ConfigLoader {
|
||||
|
||||
fun load(workingDir: Path = Paths.get(".")): GitTallyConfig {
|
||||
val raw = loadRaw(workingDir)
|
||||
return if (raw.isEmpty()) {
|
||||
GitTallyConfig()
|
||||
} else {
|
||||
yaml.convertValue(mergeBranchDefaults(raw), GitTallyConfig::class.java)
|
||||
val config =
|
||||
if (raw.isEmpty()) {
|
||||
GitTallyConfig()
|
||||
} else {
|
||||
yaml.convertValue(mergeBranchDefaults(raw), GitTallyConfig::class.java)
|
||||
}
|
||||
return defaultPublicBaseUrl(config)
|
||||
}
|
||||
|
||||
/** Legacy default: an empty `server.publicBaseUrl` becomes `https://<nginx.serverName>/`. */
|
||||
private fun defaultPublicBaseUrl(config: GitTallyConfig): GitTallyConfig {
|
||||
if (config.server.publicBaseUrl.isNotBlank() ||
|
||||
config.server.nginx.serverName
|
||||
.isBlank()
|
||||
) {
|
||||
return config
|
||||
}
|
||||
return config.copy(server = config.server.copy(publicBaseUrl = "https://${config.server.nginx.serverName}/"))
|
||||
}
|
||||
|
||||
fun loadRaw(workingDir: Path = Paths.get(".")): Map<String, Any?> {
|
||||
|
||||
@@ -11,12 +11,44 @@ data class GitTallyConfig(
|
||||
)
|
||||
|
||||
data class ServerConfig(
|
||||
/**
|
||||
* Public base URL of this installation; empty defaults to `https://<nginx.serverName>/`
|
||||
* when [NginxConfig.serverName] is set (applied by [ConfigLoader]).
|
||||
*/
|
||||
val publicBaseUrl: String = "",
|
||||
/** HTTP port of the `server` subcommand; 18080 like the legacy artifact server. */
|
||||
val port: Int = 18080,
|
||||
val bindAddress: String = "0.0.0.0",
|
||||
/** Optional Impressum (legal disclosure) link shown in the web UI footer; empty hides the link. */
|
||||
val impressumUrl: String = "",
|
||||
val nginx: NginxConfig = NginxConfig(),
|
||||
)
|
||||
|
||||
/**
|
||||
* Opt-in managed nginx+certbot Docker container serving GitTally over HTTPS,
|
||||
* for hosts without a usable reverse proxy (ADR 0005). Off by default; the
|
||||
* reverse-proxy deployment from `docs/deployment.md` stays the recommended setup.
|
||||
*/
|
||||
data class NginxConfig(
|
||||
/** Manage an nginx Docker container with Let's Encrypt certificates. */
|
||||
val enabled: Boolean = false,
|
||||
/** Public DNS name served by nginx and used for the certificate; required when [enabled]. */
|
||||
val serverName: String = "",
|
||||
/** Host port published as nginx port 80 (ACME challenge + HTTPS redirect). */
|
||||
val httpPort: Int = 8080,
|
||||
/** Host port published as nginx port 443. */
|
||||
val httpsPort: Int = 8443,
|
||||
/** Host nginx proxies to; empty uses [serverName] (the container cannot reach `localhost`). */
|
||||
val upstreamHost: String = "",
|
||||
/** Name of the managed container; empty means `gittally-nginx-<repo-name>`. */
|
||||
val containerName: String = "",
|
||||
/**
|
||||
* Directory for nginx config, certificates, and logs; empty means the platform
|
||||
* default `XDG_STATE_HOME` (or `~/.local/state`) + `/gittally/nginx/<repo-key>`.
|
||||
*/
|
||||
val stateDir: String = "",
|
||||
/** E-mail for the Let's Encrypt account; empty registers without one. */
|
||||
val letsencryptEmail: String = "",
|
||||
)
|
||||
|
||||
data class GitConfig(
|
||||
|
||||
Reference in New Issue
Block a user