feat: add HTTPS/TLS support via environment variables

- Add HTTPS_ENABLED, TLS_CERT_FILE, TLS_KEY_FILE environment variables
- Server automatically starts in HTTPS mode when configured
- Falls back to HTTP with warning if certs missing
- WebSocket origins automatically adjust for HTTPS
- Fully backward compatible - defaults to HTTP
- Documented in README and CONFIGURATION.md

Addresses kenrmayfield's request for HTTPS support
This commit is contained in:
Pulse Monitor
2025-08-18 15:29:37 +00:00
parent 5b32f47587
commit d71d085f32
4 changed files with 78 additions and 14 deletions
+18
View File
@@ -253,6 +253,24 @@ Configure email notifications in **Settings → Alerts → Email Destinations**
2. Use your email as username and app password as password
3. Server: smtp-mail.outlook.com, Port: 587, Enable STARTTLS
### HTTPS/TLS Configuration
Enable HTTPS by setting these environment variables:
```bash
# Systemd: sudo systemctl edit pulse-backend
Environment="HTTPS_ENABLED=true"
Environment="TLS_CERT_FILE=/etc/pulse/cert.pem"
Environment="TLS_KEY_FILE=/etc/pulse/key.pem"
# Docker
docker run -d -p 7655:7655 \
-e HTTPS_ENABLED=true \
-e TLS_CERT_FILE=/data/cert.pem \
-e TLS_KEY_FILE=/data/key.pem \
-v pulse_data:/data \
-v /path/to/certs:/data/certs:ro \
rcourtman/pulse:latest
```
For deployment overrides (ports, etc), use environment variables:
```bash
# Systemd: sudo systemctl edit pulse-backend
+34 -12
View File
@@ -82,12 +82,19 @@ func runServer() {
// This will be dynamically set based on the actual request host
allowedOrigins := []string{}
// Add localhost variants for development
allowedOrigins = append(allowedOrigins,
"http://localhost:"+fmt.Sprintf("%d", cfg.FrontendPort),
"http://127.0.0.1:"+fmt.Sprintf("%d", cfg.FrontendPort),
)
// If HTTPS is likely being used, add those too
if cfg.FrontendPort == 443 || cfg.FrontendPort == 8443 {
if cfg.HTTPSEnabled {
allowedOrigins = append(allowedOrigins,
"https://localhost:"+fmt.Sprintf("%d", cfg.FrontendPort),
"https://127.0.0.1:"+fmt.Sprintf("%d", cfg.FrontendPort),
)
} else {
allowedOrigins = append(allowedOrigins,
"http://localhost:"+fmt.Sprintf("%d", cfg.FrontendPort),
"http://127.0.0.1:"+fmt.Sprintf("%d", cfg.FrontendPort),
)
}
// If HTTPS is likely being used based on port, add those too
if !cfg.HTTPSEnabled && (cfg.FrontendPort == 443 || cfg.FrontendPort == 8443) {
allowedOrigins = append(allowedOrigins,
"https://localhost:"+fmt.Sprintf("%d", cfg.FrontendPort),
"https://127.0.0.1:"+fmt.Sprintf("%d", cfg.FrontendPort),
@@ -140,12 +147,27 @@ func runServer() {
// Start server
go func() {
log.Info().
Str("host", cfg.BackendHost).
Int("port", cfg.FrontendPort).
Msg("Server listening")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal().Err(err).Msg("Failed to start server")
if cfg.HTTPSEnabled && cfg.TLSCertFile != "" && cfg.TLSKeyFile != "" {
log.Info().
Str("host", cfg.BackendHost).
Int("port", cfg.FrontendPort).
Str("protocol", "HTTPS").
Msg("Server listening")
if err := srv.ListenAndServeTLS(cfg.TLSCertFile, cfg.TLSKeyFile); err != nil && err != http.ErrServerClosed {
log.Fatal().Err(err).Msg("Failed to start HTTPS server")
}
} else {
if cfg.HTTPSEnabled {
log.Warn().Msg("HTTPS_ENABLED is true but TLS_CERT_FILE or TLS_KEY_FILE not configured, falling back to HTTP")
}
log.Info().
Str("host", cfg.BackendHost).
Int("port", cfg.FrontendPort).
Str("protocol", "HTTP").
Msg("Server listening")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal().Err(err).Msg("Failed to start HTTP server")
}
}
}()
+7 -2
View File
@@ -120,12 +120,17 @@ For backwards compatibility, some settings can be overridden via environment var
- `BACKEND_HOST` - IP address to bind to (default: `0.0.0.0`)
- Set to `127.0.0.1` or `localhost` to only listen on localhost (for reverse proxy)
- `FRONTEND_PORT` - Port to listen on (default: `7655`)
3. **HTTPS/TLS variables** - For enabling HTTPS
- `HTTPS_ENABLED` - Set to `true` to enable HTTPS (default: `false`)
- `TLS_CERT_FILE` - Path to TLS certificate file (e.g., `/etc/pulse/cert.pem`)
- `TLS_KEY_FILE` - Path to TLS private key file (e.g., `/etc/pulse/key.pem`)
3. **System settings (from system.json)** - Normal priority
4. **System settings (from system.json)** - Normal priority
- If system.json exists, it takes precedence
- If missing, environment variables are checked
4. **Legacy environment variables** - Lowest priority (deprecated)
5. **Legacy environment variables** - Lowest priority (deprecated)
- `POLLING_INTERVAL` - Only used if system.json doesn't exist
- `CONNECTION_TIMEOUT` - Can override system.json value
- `ALLOWED_ORIGINS` - Can override system.json value
+19
View File
@@ -88,6 +88,11 @@ type Config struct {
AuthPass string `envconfig:"PULSE_AUTH_PASS"`
AllowedOrigins string `envconfig:"ALLOWED_ORIGINS" default:"*"`
IframeEmbeddingAllow string `envconfig:"IFRAME_EMBEDDING_ALLOW" default:"SAMEORIGIN"`
// HTTPS/TLS settings
HTTPSEnabled bool `envconfig:"HTTPS_ENABLED" default:"false"`
TLSCertFile string `envconfig:"TLS_CERT_FILE" default:""`
TLSKeyFile string `envconfig:"TLS_KEY_FILE" default:""`
// Update settings
UpdateChannel string `envconfig:"UPDATE_CHANNEL" default:"stable"`
@@ -346,6 +351,20 @@ func Load() (*Config, error) {
}
log.Debug().Bool("is_hashed", IsPasswordHashed(authPass)).Msg("Loaded auth password from env var")
}
// HTTPS/TLS configuration from environment
if httpsEnabled := os.Getenv("HTTPS_ENABLED"); httpsEnabled != "" {
cfg.HTTPSEnabled = httpsEnabled == "true" || httpsEnabled == "1"
log.Debug().Bool("enabled", cfg.HTTPSEnabled).Msg("HTTPS enabled status from env var")
}
if tlsCertFile := os.Getenv("TLS_CERT_FILE"); tlsCertFile != "" {
cfg.TLSCertFile = tlsCertFile
log.Debug().Str("cert_file", tlsCertFile).Msg("TLS cert file from env var")
}
if tlsKeyFile := os.Getenv("TLS_KEY_FILE"); tlsKeyFile != "" {
cfg.TLSKeyFile = tlsKeyFile
log.Debug().Str("key_file", tlsKeyFile).Msg("TLS key file from env var")
}
// REMOVED: Update channel, auto-update, connection timeout, and allowed origins env vars
// These settings now ONLY come from system.json to prevent confusion
// Only keeping essential deployment/infrastructure env vars