Files
nostr-webhost/hostr/main.go
studiokaiji 6841ef94bb Add web server and relay configuration support
- Introduced a new Dockerfile for building the web server.
- Updated docker-compose.yml to include the web server service with environment variable support for relay URLs.
- Enhanced relay management in relays.go to read from environment variables.
- Updated main.go to provide descriptions for relay configuration in CLI commands.
2025-11-26 00:24:29 +09:00

216 lines
5.9 KiB
Go
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
_ "embed"
"fmt"
"os"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip19"
"github.com/studiokaiji/nostr-webhost/hostr/cmd/deploy"
"github.com/studiokaiji/nostr-webhost/hostr/cmd/keystore"
"github.com/studiokaiji/nostr-webhost/hostr/cmd/relays"
"github.com/studiokaiji/nostr-webhost/hostr/cmd/server"
"github.com/urfave/cli/v2"
)
//go:embed cute-ostrich.txt
var cuteOstrich string
func main() {
app := &cli.App{
Commands: []*cli.Command{
{
Name: "deploy",
Usage: "🌐 Deploy nostr website",
Description: `Deploy your website to Nostr relays.
Relay configuration:
- Set RELAY_URLS environment variable with comma-separated relay URLs to bypass .nostr_relays file
- Example: RELAY_URLS="wss://relay1.com,wss://relay2.com" hostr deploy
- If RELAY_URLS is not set, will read from .nostr_relays file`,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Value: "./",
Usage: "Site directory",
},
&cli.BoolFlag{
Name: "replaceable",
Aliases: []string{"r"},
Usage: "Specify 'true' explicitly when using NIP-33",
Value: true,
},
&cli.StringFlag{
Name: "identifier",
Aliases: []string{"d"},
Usage: "index.html identifier (valid only if replaceable option is true)",
},
},
Action: func(ctx *cli.Context) error {
fmt.Println("🌐 Deploying...")
path := ctx.String("path")
replaceable := ctx.Bool("replaceable")
dTag := ctx.String("identifier")
_, encoded, dTag, err := deploy.Deploy(path, replaceable, dTag)
if err == nil {
fmt.Println("🌐 Deploy Complete!")
pubkey, err := keystore.GetPublic()
if err != nil {
os.Exit(1)
}
npub, err := nip19.EncodePublicKey(pubkey)
if err != nil {
os.Exit(1)
}
defaultModeUrl := "https://h.hostr.cc"
secureModeUrl := fmt.Sprintf("https://%s.hostr.cc", npub)
if replaceable {
defaultModeUrl = fmt.Sprintf("%s/p/%s/d/%s", defaultModeUrl, npub, dTag)
secureModeUrl = fmt.Sprintf("%s/d/%s", secureModeUrl, dTag)
} else {
defaultModeUrl = fmt.Sprintf("%s/e/%s", defaultModeUrl, encoded)
secureModeUrl = fmt.Sprintf("%s/e/%s", secureModeUrl, encoded)
}
fmt.Println("\n\033[1m========= 🚵 Access To =========\033")
fmt.Printf("\n\033[1m🗃 Default Mode:\033[0m\n\x1b[36m%s\x1b[0m\n", defaultModeUrl)
fmt.Printf("\033[1m\n🔑 Secure Mode:\033[0m\n\x1b[36m%s\x1b[0m\n", secureModeUrl)
fmt.Printf("\n\x1b[90mh.hostr.cc is just one endpoint, so depending on the relay configuration, it may not be accessible.\x1b[0m\n")
fmt.Printf("\n\033[1m=================================\033\n")
}
return err
},
},
{
Name: "add-relay",
Usage: "📌 Add nostr relay",
Action: func(ctx *cli.Context) error {
args := ctx.Args()
relay := args.Get(args.Len() - 1)
err := relays.AddRelay(relay)
if err == nil {
fmt.Println("📌 Added relay:", relay)
}
return err
},
},
{
Name: "remove-relay",
Usage: "🗑 Remove nostr relay",
Action: func(ctx *cli.Context) error {
args := ctx.Args()
relay := args.Get(args.Len() - 1)
err := relays.RemoveRelay(relay)
if err == nil {
fmt.Println("🗑 Removed relay:", relay)
}
return err
},
},
{
Name: "list-relays",
Usage: "📝 List added nostr relays",
Action: func(ctx *cli.Context) error {
relays, err := relays.GetAllRelays()
fmt.Println("===========================")
for _, relay := range relays {
fmt.Println(relay)
}
fmt.Println("===========================")
return err
},
},
{
Name: "set-private",
Usage: "🔐 Set private key",
Action: func(ctx *cli.Context) error {
args := ctx.Args()
key := args.Get(args.Len() - 1)
err := keystore.SetSecret(key)
if err == nil {
fmt.Println("🔐 Secret is recorded")
}
return err
},
},
{
Name: "show-public",
Usage: "📛 Show public key",
Action: func(ctx *cli.Context) error {
_, _, err := keystore.ShowPublic()
return err
},
},
{
Name: "generate-key",
Usage: "🗝 Generate key",
Action: func(ctx *cli.Context) error {
key := nostr.GeneratePrivateKey()
err := keystore.SetSecret(key)
if err == nil {
fmt.Print("🗝 Generated key\n🗝 You can check the public key with 'hostr show-public'\n")
}
return err
},
},
{
Name: "start",
Usage: "🕺 Wake up web server",
Description: `Start the web server to serve content from Nostr relays.
Relay configuration:
- Set RELAY_URLS environment variable with comma-separated relay URLs to bypass .nostr_relays file
- Example: RELAY_URLS="wss://relay1.com,wss://relay2.com" hostr start
- If RELAY_URLS is not set, will read from .nostr_relays file`,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "port",
Aliases: []string{"p"},
Value: "3000",
Usage: "Web server port",
},
&cli.StringFlag{
Name: "mode",
Aliases: []string{"m"},
Value: "normal",
Usage: "🧪 Experimental: Enabled subdomain-based access in replaceable events.",
Action: func(ctx *cli.Context, v string) error {
if v != "normal" && v != "hybrid" && v != "secure" {
return fmt.Errorf("Invalid mode flag. Must be 'normal', 'hybrid', or 'secure'.")
}
return nil
},
},
},
Action: func(ctx *cli.Context) error {
port := ctx.String("port")
mode := ctx.String("mode")
server.Start(port, mode)
return nil
},
},
},
}
if len(os.Args) < 2 || os.Args[1] == "help" || os.Args[1] == "h" {
// Display ostrich
fmt.Println(cuteOstrich)
}
// Start app
err := app.Run(os.Args)
if err != nil {
fmt.Println(err)
}
}