feat: Add SSL external option for Pages custom domains
Some checks failed
Build and Release / Create Release (push) Has been skipped
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 1m37s
Build and Release / Unit Tests (push) Successful in 1m54s
Build and Release / Lint (push) Failing after 1m58s
Build and Release / Build Binaries (amd64, darwin) (push) Has been skipped
Build and Release / Build Binaries (amd64, linux) (push) Has been skipped
Build and Release / Build Binaries (amd64, windows) (push) Has been skipped
Build and Release / Build Binaries (arm64, darwin) (push) Has been skipped
Build and Release / Build Binaries (arm64, linux) (push) Has been skipped

- Add checkbox to mark SSL as handled externally (e.g., Cloudflare)
- Add Activate SSL button for verified domains with pending SSL
- Add SSLExternal option to API
- Useful when using CDN/reverse proxy that handles SSL certificates
This commit is contained in:
Claude Code 2026-01-11 00:35:58 +01:00
parent 84adad19bf
commit 7292421334
7 changed files with 52 additions and 4 deletions

View File

@ -142,6 +142,12 @@ func UpdatePagesDomain(ctx context.Context, domain *PagesDomain) error {
return err return err
} }
// ActivatePagesDomainSSL sets SSL status to active for a domain
func ActivatePagesDomainSSL(ctx context.Context, id int64) error {
_, err := db.GetEngine(ctx).ID(id).Cols("ssl_status").Update(&PagesDomain{SSLStatus: SSLStatusActive})
return err
}
// DeletePagesDomain deletes a pages domain // DeletePagesDomain deletes a pages domain
func DeletePagesDomain(ctx context.Context, id int64) error { func DeletePagesDomain(ctx context.Context, id int64) error {
_, err := db.GetEngine(ctx).ID(id).Delete(new(PagesDomain)) _, err := db.GetEngine(ctx).ID(id).Delete(new(PagesDomain))

View File

@ -38,6 +38,8 @@ type AddPagesDomainOption struct {
// The custom domain to add // The custom domain to add
// required: true // required: true
Domain string `json:"domain" binding:"Required"` Domain string `json:"domain" binding:"Required"`
// Mark SSL as handled externally (e.g., by Cloudflare)
SSLExternal bool `json:"ssl_external"`
} }
// PagesInfo represents the full pages information for a repository // PagesInfo represents the full pages information for a repository

View File

@ -2536,6 +2536,10 @@
"repo.settings.pages.pending": "Pending", "repo.settings.pages.pending": "Pending",
"repo.settings.pages.ssl_active": "Active", "repo.settings.pages.ssl_active": "Active",
"repo.settings.pages.ssl_pending": "Pending", "repo.settings.pages.ssl_pending": "Pending",
"repo.settings.pages.ssl_external": "SSL handled externally (e.g., Cloudflare)",
"repo.settings.pages.ssl_external_desc": "Check this if SSL is managed by a CDN or reverse proxy like Cloudflare",
"repo.settings.pages.activate_ssl": "Activate SSL",
"repo.settings.pages.ssl_activated": "SSL has been activated for this domain",
"repo.settings.pages.ssl_none": "None", "repo.settings.pages.ssl_none": "None",
"repo.settings.pages.verify": "Verify", "repo.settings.pages.verify": "Verify",
"repo.settings.pages.verify_dns_hint": "Add the following TXT record to your DNS to verify domain ownership:", "repo.settings.pages.verify_dns_hint": "Add the following TXT record to your DNS to verify domain ownership:",

View File

@ -219,7 +219,7 @@ func AddPagesDomain(ctx *context.APIContext) {
form := web.GetForm(ctx).(*api.AddPagesDomainOption) form := web.GetForm(ctx).(*api.AddPagesDomainOption)
domain, err := pages_service.AddPagesDomain(ctx, ctx.Repo.Repository.ID, form.Domain) domain, err := pages_service.AddPagesDomain(ctx, ctx.Repo.Repository.ID, form.Domain, form.SSLExternal)
if err != nil { if err != nil {
if repo_model.IsErrPagesDomainAlreadyExist(err) { if repo_model.IsErrPagesDomainAlreadyExist(err) {
ctx.APIError(http.StatusUnprocessableEntity, "Domain already exists") ctx.APIError(http.StatusUnprocessableEntity, "Domain already exists")

View File

@ -92,7 +92,8 @@ func PagesPost(ctx *context.Context) {
ctx.Redirect(ctx.Repo.Repository.Link() + "/settings/pages") ctx.Redirect(ctx.Repo.Repository.Link() + "/settings/pages")
return return
} }
_, err := pages_service.AddPagesDomain(ctx, ctx.Repo.Repository.ID, domain) sslExternal := ctx.FormBool("ssl_external")
_, err := pages_service.AddPagesDomain(ctx, ctx.Repo.Repository.ID, domain, sslExternal)
if err != nil { if err != nil {
if repo_model.IsErrPagesDomainAlreadyExist(err) { if repo_model.IsErrPagesDomainAlreadyExist(err) {
ctx.Flash.Error(ctx.Tr("repo.settings.pages.domain_exists")) ctx.Flash.Error(ctx.Tr("repo.settings.pages.domain_exists"))
@ -112,6 +113,14 @@ func PagesPost(ctx *context.Context) {
} }
ctx.Flash.Success(ctx.Tr("repo.settings.pages.domain_deleted")) ctx.Flash.Success(ctx.Tr("repo.settings.pages.domain_deleted"))
case "activate_ssl":
domainID := ctx.FormInt64("domain_id")
if err := repo_model.ActivatePagesDomainSSL(ctx, domainID); err != nil {
ctx.ServerError("ActivatePagesDomainSSL", err)
return
}
ctx.Flash.Success(ctx.Tr("repo.settings.pages.ssl_activated"))
case "verify_domain": case "verify_domain":
domainID := ctx.FormInt64("domain_id") domainID := ctx.FormInt64("domain_id")
if err := pages_service.VerifyDomain(ctx, domainID); err != nil { if err := pages_service.VerifyDomain(ctx, domainID); err != nil {

View File

@ -190,7 +190,7 @@ func GetPagesDomains(ctx context.Context, repoID int64) ([]*repo_model.PagesDoma
} }
// AddPagesDomain adds a custom domain for pages // AddPagesDomain adds a custom domain for pages
func AddPagesDomain(ctx context.Context, repoID int64, domain string) (*repo_model.PagesDomain, error) { func AddPagesDomain(ctx context.Context, repoID int64, domain string, sslExternal bool) (*repo_model.PagesDomain, error) {
// Normalize domain // Normalize domain
domain = strings.ToLower(strings.TrimSpace(domain)) domain = strings.ToLower(strings.TrimSpace(domain))
@ -200,9 +200,15 @@ func AddPagesDomain(ctx context.Context, repoID int64, domain string) (*repo_mod
return nil, repo_model.ErrPagesDomainAlreadyExist{Domain: domain} return nil, repo_model.ErrPagesDomainAlreadyExist{Domain: domain}
} }
sslStatus := repo_model.SSLStatusPending
if sslExternal {
sslStatus = repo_model.SSLStatusActive
}
pagesDomain := &repo_model.PagesDomain{ pagesDomain := &repo_model.PagesDomain{
RepoID: repoID, RepoID: repoID,
Domain: domain, Domain: domain,
SSLStatus: sslStatus,
} }
if err := repo_model.CreatePagesDomain(ctx, pagesDomain); err != nil { if err := repo_model.CreatePagesDomain(ctx, pagesDomain); err != nil {

View File

@ -104,6 +104,13 @@
{{end}} {{end}}
</td> </td>
<td class="tw-text-right"> <td class="tw-text-right">
{{if and .Verified (eq .SSLStatus "pending")}}
<form method="post" class="tw-inline-block">
<input type="hidden" name="action" value="activate_ssl">
<input type="hidden" name="domain_id" value="{{.ID}}">
<button class="ui green tiny button">{{ctx.Locale.Tr "repo.settings.pages.activate_ssl"}}</button>
</form>
{{end}}
{{if not .Verified}} {{if not .Verified}}
<form method="post" class="tw-inline-block"> <form method="post" class="tw-inline-block">
<input type="hidden" name="action" value="verify_domain"> <input type="hidden" name="action" value="verify_domain">
@ -118,7 +125,14 @@
</form> </form>
</td> </td>
</tr> </tr>
{{if not .Verified}} {{if and .Verified (eq .SSLStatus "pending")}}
<form method="post" class="tw-inline-block">
<input type="hidden" name="action" value="activate_ssl">
<input type="hidden" name="domain_id" value="{{.ID}}">
<button class="ui green tiny button">{{ctx.Locale.Tr "repo.settings.pages.activate_ssl"}}</button>
</form>
{{end}}
{{if not .Verified}}
<tr> <tr>
<td colspan="4"> <td colspan="4">
<div class="ui info message"> <div class="ui info message">
@ -138,6 +152,13 @@
<div class="inline field"> <div class="inline field">
<label>{{ctx.Locale.Tr "repo.settings.pages.add_domain"}}</label> <label>{{ctx.Locale.Tr "repo.settings.pages.add_domain"}}</label>
<input name="domain" type="text" placeholder="example.com"> <input name="domain" type="text" placeholder="example.com">
<div class="field">
<div class="ui checkbox">
<input type="checkbox" name="ssl_external" id="ssl_external">
<label for="ssl_external">{{ctx.Locale.Tr "repo.settings.pages.ssl_external"}}</label>
</div>
<p class="help">{{ctx.Locale.Tr "repo.settings.pages.ssl_external_desc"}}</p>
</div>
<button class="ui primary button">{{ctx.Locale.Tr "repo.settings.pages.add"}}</button> <button class="ui primary button">{{ctx.Locale.Tr "repo.settings.pages.add"}}</button>
</div> </div>
</form> </form>