feat: add SSL provider selection to settings and update config generation
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()}
|
||||
|
||||
Reference in New Issue
Block a user