feat: add SSL provider selection to settings and update config generation

This commit is contained in:
Wikid82
2025-11-22 22:22:22 -05:00
parent e66db3c27f
commit 155bedcf66
6 changed files with 63 additions and 20 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ func TestClient_Load_Success(t *testing.T) {
ForwardPort: 8080,
Enabled: true,
},
}, "/tmp/caddy-data", "admin@example.com", "")
}, "/tmp/caddy-data", "admin@example.com", "", "")
err := client.Load(context.Background(), config)
require.NoError(t, err)
+25 -10
View File
@@ -10,7 +10,7 @@ import (
// GenerateConfig creates a Caddy JSON configuration from proxy hosts.
// This is the core transformation layer from our database model to Caddy config.
func GenerateConfig(hosts []models.ProxyHost, storageDir string, acmeEmail string, frontendDir string) (*Config, error) {
func GenerateConfig(hosts []models.ProxyHost, storageDir string, acmeEmail string, frontendDir string, sslProvider string) (*Config, error) {
// Define log file paths
// We assume storageDir is like ".../data/caddy/data", so we go up to ".../data/logs"
// storageDir is .../data/caddy/data
@@ -51,19 +51,34 @@ func GenerateConfig(hosts []models.ProxyHost, storageDir string, acmeEmail strin
}
if acmeEmail != "" {
var issuers []interface{}
// Configure issuers based on provider preference
switch sslProvider {
case "letsencrypt":
issuers = append(issuers, map[string]interface{}{
"module": "acme",
"email": acmeEmail,
})
case "zerossl":
issuers = append(issuers, map[string]interface{}{
"module": "zerossl",
})
default: // "both" or empty
issuers = append(issuers, map[string]interface{}{
"module": "acme",
"email": acmeEmail,
})
issuers = append(issuers, map[string]interface{}{
"module": "zerossl",
})
}
config.Apps.TLS = &TLSApp{
Automation: &AutomationConfig{
Policies: []*AutomationPolicy{
{
IssuersRaw: []interface{}{
map[string]interface{}{
"module": "acme",
"email": acmeEmail,
},
map[string]interface{}{
"module": "zerossl",
},
},
IssuersRaw: issuers,
},
},
},
+7 -7
View File
@@ -9,7 +9,7 @@ import (
)
func TestGenerateConfig_Empty(t *testing.T) {
config, err := GenerateConfig([]models.ProxyHost{}, "/tmp/caddy-data", "admin@example.com", "")
config, err := GenerateConfig([]models.ProxyHost{}, "/tmp/caddy-data", "admin@example.com", "", "")
require.NoError(t, err)
require.NotNil(t, config)
require.NotNil(t, config.Apps.HTTP)
@@ -31,7 +31,7 @@ func TestGenerateConfig_SingleHost(t *testing.T) {
},
}
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "")
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "")
require.NoError(t, err)
require.NotNil(t, config)
require.NotNil(t, config.Apps.HTTP)
@@ -71,7 +71,7 @@ func TestGenerateConfig_MultipleHosts(t *testing.T) {
},
}
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "")
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "")
require.NoError(t, err)
require.Len(t, config.Apps.HTTP.Servers["cpm_server"].Routes, 2)
}
@@ -88,7 +88,7 @@ func TestGenerateConfig_WebSocketEnabled(t *testing.T) {
},
}
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "")
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "")
require.NoError(t, err)
route := config.Apps.HTTP.Servers["cpm_server"].Routes[0]
@@ -109,7 +109,7 @@ func TestGenerateConfig_EmptyDomain(t *testing.T) {
},
}
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "")
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "")
require.NoError(t, err)
// Should produce empty routes (or just catch-all if frontendDir was set, but it's empty here)
require.Empty(t, config.Apps.HTTP.Servers["cpm_server"].Routes)
@@ -117,7 +117,7 @@ func TestGenerateConfig_EmptyDomain(t *testing.T) {
func TestGenerateConfig_Logging(t *testing.T) {
hosts := []models.ProxyHost{}
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "")
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "")
require.NoError(t, err)
// Verify logging configuration
@@ -155,7 +155,7 @@ func TestGenerateConfig_Advanced(t *testing.T) {
},
}
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "")
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "")
require.NoError(t, err)
require.NotNil(t, config)
+8 -1
View File
@@ -48,8 +48,15 @@ func (m *Manager) ApplyConfig(ctx context.Context) error {
acmeEmail = acmeEmailSetting.Value
}
// Fetch SSL Provider setting
var sslProviderSetting models.Setting
var sslProvider string
if err := m.db.Where("key = ?", "caddy.ssl_provider").First(&sslProviderSetting).Error; err == nil {
sslProvider = sslProviderSetting.Value
}
// Generate Caddy config
config, err := GenerateConfig(hosts, filepath.Join(m.configDir, "data"), acmeEmail, m.frontendDir)
config, err := GenerateConfig(hosts, filepath.Join(m.configDir, "data"), acmeEmail, m.frontendDir, sslProvider)
if err != nil {
return fmt.Errorf("generate config: %w", err)
}
+1 -1
View File
@@ -25,7 +25,7 @@ func TestValidate_ValidConfig(t *testing.T) {
},
}
config, _ := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "")
config, _ := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "")
err := Validate(config)
require.NoError(t, err)
}
+21
View File
@@ -26,6 +26,7 @@ interface UpdateInfo {
export default function SystemSettings() {
const queryClient = useQueryClient()
const [caddyAdminAPI, setCaddyAdminAPI] = useState('http://localhost:2019')
const [sslProvider, setSslProvider] = useState('letsencrypt')
// Fetch Settings
const { data: settings } = useQuery({
@@ -37,6 +38,7 @@ export default function SystemSettings() {
useEffect(() => {
if (settings) {
if (settings['caddy.admin_api']) setCaddyAdminAPI(settings['caddy.admin_api'])
if (settings['caddy.ssl_provider']) setSslProvider(settings['caddy.ssl_provider'])
}
}, [settings])
@@ -66,6 +68,7 @@ export default function SystemSettings() {
const saveSettingsMutation = useMutation({
mutationFn: async () => {
await updateSetting('caddy.admin_api', caddyAdminAPI, 'caddy', 'string')
await updateSetting('caddy.ssl_provider', sslProvider, 'caddy', 'string')
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['settings'] })
@@ -97,6 +100,24 @@ export default function SystemSettings() {
<p className="text-sm text-gray-500 dark:text-gray-400 -mt-2">
URL to the Caddy admin API (usually on port 2019)
</p>
<div className="w-full">
<label className="block text-sm font-medium text-gray-300 mb-1.5">
SSL Provider
</label>
<select
value={sslProvider}
onChange={(e) => setSslProvider(e.target.value)}
className="w-full bg-gray-900 border border-gray-700 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
>
<option value="letsencrypt">Let's Encrypt (Default)</option>
<option value="zerossl">ZeroSSL</option>
</select>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
Choose the default Certificate Authority for SSL certificates.
</p>
</div>
<div className="flex justify-end">
<Button
onClick={() => saveSettingsMutation.mutate()}