如何在VPS上仅用Golang工具配置htaccess(无需Nginx/Apache)
Alright, let's figure out how to get that .htaccess-style functionality working with just Go on your VPS—no Apache or Nginx required. Here's a practical breakdown of how to replicate common .htaccess features using Go's standard library or lightweight routing tools:
Core Idea
.htaccess is mostly used for URL rewrites, redirects, HTTP header management, and access control. Since Go can act as a full-featured HTTP server on its own, we can replicate all these behaviors directly in your Go code, either with the standard net/http package or a lightweight routing library like gorilla/mux (it's a popular Go-specific tool, so it fits your "only Golang tools" goal).
Common .htaccess Features & Their Go Equivalents
1. URL Rewrites (Clean URLs)
If you’re using clean URLs (like rewriting /blog/post/123 to /blog/post?id=123), here’s how to do it:
With Go's Standard Library
package main import ( "net/http" "strings" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // Rewrite /blog/post/[id] to /blog/post with id query param if strings.HasPrefix(r.URL.Path, "/blog/post/") { postID := strings.TrimPrefix(r.URL.Path, "/blog/post/") r.URL.Path = "/blog/post" r.URL.RawQuery = "id=" + postID + "&" + r.URL.RawQuery // Forward to the actual handler blogPostHandler(w, r) } else { // Serve static files from your public directory http.ServeFile(w, r, "public"+r.URL.Path) } }) http.ListenAndServe(":8080", nil) } func blogPostHandler(w http.ResponseWriter, r *http.Request) { postID := r.URL.Query().Get("id") w.Write([]byte("Blog Post ID: " + postID)) }
With gorilla/mux (Simpler for Complex Routes)
package main import ( "net/http" "github.com/gorilla/mux" ) func main() { r := mux.NewRouter() // Define the "clean" route directly as the handler r.HandleFunc("/blog/post/{id}", blogPostHandler).Methods("GET") // Serve static files from the public folder r.PathPrefix("/").Handler(http.FileServer(http.Dir("public"))) http.ListenAndServe(":8080", r) } func blogPostHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) postID := vars["id"] w.Write([]byte("Blog Post ID: " + postID)) }
2. 301/302 Redirects
For permanent (301) or temporary (302) redirects (like .htaccess's Redirect 301 /old-page /new-page):
// Using standard library http.HandleFunc("/old-page", func(w http.ResponseWriter, r *http.Request) { // 301 permanent redirect http.Redirect(w, r, "/new-page", http.StatusMovedPermanently) // Use http.StatusFound for 302 temporary redirect }) // With gorilla/mux r.HandleFunc("/old-page", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/new-page", http.StatusMovedPermanently) })
3. Setting HTTP Headers
To add security or caching headers (like .htaccess's Header set X-Content-Type-Options nosniff), use middleware:
func addSecurityHeaders(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("Cache-Control", "max-age=3600") w.Header().Set("X-Frame-Options", "DENY") // Pass the request to the next handler next.ServeHTTP(w, r) }) } // Apply middleware to your entire router func main() { r := mux.NewRouter() // ... define your routes ... // Wrap the router with the header middleware http.ListenAndServe(":8080", addSecurityHeaders(r)) }
4. Access Control (Allow/Deny IPs)
To restrict access to specific IPs (like .htaccess's Allow from 192.168.1.1):
func restrictIPs(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { allowedIPs := []string{"192.168.1.1", "10.0.0.5"} // Extract client IP (strip port number) clientIP := strings.Split(r.RemoteAddr, ":")[0] allowed := false for _, ip := range allowedIPs { if ip == clientIP { allowed = true break } } if !allowed { http.Error(w, "Forbidden", http.StatusForbidden) return } next.ServeHTTP(w, r) }) } // Apply to a specific route (e.g., admin panel) r.HandleFunc("/admin", adminHandler).Methods("GET").Middleware(restrictIPs)
Deployment on Your VPS
Once your code is ready, here’s how to deploy it reliably:
- Build the binary for your VPS:
# For 64-bit Linux VPS GOOS=linux GOARCH=amd64 go build -o mywebapp # For ARM64 VPS (e.g., AWS Graviton) GOOS=linux GOARCH=arm64 go build -o mywebapp - Transfer the binary to your VPS:
scp mywebapp your-user@your-vps-ip:/var/www/mywebapp/ - Run as a system service (so it starts on boot and restarts if it crashes):
Create a systemd service file at/etc/systemd/system/mywebapp.service:
Then enable and start the service:[Unit] Description=My Go Web Application After=network.target [Service] User=www-data WorkingDirectory=/var/www/mywebapp ExecStart=/var/www/mywebapp/mywebapp Restart=always [Install] WantedBy=multi-user.targetsudo systemctl daemon-reload sudo systemctl enable mywebapp sudo systemctl start mywebapp - Bind to port 80/443 (standard HTTP/HTTPS ports):
Instead of running withsudo, usesetcapto let the binary bind to privileged ports:
Then update your code to listen onsudo setcap CAP_NET_BIND_SERVICE=+eip /var/www/mywebapp/mywebapp:80or:443.
内容的提问来源于stack exchange,提问作者TalkingJson

