顯示具有 FreeBSD 標籤的文章。 顯示所有文章
顯示具有 FreeBSD 標籤的文章。 顯示所有文章

2017年8月19日 星期六

FreeBSD 上安裝 golang & websocket 使用 Let’s Encrypt

FreeBSD 中文教學相對現在很冷門...正體中文幾乎已經沒有人在寫新文件資料了...
golang 請直接上 golang 官網找最新版本對應改一下喔!!
用套件管理工具 pkg 安裝的很可能不是最新版所以直接上官網抓會比較好...

wget https://storage.googleapis.com/golang/go1.8.3.freebsd-amd64.tar.gz
tar zxvf go1.8.3.freebsd-amd64.tar.gz
sudo mv go /usr/local/
mkdir gowork
vi .cshrc
ADD
setenv  GOROOT  /usr/local/go
setenv  GOPATH  $HOME/gowork
set path = (/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin $HOME/bin $GOROOT/bin)
source .cshrc

go

已經可以用了!!

golang 在各平台上幾乎都能簡易的解壓縮設定環境變數後就可以用了... 同一套 source code 搬過去直接 go build .... 就可以編出一個可執行檔... 某些應用上是蠻好用的


抓取安裝 websocket 程式庫
go get github.com/gorilla/websocket
cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/command`

command 光用這個範例就可以延伸想像做許多有趣 or 邪惡應用... XDD

但為了方便測試會用 echo 這 server client 的範例 code
cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/command` && cd ../echo

但現在應用上會碰到的問題就是 https 下跨接 ws 由 SSL 加密模式接 未加密的任何東西時瀏覽器會擋...當然可以設 header by pass 的規則但還是不完整的做法
所以必須要能使用 wss 也是相同加密模式的 websocket

由G大神找到 wss 也就是加密傳輸的 websocket 範例中都沒有完整的寫到 直接可以 run 起來的問題點
rootPEM
拼湊了幾個後得到

server_wss.go
// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

package main

import (
 "flag"
 "html/template"
 "log"
 "net/http"

 "github.com/gorilla/websocket"
)

var addr = flag.String("addr", "localhost:8080", "http service address")

var upgrader = websocket.Upgrader{} // use default options

func echo(w http.ResponseWriter, r *http.Request) {
 c, err := upgrader.Upgrade(w, r, nil)
 if err != nil {
  log.Print("upgrade:", err)
  return
 }
 defer c.Close()
 for {
  mt, message, err := c.ReadMessage()
  if err != nil {
   log.Println("read:", err)
   break
  }
  log.Printf("recv: %s", message)
  err = c.WriteMessage(mt, message)
  if err != nil {
   log.Println("write:", err)
   break
  }
 }
}

func home(w http.ResponseWriter, r *http.Request) {
 homeTemplate.Execute(w, "wss://"+r.Host+"/echo")
}

func main() {
 flag.Parse()
 log.SetFlags(0)
 http.HandleFunc("/echo", echo)
 http.HandleFunc("/", home)
 //log.Fatal(http.ListenAndServe(*addr, nil))
 log.Fatal(http.ListenAndServeTLS(*addr, "cert.pem", "privkey.pem", nil))
}

var homeTemplate = template.Must(template.New("").Parse(`
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script>  
window.addEventListener("load", function(evt) {

    var output = document.getElementById("output");
    var input = document.getElementById("input");
    var ws;

    var print = function(message) {
        var d = document.createElement("div");
        d.innerHTML = message;
        output.appendChild(d);
    };

    document.getElementById("open").onclick = function(evt) {
        if (ws) {
            return false;
        }
        ws = new WebSocket("{{.}}");
        ws.onopen = function(evt) {
            print("OPEN");
        }
        ws.onclose = function(evt) {
            print("CLOSE");
            ws = null;
        }
        ws.onmessage = function(evt) {
            print("RESPONSE: " + evt.data);
        }
        ws.onerror = function(evt) {
            print("ERROR: " + evt.data);
        }
        return false;
    };

    document.getElementById("send").onclick = function(evt) {
        if (!ws) {
            return false;
        }
        print("SEND: " + input.value);
        ws.send(input.value);
        return false;
    };

    document.getElementById("close").onclick = function(evt) {
        if (!ws) {
            return false;
        }
        ws.close();
        return false;
    };

});
</script>
</head>
<body>
<table>
<tr><td valign="top" width="50%">
<p>Click "Open" to create a connection to the server, 
"Send" to send a message to the server and "Close" to close the connection. 
You can change the message and send multiple times.
<p>
<form>
<button id="open">Open</button>
<button id="close">Close</button>
<p><input id="input" type="text" value="Hello world!">
<button id="send">Send</button>
</form>
</td><td valign="top" width="50%">
<div id="output"></div>
</td></tr></table>
</body>
</html>
`))


client_wss.go
// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

package main

import (
 "crypto/tls"
 "crypto/x509"
 "flag"
 "log"
 "net/url"
 "os"
 "os/signal"
 "time"
 "io/ioutil"

 "github.com/gorilla/websocket"
)

var addr = flag.String("addr", "localhost:8080", "http service address")

func main() {
 flag.Parse()
 log.SetFlags(0)

 interrupt := make(chan os.Signal, 1)
 signal.Notify(interrupt, os.Interrupt)

 u := url.URL{Scheme: "wss", Host: *addr, Path: "/echo"}
 log.Printf("connecting to %s", u.String())

 //c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
 rootPEM, err := ioutil.ReadFile("root.pem")
 if err != nil || rootPEM == nil {
  log.Fatal("dial:", err)
 }
 roots := x509.NewCertPool()
 ok := roots.AppendCertsFromPEM(rootPEM)
 if !ok {
  log.Fatal("failed to parse root certificate")
 }
 d := websocket.Dialer{TLSClientConfig: &tls.Config{RootCAs: roots}}
 c, _, err := d.Dial(u.String(), nil)
 if err != nil {
  log.Fatal("dial:", err)
 }
 defer c.Close()

 done := make(chan struct{})

 go func() {
  defer c.Close()
  defer close(done)
  for {
   _, message, err := c.ReadMessage()
   if err != nil {
    log.Println("read:", err)
    return
   }
   log.Printf("recv: %s", message)
  }
 }()

 ticker := time.NewTicker(time.Second)
 defer ticker.Stop()

 for {
  select {
  case t := <-ticker.C:
   err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
   if err != nil {
    log.Println("write:", err)
    return
   }
  case <-interrupt:
   log.Println("interrupt")
   // To cleanly close a connection, a client should send a close
   // frame and wait for the server to close the connection.
   err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
   if err != nil {
    log.Println("write close:", err)
    return
   }
   select {
   case <-done:
   case <-time.After(time.Second):
   }
   c.Close()
   return
  }
 }
}

server_wss 大概比較沒什麼問題 只需要記得改一下 localhost:8080 to 0.0.0.0:8080 這樣外部才連的到 or 只是區網內就改成你 Server 內部的虛擬 IP... 跟要使用的 Port
另外
log.Fatal(http.ListenAndServeTLS(*addr, "cert.pem", "privkey.pem", nil))
cert.pem 跟 privkey.pem 憑證的部分
我是直接

ln -s /etc/dehydrated/certs/cert.pem
ln -s /etc/dehydrated/certs/privkey.pem

此時 go run server_wss.go 需要 root 權限!! 否則憑證無法讀取
PS: 這就看你自己憑證路徑是什麼在哪嘍~ 我是用 dehydrated 來取得 Let’s Encrypt 憑證
其他還有相仿的官方的...路徑不盡相同嘍



client_wss 基本上同上 localhost:8080 記得改成你 Domain Name

主要會碰到的問題回到 rootPEM !!!
這到底要給什麼??

由於我是用 Let’s Encrypt
所以上 https://letsencrypt.org/certificates/ 找 Active
Let’s Encrypt Authority X3 (IdenTrust cross-signed)
將它存成 root.pem

至於用其他家產的憑證就必須自己去找看看對應的來試試看嘍

2014年3月6日 星期四

在 Nginx 使用 FreeBSD 的 kernel module httpready

FreeBSD 使用一個叫 accept_filter(9) 的機制能允許應用程式要求系統核心預先處理過連線。例如,accf_http(9) 接收過濾器會等到完整的HTTP request己經讀入緩衝區裡,accept(2)才會回傳值

listen 80 default accept_filter=httpready;

httpready 參數必須設定在有 default 的 listen 之上,而且必須在 default 之後,不然會回報設定錯誤。


2011年5月26日 星期四

簡單備份 FreeBSD 所有設定

tar 再配合個 rsync 可以做的定時將系統設定檔備份的作業

tar -jcvf /root/`date '+%Y%m%d%H%M'`-Sys_etc-`hostname`.bz2 /etc
tar -jcvf /root/`date '+%Y%m%d%H%M'`-Sys_localetc`hostname`.bz2 /usr/local/etc

2009年12月17日 星期四

FreeBSD上啟用 DTrace

FreeBSD 7.1 開始有提供 由 Solaris 移植來的 DTrace 動態追蹤功能

但預設是不起動的!
一使用

$ dtrace -l
dtrace: failed to initialize dtrace: DTrace device not available on system

會出現這樣的訊息!

要使用它必須重新 build kernel 安裝

首先修改 GENERIC or 您自己的 kernel 設定檔
將下列設定注解拿掉OR新增

$ ee /usr/src/sys/amd64/conf/GENERIC
options KDTRACE_HOOKS # all architectures
options KDTRACE_FRAME # amd64-only

$ cd /usr/obj/usr/src/sys/GENERIC/
$ make clean
$ cd /usr/src
$ make buildkernel WITH_CTF=1
$ make installkernel


ok後 reboot

再來
$ kldload dtraceall

這時就可以使用了


上述啟用方式由 FreeBSD 7.1 で DTrace を使う準備 得來

相關資料:
DTrace User Guide

2008年11月19日 星期三

messages Report 中大量出現 printing/print_cups.c:cups_connect(69)

由於我有設定BSD主機自動每天發送 messages Report 到我的 email 中
看到每天都出現一推

Nov 19 00:14:42 bsd smbd[47564]: [2008/11/19 00:14:42, 0] printing/print_cups.c:cups_connect(69)
Nov 19 00:14:42 bsd smbd[47564]: Unable to connect to CUPS server localhost:631 - Connection refused
Nov 19 00:14:42 bsd smbd[47564]: [2008/11/19 00:14:42, 0] printing/print_cups.c:cups_connect(69)
Nov 19 00:14:42 bsd smbd[47564]: Unable to connect to CUPS server localhost:631 - Connection refused
Nov 19 00:46:43 bsd smbd[47564]: [2008/11/19 00:46:43, 0] printing/print_cups.c:cups_connect(69)
Nov 19 00:46:43 bsd smbd[47564]: Unable to connect to CUPS server localhost:631 - Connection refused
Nov 19 00:46:43 bsd smbd[47564]: [2008/11/19 00:46:43, 0] printing/print_cups.c:cups_connect(69)
...


因為我samba並沒有當 列印伺服器

Google 的一下解決方法是在 smb.conf
中加入

load printers = no
printing = bsd


看了一下我的設定檔原本就有
load printers = no
而 printing = cups 則是 mask起來的狀態
現在取消 mask 將 cups 改 bsd
再觀察看看會不會有一推錯誤訊息

2008年9月28日 星期日

Error: shared library "lthread.[35]" does not exist

今天心血來潮(颱風天無聊)!
正在把把測試機的 mysql 更新到新版重編卻碰到了下面這個 Error
/bin/cat /usr/ports/devel/linuxthreads/pkg-message
Please see the README.FreeBSD file in the work directory for
instructions on how to compile with linuxthreads, and for other
issues and problems.
===> Registering installation for linuxthreads-2.2.3_23
===> Returning to build of mysql-server-5.0.67
Error: shared library "lthread.[35]" does not exist
*** Error code 1

Stop in /usr/ports/databases/mysql50-server.

一般習慣 FreeBSD 用 ports 安裝 MySQL 時會加的兩個參數 WITH_LINUXTHREADS=yes BUILD_STATIC=yes
資料中寫到
從FreeBSD5.x以後的版本下不用LINUXTHREAD啦,用libthr可以得到更好的性能,但是要編譯成動態模式,因此安裝的時候不要再帶這兩個選項了

在6.x上用這兩個選項還是可以安裝的,7.0開始就不行了

配置線程庫為libthr.so
ee /etc/libmap.conf

[mysqld]
libpthread.so.2 libthr.so.2
libpthread.so libthr.so

重啟MySQL。檢查
ldd /usr/local/libexec/mysqld
/usr/local/libexec/mysqld:
libz.so.4 => /lib/libz.so.4 (0x48662000)
libwrap.so.5 => /usr/lib/libwrap.so.5 (0x48674000)
libcrypt.so.4 => /lib/libcrypt.so.4 (0x4867b000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x48694000)
libm.so.5 => /lib/libm.so.5 (0x48780000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x48798000)
libthr.so.3 => /lib/libthr.so.3 (0x487a2000)
libc.so.7 => /lib/libc.so.7 (0x487b4000)

可以看到:libthr.so.3 => /lib/libthr.so.3 (0x487a2000)

代表OK了!

補充
kernel打開SCHED_ULE/PREEMPTION 可得更好效能

2007年2月10日 星期六

hack FreeNAS

由於FreeNAS除在 /conf/config.xml 可存檔紀錄 其餘設定檔or程式皆在開機時才由 mfsroot.gz 解出or啟動時建立, webCGI 可設定部分不夠進階需自行更改 mfsroot.gz 增設
  1. 新增群組&使用者
  2. 啟動 FTPD、SSHD
  3. 使用FTP連入抓取 /cf/mfsroot.gz
  4. mfsroot.gz 傳到 FreeBSD Server (kernel 6.2-PRERELEASE 版本同 FreeNAS 0.68)
  5. 解開 mfsroot.gz
    gzip -d mfsroot.gz
  6. 以建立RAM DISK方式將 mfsroot 載入 /dev/md1
    mdconfig -a -t vnode -f /home/XXX/mfsroot
  7. mount md1
    mount /dev/md1 /mnt/
  8. 複製編輯所需
    增加繁體中文語系檔 lang-TraditionalChinese.inc
    增加 csh.cshrc
    增加 ee、grep....工具程式
    /etc/inc/services.inc 服務設定檔 增加修改設定, 如 samba 要增加 ACC INFO MS WIN 等相關分享
  9. umount md1
  10. /dev/md1 卸除
    mdconfig -d -u 1
  11. 壓縮回 .gz
    gzip -9 mfsroot
  12. 使用putty連入FreeNAS
  13. umount /cf
  14. 將 /dev/ad0s1 mount 到臨時資料夾
  15. 用FTP傳回 mfsroot.gz 蓋掉原本的
  16. FreeNAS reboot