Go Runtime

Build and run Go applications on Witchly.host. Compile from source on deploy, run the executable with dedicated resources.

Go Runtime

The Go egg compiles your Go source into a binary at install time, then runs that binary. Perfect for Discord bots, HTTP services, CLI daemons, and anything else where you want a compiled, fast, single-binary deployable.

Quick deploy

  1. dash.witchly.hostDeployLanguagesgolang generic.
  2. On the Startup tab:
    • Go Package — your Go import path (e.g., github.com/user/mybot)
    • Executable — name of the compiled binary (e.g., mybot)
  3. Start.

Startup flow

./${EXECUTABLE}

The startup is minimal — just runs your compiled binary. The install script handles the actual compile step:

# Pseudocode of the install step
go install ${GO_PACKAGE}@latest
mv $GOPATH/bin/<binary> /home/container/${EXECUTABLE}

Variables reference

VariablePurpose
GO_PACKAGEGo module path to install (e.g., github.com/user/tool)
EXECUTABLEName of the resulting binary (typically the repo name)

Workflow: Git repo → running service

Option A: public Go package. Set GO_PACKAGE = github.com/you/yourapp. Reinstall to recompile.

Option B: upload source manually. Upload your .go files + go.mod via SFTP to /home/container/src/, then on the Console tab:

cd src
go build -o ../myapp .
cd ..
chmod +x myapp

Set EXECUTABLE = myapp and start.

HTTP server example

// main.go
package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

func main() {
    port := os.Getenv("SERVER_PORT")
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Hello from Go on Witchly!")
    })
    log.Println("Listening on :" + port)
    http.ListenAndServe(":"+port, nil)
}

Discord bot with discordgo

package main

import (
    "os"
    "os/signal"
    "syscall"

    "github.com/bwmarrin/discordgo"
)

func main() {
    dg, _ := discordgo.New("Bot " + os.Getenv("DISCORD_TOKEN"))
    dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentMessageContent
    dg.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
        if m.Content == "!ping" {
            s.ChannelMessageSend(m.ChannelID, "pong")
        }
    })
    dg.Open()
    defer dg.Close()

    stop := make(chan os.Signal, 1)
    signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
    <-stop
}

Cross-compiling locally

If you want to skip the in-container compile and upload a ready binary:

# Build a Linux/amd64 binary from macOS or Windows
GOOS=linux GOARCH=amd64 go build -o myapp
# Upload myapp to /home/container/ via SFTP
chmod +x myapp

Faster deploys, and your server uses 0 resources at install time.

Troubleshooting

  • “exec format error” — binary was built for the wrong architecture. Use GOOS=linux GOARCH=amd64 when cross-compiling.
  • “permission denied” — chmod +x the binary after upload.
  • Listener fails — always bind to 0.0.0.0, never 127.0.0.1 or localhost, and use os.Getenv("SERVER_PORT").

Next steps

  • Pair with Redis for caching
  • Rust runtime if you want similar performance with stricter safety