{"id":12379,"date":"2022-10-17T06:00:32","date_gmt":"2022-10-17T10:00:32","guid":{"rendered":"https:\/\/blog.litespeedtech.com\/?p=12379"},"modified":"2022-10-17T06:00:32","modified_gmt":"2022-10-17T10:00:32","slug":"openlitespeed-go-gin","status":"publish","type":"post","link":"https:\/\/lswp.store\/index.php\/2022\/10\/17\/openlitespeed-go-gin\/","title":{"rendered":"OpenLiteSpeed + Go + Gin"},"content":{"rendered":"<p><img fetchpriority=\"high\" decoding=\"async\" class=\"alignnone size-full wp-image-12393\" src=\"https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/ols-go-gin.png\" alt=\"OpenLiteSpeed + Go + Gin\" width=\"1000\" height=\"500\" srcset=\"https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/ols-go-gin.png 1000w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/ols-go-gin-300x150.png 300w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/ols-go-gin-768x384.png 768w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/ols-go-gin-600x300.png 600w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><\/p>\n<p>In this blog we will talk about how to deploy <a href=\"https:\/\/pkg.go.dev\/github.com\/gin-gonic\/gin\">Gin<\/a> &#8211; a web framework written in <a href=\"https:\/\/go.dev\/\">Go<\/a> &#8211; by using <a href=\"https:\/\/openlitespeed.org\/\">OpenLiteSpeed<\/a> on <a href=\"https:\/\/releases.ubuntu.com\/22.04\/\">Ubuntu 22.04<\/a>.<\/p>\n<p>By using OpenLiteSpeed Web Server as a reverse proxy, we can easily serve multiple apps in the backend via the same port. Rewrite is supported in the <code>.htaccess<\/code> file in case we need to redirect. Also, once we set up SSL, the HTTP\/3 protocol will be ready instantly. In this blog, we use Gin as an example because it allows us to build web applications and microservices in Go. It contains a set of commonly used functionalities, like routing, and the performance is pretty good.<\/p>\n<p>We will walk though the following processes on our server:<\/p>\n<ul>\n<li><a href=\"\/#installing-go\">Installing Go<\/a><\/li>\n<li><a href=\"\/#setting-up-the-gin-package\">Setting up the Gin package<\/a><\/li>\n<li><a href=\"\/#setting-up-the-gin-service\">Setting up the Gin service<\/a><\/li>\n<li><a href=\"\/#setting-up-openlitespeed-as-a-reverse-proxy\">Setting up OpenLiteSpeed as a reverse proxy<\/a><\/li>\n<li><a href=\"\/#setting-up-ssl-optional\">Setting up SSL (Optional)<\/a><\/li>\n<li><a href=\"\/#configuring-security-optional\">Configuring Security (Optional)<\/a><\/li>\n<\/ul>\n<h2 id=\"installing-go\">Installing Go<\/h2>\n<p>Install Go using <code>snap<\/code> on Ubuntu:<\/p>\n<pre><code>$ snap install go --classic\n<\/code><\/pre>\n<p>Console output:<\/p>\n<pre><code>go 1.18.5 from Michael Hudson-Doyle (mwhudson) installed\n<\/code><\/pre>\n<p>Enable the Go Modules feature, which will allow us to use modules regardless of whether they are in the <code>GOPATH<\/code> default:<\/p>\n<pre><code>$ go env -w GO111MODULE=on\n<\/code><\/pre>\n<p>Verify the settings with the following command:<\/p>\n<pre><code>$ go env\n<\/code><\/pre>\n<p>Console output:<\/p>\n<pre><code>GO111MODULE=\"on\"\nGOARCH=\"amd64\"\n...\n<\/code><\/pre>\n<h2 id=\"setting-up-the-gin-package\">Setting up the Gin package<\/h2>\n<p>Create an example project directory named <code>gin-project<\/code> and access the directory:<\/p>\n<pre><code>$ mkdir -p \/var\/www\/html\/gin-project\n$ cd \/var\/www\/html\/gin-project\n<\/code><\/pre>\n<p>Create a <code>go.mod<\/code> file to track our code&#8217;s dependencies. Run the command from within the project directory:<\/p>\n<pre><code>$ go mod init gin-project\n<\/code><\/pre>\n<p>Check the content of the <code>go.mod<\/code> file:<\/p>\n<pre><code>$ cat go.mod\n<\/code><\/pre>\n<p>Console output:<\/p>\n<pre><code>module gin-project\n\ngo 1.18\n<\/code><\/pre>\n<p>To get the <code>gin-gonic\/gin<\/code> package from GitHub, we will need to add the following content to the file:<\/p>\n<pre><code>module gin-project\n\ngo 1.18\n\nrequire github.com\/gin-gonic\/gin v1.8.1\n<\/code><\/pre>\n<p>(Note we are using v1.8.1 in this example. Check for other versions <a href=\"https:\/\/github.com\/gin-gonic\/gin\/tags\">here<\/a>).<\/p>\n<p>Run the following command, and the required package will be installed under the <code>GOPATH\/pkg\/mod<\/code> directory. A <code>go.sum<\/code> file will be generated. It&#8217;s a record file for the package and version:<\/p>\n<pre><code>$ go mod download\n<\/code><\/pre>\n<p>Now, we are going to download the gin package:<\/p>\n<pre><code>$ go get github.com\/gin-gonic\/gin\n<\/code><\/pre>\n<p>Console Output:<\/p>\n<pre><code>go: downloading github.com\/gin-contrib\/sse v0.1.0\ngo: downloading github.com\/mattn\/go-isatty v0.0.14\ngo: downloading golang.org\/x\/net v0.0.0-20210226172049-e18ecbb05110\ngo: downloading github.com\/go-playground\/validator\/v10 v10.10.0\ngo: downloading github.com\/pelletier\/go-toml\/v2 v2.0.1\ngo: downloading github.com\/ugorji\/go\/codec v1.2.7\ngo: downloading google.golang.org\/protobuf v1.28.0\ngo: downloading gopkg.in\/yaml.v2 v2.4.0\ngo: downloading github.com\/goccy\/go-json v0.9.7\ngo: downloading github.com\/json-iterator\/go v1.1.12\ngo: downloading golang.org\/x\/sys v0.0.0-20210806184541-e5e7981a1069\ngo: downloading github.com\/go-playground\/universal-translator v0.18.0\ngo: downloading github.com\/leodido\/go-urn v1.2.1\ngo: downloading golang.org\/x\/crypto v0.0.0-20210711020723-a769d52b0f97\ngo: downloading golang.org\/x\/text v0.3.6\ngo: downloading github.com\/modern-go\/concurrent v0.0.0-20180228061459-e0a39a4cb421\ngo: downloading github.com\/modern-go\/reflect2 v1.0.2\ngo: downloading github.com\/go-playground\/locales v0.14.0\n\n<\/code><\/pre>\n<p>Using any text editor, create a file named <code>main.go<\/code>, and add the following example contents:<\/p>\n<pre><code>package main\n\nimport \"github.com\/gin-gonic\/gin\"\n\nfunc main() {\n    r := gin.Default()\n    r.GET(\"\/ping\", func(c *gin.Context) {\n        c.JSON(200, gin.H{\n            \"message\": \"pong\",\n        })\n    })\n    r.Run(\":8080\") \/\/ Listen and Serving HTTP on 0.0.0.0:8080\n}\n<\/code><\/pre>\n<p>We might also want to run the following command to remove any unused dependencies:<\/p>\n<pre><code> $ go mod tidy\n<\/code><\/pre>\n<p>Output:<\/p>\n<pre><code>go: downloading github.com\/stretchr\/testify v1.7.1\ngo: downloading github.com\/davecgh\/go-spew v1.1.1\ngo: downloading github.com\/pmezard\/go-difflib v1.0.0\ngo: downloading gopkg.in\/yaml.v3 v3.0.0-20210107192922-496545a6307b\ngo: downloading github.com\/google\/go-cmp v0.5.5\ngo: downloading github.com\/go-playground\/assert\/v2 v2.0.1\ngo: downloading gopkg.in\/check.v1 v1.0.0-20201130134442-10cb98267c6c\ngo: downloading github.com\/kr\/pretty v0.3.0\ngo: downloading golang.org\/x\/xerrors v0.0.0-20191204190536-9bdfabe68543\ngo: downloading github.com\/kr\/text v0.2.0\ngo: downloading github.com\/rogpeppe\/go-internal v1.8.0\n<\/code><\/pre>\n<p>Manually run the <code>main.go<\/code> file and test it:<\/p>\n<pre><code>$ go run main.go\n<\/code><\/pre>\n<p>Visit the site or <code>curl<\/code> the <code>http:\/\/127.0.0.1:8080\/ping<\/code> URl. We should get the following response:<\/p>\n<pre><code>{\"message\":\"pong\"}\n<\/code><\/pre>\n<h2 id=\"setting-up-the-gin-service\">Setting up the Gin service<\/h2>\n<p>In order to run the service with systemd service, we will need to build <code>main.go<\/code>, so we can get a binary file from it:<\/p>\n<pre><code>$ go build main.go\n<\/code><\/pre>\n<p>Create a gin service file at <code>\/etc\/systemd\/system\/gin.service<\/code> with the following content:<\/p>\n<pre><code>[Unit]\nDescription=gin\n\n[Service]\nType=simple\nRestart=always\nRestartSec=3s\nExecStart=\/var\/www\/html\/gin-project\/main\n\n[Install]\nWantedBy=multi-user.target\n<\/code><\/pre>\n<p>Start the service and check the status:<\/p>\n<pre><code>$ systemctl start gin\n$ systemctl status gin\n<\/code><\/pre>\n<p>Console Output:<\/p>\n<pre><code>\u25cf gin.service - gin\n     Loaded: loaded (\/etc\/systemd\/system\/bin.service; disabled; vendor preset: enabled)\n     Active: active (running) since Tue 2022-10-04 07:14:09 UTC; 45s ago\n   Main PID: 25971 (main)\n      Tasks: 5 (limit: 1119)\n     Memory: 5.4M\n        CPU: 23ms\n     CGroup: \/system.slice\/gin.service\n             \u2514\u250025971 \/var\/www\/html\/gin-project\/main\n<\/code><\/pre>\n<h2 id=\"setting-up-openlitespeed-as-a-reverse-proxy\">Setting up OpenLiteSpeed as a Reverse proxy<\/h2>\n<p>The fastest way to set up the OpenLiteSpeed web server with proxy settings is to rely on the <a href=\"https:\/\/github.com\/litespeedtech\/ols1clk\">ols1clk script<\/a> with the proxy setup option <code>--proxy-c<\/code>. It will set up an <strong>External Applications &#8211; Web Server<\/strong> with default value <code>http:\/\/127.0.0.1:8080<\/code> and a <strong>Proxy Context<\/strong> in the <code>Example<\/code> virtual host:<\/p>\n<pre><code>$ bash &lt;( curl -k https:\/\/raw.githubusercontent.com\/litespeedtech\/ols1clk\/master\/ols1clk.sh) --proxy-c\n<\/code><\/pre>\n<p>After the installation, we can visit <code>http:\/\/example.com\/ping<\/code> in the browser (replacing <code>example.com<\/code> with our actual domain):<br \/>\n<img decoding=\"async\" class=\"alignnone size-large wp-image-12385\" src=\"https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/pingpong-1024x480.png\" alt=\"OpenLiteSpeed Reverse Proxy Pin\" width=\"1024\" height=\"480\" srcset=\"https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/pingpong-1024x480.png 1024w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/pingpong-300x141.png 300w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/pingpong-768x360.png 768w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/pingpong-600x281.png 600w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/pingpong.png 1228w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>If we want to modify the default value or add more proxy content for more backend services, we can access the LiteSpeed Web Admin at port 7080 to configure it further.<\/p>\n<h2 id=\"setting-up-ssl-optional\">Setting up SSL (Optional)<\/h2>\n<p>Setting up an SSL certificate enables HTTPS on the web server, which secures the traffic between the server and the clients connecting to it. Certbot is a free and automated way to set up SSL certificates on a server.<\/p>\n<p>The first thing is to install the Certbot package to the system:<\/p>\n<pre><code>$ apt-get install certbot -y\n<\/code><\/pre>\n<p>To use Certbot, we&#8217;ll need a registered domain name and DNS records:<\/p>\n<ul>\n<li>An <code>A<\/code> record from the domain (e.g., <code>example.com<\/code>) to the server\u2019s IP address<\/li>\n<li>An <code>A<\/code> record from the domain prefaced with www (e.g., <code>www.example.com<\/code>) to the server\u2019s IP address.<\/li>\n<\/ul>\n<p>Once the DNS records are set up, we can generate the SSL certificate by following the instructions in the <a href=\"https:\/\/openlitespeed.org\/kb\/lets-encrypt-ssl-on-openlitespeed\/#Proxy_case\">OpenLiteSpeed KB<\/a>.<\/p>\n<p>After setting up SSL on OpenLiteSpeed, we can test our site, or any site on the Internet, with the <a href=\"https:\/\/http3check.net\/\">free HTTP\/3 Check tool<\/a>. Enter a URL, and HTTP\/3 Check will tell us whether QUIC or HTTP\/3 is supported by that site.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-large wp-image-12387\" src=\"https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/http3support-1024x729.png\" alt=\"The HTTP\/3 Check Tool\" width=\"1024\" height=\"729\" srcset=\"https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/http3support-1024x729.png 1024w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/http3support-300x214.png 300w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/http3support-768x547.png 768w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/http3support-600x427.png 600w, https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/http3support.png 1110w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<h2 id=\"configuring-security-optional\">Configuring Security (Optional)<\/h2>\n<p>There are several built-in security features that we could implement, for example reCAPTCHA, Per-Client Throttling, WAF, etc.<\/p>\n<h4 id=\"recaptcha\">reCAPTCHA<\/h4>\n<p>OpenLiteSpeed features reCAPTCHA as a method of defense against DDoS attack. When a visitor accesses the website, they will need to go though reCAPTCHA validation. After passing the reCAPTCHA validation, the visitor is temporarily allowlisted as long as they continue to browse the site. Once the visitor has become inactive, reCAPTCHA is once again enabled for that visitor\u2019s next request. We can follow the <a href=\"https:\/\/docs.openlitespeed.org\/docs\/advanced\/security#recaptcha-with-openlitespeed\">reCAPTCHA Security Guide<\/a> to enable the feature.<\/p>\n<h4 id=\"per-client-throttling\">Per-Client Throttling<\/h4>\n<p>OpenLiteSpeed includes a built-in Per-Client Throttling feature which allows you to block bad IPs, as well as limit the request, bandwidth, and connection rate per remote IP address. We can follow the <a href=\"https:\/\/docs.openlitespeed.org\/docs\/advanced\/security#per-client-throttling\">Per-Client Throttling Security Guide<\/a> to enable the feature.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to deploy Gin &#8211; a web framework written in Go &#8211; by using OpenLiteSpeed as a reverse proxy on Ubuntu 22.04.<\/p>\n","protected":false},"author":1,"featured_media":12393,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[29],"tags":[120,121],"class_list":["post-12379","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-openlitespeed","tag-gin","tag-go"],"jetpack_featured_media_url":"https:\/\/lswp.store\/wp-content\/uploads\/2022\/10\/ols-go-gin.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/lswp.store\/index.php\/wp-json\/wp\/v2\/posts\/12379","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lswp.store\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lswp.store\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lswp.store\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lswp.store\/index.php\/wp-json\/wp\/v2\/comments?post=12379"}],"version-history":[{"count":0,"href":"https:\/\/lswp.store\/index.php\/wp-json\/wp\/v2\/posts\/12379\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lswp.store\/index.php\/wp-json\/wp\/v2\/media\/12393"}],"wp:attachment":[{"href":"https:\/\/lswp.store\/index.php\/wp-json\/wp\/v2\/media?parent=12379"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lswp.store\/index.php\/wp-json\/wp\/v2\/categories?post=12379"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lswp.store\/index.php\/wp-json\/wp\/v2\/tags?post=12379"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}