Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ vim config.toml
go run cmd/sea/main.go > sea.conf
```

### TLS / Let's Encrypt

If you want to run SEA behind HTTPS using Certbot, set `listen_ssl`,
`ssl_certificate`, and `ssl_certificate_key` in `config.toml`. Enable the
`letsencrypt` and `redirect_http` flags to generate a second server block for
port 80 that redirects to HTTPS. The resulting configuration can be safely
included in your `nginx` setup, and Certbot may modify only the certificate
paths when certificates renew.

## Development Requirements

- Go >= 1.22
Expand Down
17 changes: 13 additions & 4 deletions cmd/sea/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ import (

// Config represents the TOML configuration structure.
type Config struct {
Listen int `toml:"listen"`
ServerName string `toml:"server_name"`
CustomKeywords []KeywordRule `toml:"custom_keywords"`
Listen int `toml:"listen"`
ListenSSL int `toml:"listen_ssl"`
ServerName string `toml:"server_name"`
SSLCertificate string `toml:"ssl_certificate"`
SSLCertificateKey string `toml:"ssl_certificate_key"`
LetsEncrypt bool `toml:"letsencrypt"`
RedirectHTTP bool `toml:"redirect_http"`
CustomKeywords []KeywordRule `toml:"custom_keywords"`
}

// TemplateData combines the parsed configuration with the destination
Expand Down Expand Up @@ -56,7 +61,11 @@ func main() {
}

func loadConfig(path string) (Config, error) {
cfg := Config{Listen: 80, ServerName: "search.localhost"}
cfg := Config{
Listen: 80,
ListenSSL: 0,
ServerName: "search.localhost",
}
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
Expand Down
33 changes: 32 additions & 1 deletion cmd/sea/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@ func TestLoadConfig(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "cfg.toml")
data := []byte(`listen = 8080
listen_ssl = 443
server_name = "example.com"

redirect_http = true

ssl_certificate = "/tmp/full.pem"
ssl_certificate_key = "/tmp/key.pem"
letsencrypt = true

[[custom_keywords]]
phrase = "foo bar"
dest = "google"`)
Expand All @@ -33,6 +40,18 @@ dest = "google"`)
if cfg.Listen != 8080 {
t.Errorf("expected listen 8080, got %d", cfg.Listen)
}
if cfg.ListenSSL != 443 {
t.Errorf("expected listen_ssl 443, got %d", cfg.ListenSSL)
}
if !cfg.RedirectHTTP {
t.Error("expected redirect_http true")
}
if cfg.SSLCertificate != "/tmp/full.pem" || cfg.SSLCertificateKey != "/tmp/key.pem" {
t.Errorf("unexpected certificate paths %+v", cfg)
}
if !cfg.LetsEncrypt {
t.Error("expected letsencrypt true")
}
if cfg.ServerName != "example.com" {
t.Errorf("expected server name example.com, got %s", cfg.ServerName)
}
Expand All @@ -45,14 +64,26 @@ dest = "google"`)
}

func TestGenerateNginx(t *testing.T) {
cfg := Config{Listen: 8080, ServerName: "example.com", CustomKeywords: []KeywordRule{{Phrase: "foo", Dest: "google"}}}
cfg := Config{
Listen: 8080,
ListenSSL: 8443,
ServerName: "example.com",
RedirectHTTP: true,
CustomKeywords: []KeywordRule{{
Phrase: "foo",
Dest: "google",
}},
}
out, err := generateNginx(cfg)
if err != nil {
t.Fatalf("generateNginx returned error: %v", err)
}
if !strings.Contains(out, "server_name example.com;") {
t.Errorf("generated config missing server name: %s", out)
}
if !strings.Contains(out, "listen 8443 ssl") {
t.Errorf("generated config missing ssl server: %s", out)
}
if !strings.Contains(out, "~*(?i)^foo$") {
t.Errorf("generated config missing custom rule: %s", out)
}
Expand Down
35 changes: 35 additions & 0 deletions cmd/sea/nginx.conf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,40 @@ map $dest $target {
{{- end }}
}

{{ if gt .ListenSSL 0 }}
server {
listen {{ .ListenSSL }} ssl http2;
server_name {{ .ServerName }};
{{- if .SSLCertificate }}
ssl_certificate {{ .SSLCertificate }};
ssl_certificate_key {{ .SSLCertificateKey }};
{{- if .LetsEncrypt }}
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
{{- end }}
{{- end }}

location / {
return 302 $target;
}
}
{{ if .RedirectHTTP }}
server {
listen {{ .Listen }};
server_name {{ .ServerName }};
return 301 https://$host$request_uri;
}
{{ else }}
server {
listen {{ .Listen }};
server_name {{ .ServerName }};

location / {
return 302 $target;
}
}
{{ end }}
{{ else }}
server {
listen {{ .Listen }};
server_name {{ .ServerName }};
Expand All @@ -49,4 +83,5 @@ server {
return 302 $target;
}
}
{{ end }}

7 changes: 6 additions & 1 deletion config-example.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
listen = 3001
listen = 80
listen_ssl = 443
server_name = "your.site"
# ssl_certificate = "/etc/letsencrypt/live/your.site/fullchain.pem"
# ssl_certificate_key = "/etc/letsencrypt/live/your.site/privkey.pem"
# letsencrypt = true
# redirect_http = true

[[custom_keywords]]
phrase = "nginx"
Expand Down
2 changes: 2 additions & 0 deletions nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ map $dest $target {
wikipedia https://en.wikipedia.org/wiki/$arg_q;
}


server {
listen 80;
server_name search.localhost;
Expand All @@ -49,3 +50,4 @@ server {
}
}