2

I am new to Golang and I did set up a "hello world!" test message for a Golang API on our VPS. It works just fine at http://www.example.com:8080/hello. I would like however to move to HTTPS.

Could someone tell me step by step the right procedure to go from HTTP to HTTPS for a golang API? Thank you!

In case there is an issue with the golang code:

package main

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

func main() {
        http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
                fmt.Fprintf(w, "Hello, World")
        })

        fmt.Println("Server Started On Port 8080")
        log.Fatal(http.ListenAndServe(":8080", nil))
}

Filippo
  • 83
  • 9
  • Do you have a code to share? and find the issues to resolve.. – Kishore Apr 21 '22 at 17:45
  • I added it in in the question body. I do expect it to be a problem with apache configuration through – Filippo Apr 21 '22 at 18:10
  • 1
    If you are having a problem with apache, then this is not the place to ask. If you want to serve TLS directly with go, and are having a problem, then there may be something we can help with. The [documentation](https://pkg.go.dev/net/http#example-ListenAndServeTLS) has an example, and there is a script to generate certs included in the package for testing. – JimB Apr 21 '22 at 18:30
  • First you need a certificate – Tiago Peczenyj Apr 21 '22 at 18:33
  • I do have SSL certificate over www.example.com. Where should I go to ask about apache configuration? – Filippo Apr 21 '22 at 20:07
  • Edit your question and show the Apache VirtualHost configuration. – John Hanley Apr 21 '22 at 23:34
  • @JohnHanley I added the configuration. – Filippo Apr 22 '22 at 14:40
  • 1) Include the VirtualHost for port 80 as well. 2) To prevent displaying the contents of the bin directory, remove **Options Indexes** specified in the `` section. 3) You cannot specify the bin directory for the DocumentRoot. Instead run your application as a webserver and then configure Apache to be a **proxy**. This answer will help: https://stackoverflow.com/a/54897474/8016720 4) Do not use port 8080 for SSL. Use a port such as 8443. Proxy to your Go app listening on port 8080. – John Hanley Apr 22 '22 at 20:05
  • @JohnHanley Thanks for the comment. I edited the post and added the VirtualHost for 80 and (now) 8443, but on https://www.example.com:8443/hello I still have a configuration issue. – Filippo Apr 23 '22 at 09:26
  • Your VirtualHost for port 80 is not forwarding to your Go application. It just serves normal website files. So you have a problem there as well. For the server error, what does **error.log** indicate? – John Hanley Apr 23 '22 at 18:12
  • @JohnHanley the error.log said that I have no Handler for http. I loaded the module proxy_http and now it works correctly at www.example.com:8443/hello. Regarding the port 80, why should it forward to Go? Should it be forwarding only if I use a subdomain like api.example.com? – Filippo Apr 23 '22 at 19:25
  • You said that it works on port 80 but did not work on 8443. I assumed that you wanted forwarding to your Go app to work on 80 as well. Review how you worded your question and cleanup to make everything clear. – John Hanley Apr 23 '22 at 22:24
  • @JohnHanley I checked if I mispoke about port 80 but I do not find reference to it. I only see 8080 (until you asked VirtualHost on port 80). I will clean up everything to make it easy to understand. By the way, thank you very much for your help! – Filippo Apr 24 '22 at 09:19

3 Answers3

2

Use http.ListenAndServeTLS Instead

https://pkg.go.dev/net/http#ListenAndServeTLS

    package main

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

func main() {
        http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
                fmt.Fprintf(w, "Hello, World")
        })

        fmt.Println("Server Started On Port 8080")
        err := http.ListenAndServeTLS(":8080", "cert.pem", "key.pem", nil)
        log.Fatal(err)
}
Dan
  • 182
  • 1
  • 2
  • 13
1

Thanks to John Hanley for support that lead to this answer. First of all I did set the port 8443 for https by editing /etc/apache2/ports.conf:

Listen 80

<IfModule ssl_module>
        Listen 443
        Listen 8443
</IfModule>

Then I added a VirtualHost in the config of the example.com domain so that port 8443 acts as a proxy:

<VirtualHost *:8443>
        ServerAdmin admin@example.com
        ServerName www.example.com
        ServerAlias example.com

        ProxyRequests Off
        <Proxy *>
                Order deny,allow
                Allow from all
        </Proxy>
        ProxyPass / http://localhost:8080/
        ProxyPassReverse / http://localhost:8080/

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

       Include /etc/letsencrypt/options-ssl-apache.conf
       SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
       SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>

and you need to load the modules proxy and proxy_http using e2enmod proxy and e2enmod proxy_http. After reloading apache, the API can be called at https://www.example.com:8443/hello.

Filippo
  • 83
  • 9
0

Adding on to @Dan 's answer. A little more complex implementation but enables you to configure it more.

If you want to use more than 1 set of certs

certs := []tls.Certificate{}
for _, cert := range []{"cert1", "cert2"} {
    certSet, err := tls.LoadX509KeyPair(cert+".pem", cert+".key")
    if err != nil {
        return err
    }
    certs = append(certs, certSet)
}

Create tls config

cfg := &tls.Config {
    Certificates: certs,
    MinVersion:   tls.VersionTLS12,
}
cfg.BuildNameToCertificate()
server := &http.Server{
    Addr:        ":8080",
    TLSConfig:   cfg,
    IdleTimeout: 30 * time.Second,
}

Add handler and start server

http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World")
})

err := server.ListenAndServeTLS("", "") // Dont give filename here if giving set of certs in tls config above
if err != nil {
    return err
}
Suyash Medhavi
  • 1,135
  • 6
  • 18