ESXi6 虚拟机 IO 直通

客户端OS: Debian12 AMD64

网络适配器: VMXNET 3

虚拟机分配内存: 8G

内存资源分配: 全部锁定

Note:

E1000 不支持直通

虚拟机内存太小(4G),不支持直通,出现错误:已连接网络的状况阻止directpath i/o

acme.sh with Google SSL certificate

Acme.sh issue SSL certificate with Google

Install acme.sh

    sudo su
    source ~/env.sh
    env|grep proxy|grep http

    curl https://get.acme.sh|sh
    exit
    sudo su
    source ~/env.sh
    source /root/.acme.sh/acme.sh.env
    acme.sh --set-default-ca --server google

Generae EAB:

# Must install Google Cloud SDK first
gcloud publicca external-account-keys create

Register Account:

acme.sh --register-account -m admin@zhenglei.net --server google --eab-kid "your KeyId" --eab-hmac-key "your b64MacKey"

Issue:

sudo su
   
   # Stop services listen 80/443 port
   #/opt/local/etc/init.d/openresty stop
  
   source ~/env.sh
   source /root/.acme.sh/acme.sh.env

   # Only have IP v6 public Address
   acme.sh  --issue  -d blog.zhenglei.net  --standalone --listen-v6

Install Google Cloud SDK on Debian system

Install google-cloud-cli

sudo su

source ~/proxy.sh
env|grep proxy|grep http

apt-get update
apt-get install apt-transport-https ca-certificates gnupg  curl socat

curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg

echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list

apt-get update
apt install google-cloud-cli
gcloud init

Install music-tag-web on debian system

Remote debian system

ssh remote.zhenglei.net
sudo su
docker pull xhongc/music_tag_web:latest
docker images
docker save -o music_tag_web.tar  xhongc/music_tag_web:latest

Local debian system

ssh local.zhenglei.net
scp remote.zhenglei.net:/${YOUR_PATH}/remote.zhenglei.net .
sudo su
docker load < music_tag_web.tar
docker image ls

Launch

sudo su
./music_tag_web.sh

cat music_tag_web.sh

#!/bin/bash
PORT=8001:8001
DATA=/Music
CFG=/docker/music/config

MTAG=xhongc/music_tag_web:latest

if [ ! -d ${CFG} ];then
  mkdir -p ${CFG}
fi

if [ ! -d ${DATA} ];then
  mkdir -p ${DATA}
fi

docker run -d -p ${PORT} -v ${DATA}:/app/media -v ${CFG}:/app/data --restart=always ${MTAG}

Verify

http://yor_ip:8001

default login: admin:admin

Stop

sudo su
docker stats
docker stop  $(docker ps -q)

Install ffmpeg

sudo apt-get instgall ffmpeg
which ffmpeg
# cd ${CFG}/bin
cd /docker/music/config/bin
sudo ln /usr/bin/ffmpeg

Install docker on Debian

sudo apt update

sudo apt upgrade

sudo apt install apt-transport-https ca-certificates curl software-properties-common gnupg2

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"

sudo apt update
sudo apt install docker-ce


sudo usermod -aG docker $USER

给家中的服务器, 分配 IPv6公网地址

条件:

中国电信光猫, Openwrt 路由器, 阿里云域名

Step 1: 路由器升级, 最新版 OpenWrt / 23.05.03

Step 2: 从电信获得 宽带帐号/宽带密码

Step 3: 设置光猫为Bridge 模式

Step 4: 路由器 Lan 接口 IPv4 地址设置为 10.0.0.1

Step 5: 路由器 Wan 接口 修改为 PPPoE 模式, PAP/CHAP username/password 填入从电信获得的 宽带帐号/宽带密码

Step 6: 因为PPPoE 拨号会同时获得 IPv4 和 IPv6地址,wan6 接口没用,删除wan6接口

Step 7: 重起wan接口,会自动拨号,若成功,自动增加wan_6虚拟接口,IPv6 和IPv6-PD

Step 8: 修改Lan接口Advanced Setting:

Delegate IPv6 prefixes = yes

IPv6 assignment length = 60

IPv6 prefix filter = wan_6

Step 9: 修改路由器 network/dhcp/Static Leases, 为每个IPv6公网网卡增加一项纪录:

包括: Hostname, Mac 地址,IPv4,IPv6-Suffix,

为方便记忆,我选择 IPv4 最后一栏与IPv6-Suffix 相同,

比如,mpd IPv4=10.0.0.222, mpd的IPv6-Suffix 设置为0222

Step 10: 根据应用需要,修改基于端口的防火墙:Network/Firewall/TrafficRules 增加纪录

至此,路由器设置完毕

域名更新

由于每次拨号,都会获得一个不同的IPv6-PD值

可以使用脚本程序,监控路由器中的IPv6-PD值,若有变化,调用域名服务商的API接口,更新IPv6值

https://github.com/zhengleic/ddns-aliyun

存在问题

发现重新拨号,IPv6-PD变化后,应用服务器可以自动获得新的IPv6,并访问外部网络,但无法从外部网络访问应用服务器

原因不详, 应用服务器为Debian 10

解决办法:

更新域名后,同时将应用服务器的网卡down/up一次: ifdown dev / ifup dev

Tailscale vpn bypass firewall

Sometime, we need to bypass the firewall.

Suppose there are two linux box, a local box and a remote box, the local box unable to access some URL, due to the firewall limitation, while the remote box have no limitation.

We setup one tailscale vpn between these two nodes, as describe in https://tailscale.com/kb/1017/install

Now we config a exit node, to bypass the firewall of the local linux box.

Remore linux: Enable IP forward & Add exit-node:

sudo sed -i “s/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/” /etc/sysctl.conf

sudo sed -i “s/#net.ipv6.conf.all.forwarding=1/net.ipv6.conf.all.forwarding=1/” /etc/sysctl.conf

sudo sysctl -p /etc/sysctl.conf
sudo tailscale up --advertise-exit-node

Tailscale admin webpage: Approve the exit node

Local linux:  Use exit-node:

sudo sed -i "s/#net.ipv4.conf.all.rp_filter=1/net.ipv4.conf.all.rp_filter=2/"  /etc/sysctl.conf


sudo sysctl -p /etc/sysctl.conf

sudo tailscale up --accept-routes --exit-node-allow-lan-access --exit-node=RemoteIP

Where RemoteIP is the vpn ip of remote node, say 100.113.189.45

Live Streaming with Android Handset

引用

Create your own streaming server with nginx

FWD: CamOn Living Streaming

Note: Have been verified on Redmi-6/MiUi 14, and openresty + RTMP Module + Linux

We saw how to setup a streaming server with MistServer in this post, let’s see how to do the same with nginx.

nginx, pronounced “engine X“, is a web server that can also be used as a reverse proxy, load balancer, mail proxy, HTTP cache and, why not, RTMP server. It is free and open-source software, released under the terms of the 2-clause BSD license.

For the purpose of this trial, we will see how to install and configure the server on a Raspberry Pi board running Raspberry Pi OS Lite.


Install nginx with RTMP support

First, we must install the server and an add-on module that will allow it to handle the RTMP protocol. sudo apt install nginxsudo apt install libnginx-mod-rtmp

After the installation is complete, we should be able to reach the welcome page simply by entering the IP address of the server in our favorite browser, http://192.168.1.18/ for us.


Configure the RTMP server

The way nginx and its modules work is determined in the configuration file. By default, the configuration file is named nginx.conf and placed in the directory /etc/nginx. For details, please check out the Beginner’s Guide and other resources available in the nginx documentation.

To enable the RTMP protocol, edit the configuration file sudo nano /etc/nginx/nginx.conf

then add these few lines at the very end # protocol imap; # proxy on; # } #}
rtmp { server { listen 1935; application live { live on;
hls on; hls_path /tmp/hls; } } }

finally save the file and restart the server so that the new configuration will be loaded sudo nginx -s reload

In this example, we are configuring the RTMP server to listen on the port 1935 (the default RTMP port), and to handle an application named live. This application has the live mode (one-to-many broadcasting) enabled. The HLS output is also enabled, the playlist and the fragments will be saved in /tmp/hls (if the directory does not exist it will be created).

The complete reference about the available RTMP directives can be found here.


Configure the HTTP server

We need to configure the HTTP server so that it can access the files in /tmp/hls for clients to play HLS. nginx uses the so called Server Blocks to serve multiple sites in parallel, let’s change the configuration of the default one sudo nano /etc/nginx/sites-enabled/default

by adding a new location entry according to the documentation location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. try_files $uri $uri/ =404; } location /hls { types { application/vnd.apple.mpegurl m3u8; } root /tmp; add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; } # pass PHP scripts to FastCGI server #

then save the file and restart the server once again sudo nginx -s reload


Configure the app

From CamON Live Streaming app settings, enable the Live streaming adapter and configure it

  • in he Server field, specify the RTMP URL for the application we configured, rtmp://192.168.1.18/live in this example
  • in the Stream field enter a streaming key of your choice, let’s use spynet

TIP: the streaming key will be used by nginx as the base name for the HLS files

To start the stream use the arrow icon in the bottom-right corner of the main screen. By tapping on it a countdown will be shown, at the end of which the device will connect to nginx.

TIP: during the countdown, tap on the arrow again if you wish to abort


Let’s see it in action

To verify that everything is working as expected, we can use VLC as the client to see the nginx broadcast.

It is possible to see the HLS output using the URL http://192.168.1.18/hls/spynet.m3u8, where hls is the location we configured for the HTTP server to find the files and spynet is the streaming key we have chosen.

It is also possible to see the RTMP output using the URL rtmp://192.168.1.18/live/spynet, where live is the name of the application we configured and spynet is the streaming key.


Embed the player

For a better user experience, we may want to embed the player in our web page, This way the broadcast will be available with no extra effort. As the player, Video.js is a good choice to see the HLS broadcast.

Let’s create our index.html page in /var/www/html sudo nano /var/www/html/index.html

with the following HTML code

TIP: the key point is to set the correct source, src=”/hls/spynet.m3u8″, as described above

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32<!DOCTYPE html> <html lang=”en”> <head> <link href=”https://vjs.zencdn.net/7.17.0/video-js.css” rel=”stylesheet” /> <!– If you’d like to support IE8 (for Video.js versions prior to v7) –> <script src=”https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js”></script> </head> <body> <h1>My nginx streaming server</h1> <video id=”my-video” class=”video-js” controls preload=”auto” width=”640″ height=”360″ data-setup=”{}” > <source src=”/hls/spynet.m3u8″ type=”application/vnd.apple.mpegurl m3u8″ /> <p class=”vjs-no-js”> To view this video please enable JavaScript, and consider upgrading to a web browser that <a href=”https://videojs.com/html5-video-support/” target=”_blank”> supports HTML5 video </a> </p> </video> <script src=”https://vjs.zencdn.net/7.17.0/video.js”></script> </body> </html>

After the file has been saved (no need to restart the server), by navigating to address of the server, http://192.168.1.18/, we can see the new homepage in action


Some small tweaks

Since we are planning to broadcast our video over the Internet, we should make the server publicly reachable. To keep it simple, we should consider setting up port forwarding and the Dynamic DNS as described in this post.

In summary, if the router supports the UPnP protocol, we can use the command line utility upnpc to forward the HTTP port directly from the server. If not, we can manually configure the router. sudo apt install miniupnpcupnpc -a server_ipserver_portexternal_port tcpupnpc -a 192.168.1.18 80 8282 tcp

This way the server will be reachable from anywhere at http://public_ip_address:8282/ or http://myserver.dyndns.org:8282/.

As discussed, HLS is continuously writes files to disk while updating the playlist and the fragments. This consumes resources and can dramatically reduce the life of the SD card used by the server as storage. A better solution is to use a ramdisk to temporary store those files.

Examine the available memory to find out how much we can use. free -h

Examine the typical HLS disk usage to find out how much memory we expect to need. sudo du -sh /tmp/hls/

Create a folder where to mount the ramdisk. sudo mkdir -p /mnt/ramdisk

Add an entry to fstab to configure the ramdisk (50M is enough for this example). sudo nano /etc/fstabproc /proc proc defaults 0 0 PARTUUID=4b551375-01 /boot vfat defaults 0 2 PARTUUID=4b551375-02 / ext4 defaults,noatime 0 1 tmpfs /mnt/ramdisk tmpfs nodev,nosuid,noexec,nodiratime,size=50M 0 0

Reboot the server. sudo reboot

Verify that the ramdisk was mounted. sudo df -hFilesystem Size Used Avail Use% Mounted on /dev/root 3.4G 1.7G 1.6G 52% / devtmpfs 87M 0 87M 0% /dev tmpfs 215M 0 215M 0% /dev/shm tmpfs 86M 632K 86M 1% /run tmpfs 5.0M 4.0K 5.0M 1% /run/lock tmpfs 50M 0 50M 0% /mnt/ramdisk /dev/mmcblk0p1 253M 49M 204M 20% /boot tmpfs 43M 0 43M 0% /run/user/1000

Change the nginx configuration so that HLS files will be saved in /mnt/ramdisk/hls instead of in /tmp/hls. sudo nano /etc/nginx/nginx.confrtmp { server { listen 1935; application live { live on; hls on; hls_path /mnt/ramdisk/hls; } } }

Change the nginx configuration so that the HTTP server will know where to find the HLS files. sudo nano /etc/nginx/sites-enabled/default location /hls { types { application/vnd.apple.mpegurl m3u8; } root /mnt/ramdisk; add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; }

Restart the server. sudo nginx -s reload

Verify that the ramdisk is now used. sudo df -hFilesystem Size Used Avail Use% Mounted on /dev/root 3.4G 1.7G 1.6G 52% / devtmpfs 87M 0 87M 0% /dev tmpfs 215M 0 215M 0% /dev/shm tmpfs 86M 632K 86M 1% /run tmpfs 5.0M 4.0K 5.0M 1% /run/lock tmpfs 50M 12M 39M 24% /mnt/ramdisk /dev/mmcblk0p1 253M 49M 204M 20% /boot tmpfs 43M 0 43M 0% /run/user/1000

Your server should now run much smoother!

Play DSD dff file within MPD daemon

To support play DSD dff file inrealtime mode, we must add dsdiff plugin in mpd config file.

decoder {
  plugin “ffmpeg”
  enable “yes”
}

decoder {
  plugin “dsdiff”
  enable “yes”
}

cat mpd.conf

music_directory     “/music”
playlist_directory “/opt/local/run/mpd/playlists”
db_file            “/opt/local/run/mpd/database”
log_file       “/opt/local/run/mpd/log”
pid_file       “/opt/local/run/mpd/mpd.pid”
state_file         “/opt/local/run/mpd/state”
sticker_file      “/opt/local/run/mpd/sticker.sql”

user           “root”
group          “root”
bind_to_address         “any”
#bind_to_address       “localhost”
bind_to_address         “/opt/local/run/mpd/socket”
port           “6600”


# default=notice
# secure=info

log_level      “default”
#log_level              “secure”
#log_level              “verbose”
#log_level              “warning”
#log_level              “error”



restore_paused         “no”
save_absolute_paths_in_playlists  “no”
metadata_to_use  “artist,album,title,track,name,genre,date,composer,performer,disc”

auto_update        “yes”
auto_update_depth      “8”


follow_outside_symlinks        “yes”
follow_inside_symlinks      “yes”



zeroconf_enabled       “yes”
zeroconf_name          “Music Player @ %h”


#password                        “password@read,add,control,admin”
default_permissions         “read,add,control,admin”



#database {
#       plugin “proxy”
#       host “other.mpd.host”
#       port “6600”
#}


decoder {
  plugin “ffmpeg”
  enable “yes”
}

decoder {
  plugin “dsdiff”
  enable “yes”
}


#input {
#        plugin “curl”
#       proxy “proxy.isp.com:8080”
#       proxy_user “user”
#       proxy_password “password”
#}


#audio_output {
#   type       “alsa”
#   name       “ALSA”
#   device     “hw:0,0”   # optional
#   mixer_type      “hardware” # optional
#   mixer_device   “default”  # optional
#   mixer_control  “PCM”      # optional
#   mixer_index “0”     # optional
#}

#audio_output {
#    type                    “fifo”
#    name                    “my_fifo”
#    path                    “/tmp/mpd.fifo”
#    format                  “44100:16:2”
#}


# creative usb card
#audio_output {
#        type            “alsa”
#        name            “MP3”
#        device          “hw:CARD=MP3,DEV=0”
#        mixer_type      “software”      # optional
#}


#audio_output {
#        type            “alsa”
#        name            “TerraTec”
#        device          “iec958:CARD=Device,DEV=0”
#        mixer_type      “software”      # optional
#}

#audio_output {
#        type            “alsa”
#        name            “C-Media”
#        device          “iec958:CARD=Set,DEV=0”
#        mixer_type      “hardware”      # optional
#}

# Via Winner AD-86D amplifer
audio_output {
        type            “alsa”
        name            “Audio”
        device          “hw:CARD=AUDIO,DEV=0”
        mixer_type      “software”    
}



# via Jack Daemon
#audio_output {
#        type “jack”
#        name “My Jack Output”
#        mixer_type      “software”
#}



#
# An example of an OSS output:
#
#audio_output {
#   type       “oss”
#   name       “My OSS Device”
##  device     “/dev/dsp” # optional
##  mixer_type      “hardware” # optional
##  mixer_device   “/dev/mixer”   # optional
##  mixer_control  “PCM”      # optional
#}
#
# An example of a shout output (for streaming to Icecast):
#
#audio_output {
#   type       “shout”
#   encoder    “vorbis”       # optional
#   name       “My Shout Stream”
#   host       “localhost”
#   port       “8000”
#   mount      “/mpd.ogg”
#   password   “hackme”
#   quality    “5.0”
#   bitrate    “128”
#   format     “44100:16:1”
##  protocol   “icecast2”     # optional
##  user       “source”       # optional
##  description “My Stream Description”    # optional
##  url     “http://example.com”   # optional
##  genre      “jazz”         # optional
##  public     “no”           # optional
##  timeout    “2”        # optional
##  mixer_type      “software”     # optional
#}
#
# An example of a recorder output:
#
#audio_output {
#   type       “recorder”
#   name       “My recorder”
#   encoder    “vorbis”       # optional, vorbis or lame
#   path       “/opt/local/run/mpd/recorder/mpd.ogg”
##  quality    “5.0”          # do not define if bitrate is defined
#   bitrate    “128”          # do not define if quality is defined
#   format     “44100:16:1”
#}
#
# An example of a httpd output (built-in HTTP streaming server):
#
#audio_output {
#   type       “httpd”
#   name       “My HTTP Stream”
#   encoder    “vorbis”       # optional, vorbis or lame
#   port       “8000”
#   bind_to_address “0.0.0.0”      # optional, IPv4 or IPv6
##  quality    “5.0”          # do not define if bitrate is defined
#   bitrate    “128”          # do not define if quality is defined
#   format     “44100:16:1”
#   max_clients “0”        # optional 0=no limit
#}
#
# An example of a pulseaudio output (streaming to a remote pulseaudio server)
#
#audio_output {
#   type       “pulse”
#   name       “My Pulse Output”
##  server     “remote_server”    # optional
##  sink       “remote_server_sink”   # optional
#}
#
# An example of a winmm output (Windows multimedia API).
#
#audio_output {
#   type       “winmm”
#   name       “My WinMM output”
##  device     “Digital Audio (S/PDIF) (High Definition Audio Device)” # optional
#       or
##  device     “0”     # optional
##  mixer_type “hardware” # optional
#}
#
# An example of an openal output.
#
#audio_output {
#   type       “openal”
#   name       “My OpenAL output”
##  device     “Digital Audio (S/PDIF) (High Definition Audio Device)” # optional
#}
#
# An example of an sndio output.
#
#audio_output {
#   type       “sndio”
#   name       “sndio output”
#   mixer_type “hardware”
#}
#
# An example of an OS X output:
#
#audio_output {
#   type       “osx”
#   name       “My OS X Device”
##  device     “Built-in Output”  # optional
##  channel_map      “-1,-1,0,1”   # optional
#}
#
## Example “pipe” output:
#
#audio_output {
#   type       “pipe”
#   name       “my pipe”
#   command    “aplay -f cd 2>/dev/null”
## Or if you’re want to use AudioCompress
#   command    “AudioCompress -m | aplay -f cd 2>/dev/null”
## Or to send raw PCM stream through PCM:
#   command    “nc example.org 8765”
#   format     “44100:16:2”
#}
#
## An example of a null output (for no audio output):
#
#audio_output {
#   type       “null”
#   name       “My Null Output”
#   mixer_type      “none”         # optional
#}
#
###############################################################################


# Normalization automatic volume adjustments ##################################
#
# This setting specifies the type of ReplayGain to use. This setting can have
# the argument “off”, “album”, “track” or “auto”. “auto” is a special mode that
# chooses between “track” and “album” depending on the current state of
# random playback. If random playback is enabled then “track” mode is used.
# See <http://www.replaygain.org> for more details about ReplayGain.
# This setting is off by default.
#
#replaygain        “album”
#
# This setting sets the pre-amp used for files that have ReplayGain tags. By
# default this setting is disabled.
#
#replaygain_preamp     “0”
#
# This setting sets the pre-amp used for files that do NOT have ReplayGain tags.
# By default this setting is disabled.
#
#replaygain_missing_preamp “0”
#
# This setting enables or disables ReplayGain limiting.
# MPD calculates actual amplification based on the ReplayGain tags
# and replaygain_preamp / replaygain_missing_preamp setting.
# If replaygain_limit is enabled MPD will never amplify audio signal
# above its original level. If replaygain_limit is disabled such amplification
# might occur. By default this setting is enabled.
#
#replaygain_limit      “yes”
#
# This setting enables on-the-fly normalization volume adjustment. This will
# result in the volume of all playing audio to be adjusted so the output has
# equal “loudness”. This setting is disabled by default.
#
#volume_normalization      “no”
#
###############################################################################

# Character Encoding ##########################################################
#
# If file or directory names do not display correctly for your locale then you
# may need to modify this setting.
#
#filesystem_charset        “UTF-8”
#
###############################################################################