Docker部署开源客户沟通平台ChatWoot

Chatwoot 简介

Chatwoot 是一款开源的多渠道客户支持平台,旨在帮助企业建立强大、高效的客户服务体系。以下是 Chatwoot 的一些主要特点和功能:

多渠道支持:    Chatwoot 支持通过多种渠道与客户进行互动,包括实时聊天、电子邮件、社交媒体(如 Facebook 和 Twitter)等。
实时聊天:      提供实时聊天功能,使客服团队能够与客户实时互动,解决问题并提供支持。
帮助中心功能:   Chatwoot 还提供强大的帮助中心功能,帮助企业创建和维护丰富的知识库,使客户能够自助获取信息,提高服务效率。
电子邮件集成:   可以集成多个电子邮件账户,使客服团队能够通过 Chatwoot 统一管理和回复客户的电子邮件。
自动化和工作流: 提供自动化工作流和规则引擎,帮助优化客户服务流程,提高效率。
开放源代码:    Chatwoot 是开源软件,你可以自由查看、修改和定制其代码以满足特定需求。
多语言支持:    提供多语言支持,适应全球范围内的用户和客户。
团队协作:      支持多用户和团队协作,使团队成员能够协同工作,提供一致的客户支持。
跟踪和分析:    提供报告和分析工具,帮助你了解客户服务绩效,并采取相应的改进措施。

通过使用 Chatwoot,企业可以更好地管理和响应客户请求,提高客户满意度,同时保持对话历史记录,以更好地了解客户需求。

使用 Docker 部署

一、安装docker

先设置一下配置文件
mkdir /etc/docker && nano -w /etc/docker/daemon.json

{
  "data-root": "/srv/docker",
  "dns": ["8.8.8.8", "8.8.4.4"]
}

Docker 20.10.13 版本起,docker-compose 被替换为 docker compose(插件形式),可以直接用 pacman 安装:

1️⃣ 安装 Docker 和 Compose 插件

pacman -S docker docker-compose

2️⃣ 启动 Docker

systemctl enable --now docker

3️⃣ 验证 docker compose 是否可用

docker compose version

如果安装成功,你应该会看到类似输出:

Docker Compose version 2.32.4

二、配置服务器

创建程序目录

/srv && mkdir chatwoot && cd chatwoot

创建数据目录

mkdir -p ./{postgres,redis,storage}

设置环境变量

wget -O .env https://raw.githubusercontent.com/chatwoot/chatwoot/develop/.env.example

env 环境变量文件

wget -O .env https://raw.githubusercontent.com/chatwoot/chatwoot/develop/.env.example

SECRET_KEY_BASE :     可以用命令 openssl rand -base64 32 来生成;
FRONTEND_URL :        前端地址,根据实际情况填写,例如 http://127.0.0.1:3000,或具体ip,例如http://192.168.0.10:3000
HELPCENTER_URL :      帮助中心地址,可以和 FRONTEND_URL 一样
POSTGRES_PASSWORD:    PostgresSQL 数据库密码,这个密码需要与 docker-compose.yaml 里的 PostgresSQL 密码一致

nano -w .env

# Learn about the various environment variables at
# https://www.chatwoot.com/docs/self-hosted/configuration/environment-variables/#rails-production-variables

# Used to verify the integrity of signed cookies. so ensure a secure value is set
# SECRET_KEY_BASE should be alphanumeric. Avoid special characters or symbols. 
# Use `rake secret` to generate this variable
SECRET_KEY_BASE=BJ/aKkDoj1E0HqwtwqXSE9gcqd5hzG8tgT809UV0zM4=

# Replace with the URL you are planning to use for your app
FRONTEND_URL=http://116.202.96.177:3000
# To use a dedicated URL for help center pages
# HELPCENTER_URL=http://0.0.0.0:3000
HELPCENTER_URL=http://116.202.96.177:3000

# If the variable is set, all non-authenticated pages would fallback to the default locale.
# Whenever a new account is created, the default language will be DEFAULT_LOCALE instead of en
# DEFAULT_LOCALE=en

# If you plan to use CDN for your assets, set Asset CDN Host
ASSET_CDN_HOST=

# Force all access to the app over SSL, default is set to false
FORCE_SSL=false

# This lets you control new sign ups on your chatwoot installation
# true : default option, allows sign ups
# false : disables all the end points related to sign ups
# api_only: disables the UI for signup, but you can create sign ups via the account apis
ENABLE_ACCOUNT_SIGNUP=false

# Redis config
# specify the configs via single URL or individual variables
# ref: https://www.iana.org/assignments/uri-schemes/prov/redis
# You can also use the following format for the URL: redis://:password@host:port/db_number
REDIS_URL=redis://redis:6379
# If you are using docker-compose, set this variable's value to be any string,
# which will be the password for the redis service running inside the docker-compose
# to make it secure
REDIS_PASSWORD=
# Redis Sentinel can be used by passing list of sentinel host and ports e,g. sentinel_host1:port1,sentinel_host2:port2
REDIS_SENTINELS=
# Redis sentinel master name is required when using sentinel, default value is "mymaster".
# You can find list of master using "SENTINEL masters" command
REDIS_SENTINEL_MASTER_NAME=

# By default Chatwoot will pass REDIS_PASSWORD as the password value for sentinels
# Use the following environment variable to customize passwords for sentinels.
# Use empty string if sentinels are configured with out passwords
# REDIS_SENTINEL_PASSWORD=

# Redis premium breakage in heroku fix
# enable the following configuration
# ref: https://github.com/chatwoot/chatwoot/issues/2420
# REDIS_OPENSSL_VERIFY_MODE=none

# Postgres Database config variables
# You can leave POSTGRES_DATABASE blank. The default name of
# the database in the production environment is chatwoot_production
# POSTGRES_DATABASE=
POSTGRES_HOST=postgres
POSTGRES_USERNAME=postgres
POSTGRES_PASSWORD=password
RAILS_ENV=development
# Changes the Postgres query timeout limit. The default is 14 seconds. Modify only when required.
# POSTGRES_STATEMENT_TIMEOUT=14s
RAILS_MAX_THREADS=5

# The email from which all outgoing emails are sent
# could user either  `email@yourdomain.com` or `BrandName <email@yourdomain.com>`
MAILER_SENDER_EMAIL=Chatwoot <accounts@chatwoot.com>

#SMTP domain key is set up for HELO checking
SMTP_DOMAIN=chatwoot.com
# Set the value to "mailhog" if using docker-compose for development environments,
# Set the value as "localhost" or your SMTP address in other environments
# If SMTP_ADDRESS is empty, Chatwoot would try to use sendmail(postfix)
SMTP_ADDRESS=
SMTP_PORT=1025
SMTP_USERNAME=
SMTP_PASSWORD=
# plain,login,cram_md5
SMTP_AUTHENTICATION=
SMTP_ENABLE_STARTTLS_AUTO=true
# Can be: 'none', 'peer', 'client_once', 'fail_if_no_peer_cert', see http://api.rubyonrails.org/classes/ActionMailer/Base.html
SMTP_OPENSSL_VERIFY_MODE=peer
# Comment out the following environment variables if required by your SMTP server
# SMTP_TLS=
# SMTP_SSL=
# SMTP_OPEN_TIMEOUT
# SMTP_READ_TIMEOUT

# Mail Incoming
# This is the domain set for the reply emails when conversation continuity is enabled
MAILER_INBOUND_EMAIL_DOMAIN=
# Set this to the appropriate ingress channel with regards to incoming emails
# Possible values are :
# relay for Exim, Postfix, Qmail
# mailgun for Mailgun
# mandrill for Mandrill
# postmark for Postmark
# sendgrid for Sendgrid
RAILS_INBOUND_EMAIL_SERVICE=
# Use one of the following based on the email ingress service
# Ref: https://edgeguides.rubyonrails.org/action_mailbox_basics.html
# Set this to a password of your choice and use it in the Inbound webhook
RAILS_INBOUND_EMAIL_PASSWORD=

MAILGUN_INGRESS_SIGNING_KEY=
MANDRILL_INGRESS_API_KEY=

# Creating Your Inbound Webhook Instructions for Postmark and Sendgrid:
# Inbound webhook URL format:
#    https://actionmailbox:[YOUR_RAILS_INBOUND_EMAIL_PASSWORD]@[YOUR_CHATWOOT_DOMAIN.COM]/rails/action_mailbox/[RAILS_INBOUND_EMAIL_SERVICE]/inbound_emails
# Note: Replace the values inside the brackets; do not include the brackets themselves.
# Example: https://actionmailbox:mYRandomPassword3@chatwoot.example.com/rails/action_mailbox/postmark/inbound_emails
# For Postmark
# Ensure the 'Include raw email content in JSON payload' checkbox is selected in the inbound webhook section.

# Storage
ACTIVE_STORAGE_SERVICE=local

# Amazon S3
# documentation: https://www.chatwoot.com/docs/configuring-s3-bucket-as-cloud-storage
S3_BUCKET_NAME=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=

# Log settings
# Disable if you want to write logs to a file
RAILS_LOG_TO_STDOUT=true
LOG_LEVEL=info
LOG_SIZE=500
# Configure this environment variable if you want to use lograge instead of rails logger
#LOGRAGE_ENABLED=true

### This environment variables are only required if you are setting up social media channels

# Facebook
# documentation: https://www.chatwoot.com/docs/facebook-setup
FB_VERIFY_TOKEN=
FB_APP_SECRET=
FB_APP_ID=

# https://developers.facebook.com/docs/messenger-platform/instagram/get-started#app-dashboard
IG_VERIFY_TOKEN=

# Twitter
# documentation: https://www.chatwoot.com/docs/twitter-app-setup
TWITTER_APP_ID=
TWITTER_CONSUMER_KEY=
TWITTER_CONSUMER_SECRET=
TWITTER_ENVIRONMENT=

#slack integration
SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=

# Google OAuth
GOOGLE_OAUTH_CLIENT_ID=
GOOGLE_OAUTH_CLIENT_SECRET=
GOOGLE_OAUTH_CALLBACK_URL=

### Change this env variable only if you are using a custom build mobile app
## Mobile app env variables
IOS_APP_ID=L7YLMN4634.com.chatwoot.app
ANDROID_BUNDLE_ID=com.chatwoot.app

# https://developers.google.com/android/guides/client-auth (use keytool to print the fingerprint in the first section)
ANDROID_SHA256_CERT_FINGERPRINT=AC:73:8E:DE:EB:56:EA:CC:10:87:02:A7:65:37:7B:38:D4:5D:D4:53:F8:3B:FB:D3:C6:28:64:1D:AA:08:1E:D8

### Smart App Banner
# https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/PromotingAppswithAppBanners/PromotingAppswithAppBanners.html
# You can find your app-id in https://itunesconnect.apple.com
#IOS_APP_IDENTIFIER=1495796682

## Push Notification
## generate a new key value here : https://d3v.one/vapid-key-generator/
# VAPID_PUBLIC_KEY=
# VAPID_PRIVATE_KEY=
#
# for mobile apps
# FCM_SERVER_KEY=

### APM and Error Monitoring configurations
## Elastic APM
## https://www.elastic.co/guide/en/apm/agent/ruby/current/getting-started-rails.html
# ELASTIC_APM_SERVER_URL=
# ELASTIC_APM_SECRET_TOKEN=

## Sentry
# SENTRY_DSN=


## Scout
## https://scoutapm.com/docs/ruby/configuration
# SCOUT_KEY=YOURKEY
# SCOUT_NAME=YOURAPPNAME (Production)
# SCOUT_MONITOR=true

## NewRelic
# https://docs.newrelic.com/docs/agents/ruby-agent/configuration/ruby-agent-configuration/
# NEW_RELIC_LICENSE_KEY=
# Set this to true to allow newrelic apm to send logs.
# This is turned off by default.
# NEW_RELIC_APPLICATION_LOGGING_ENABLED=

## Datadog
## https://github.com/DataDog/dd-trace-rb/blob/master/docs/GettingStarted.md#environment-variables
# DD_TRACE_AGENT_URL=

# MaxMindDB API key to download GeoLite2 City database
# IP_LOOKUP_API_KEY=

## Rack Attack configuration
## To prevent and throttle abusive requests
# ENABLE_RACK_ATTACK=true
# RACK_ATTACK_LIMIT=300
# ENABLE_RACK_ATTACK_WIDGET_API=true

## Running chatwoot as an API only server
## setting this value to true will disable the frontend dashboard endpoints
# CW_API_ONLY_SERVER=false

## Development Only Config
# if you want to use letter_opener for local emails
# LETTER_OPENER=true
# meant to be used in github codespaces
# WEBPACKER_DEV_SERVER_PUBLIC=

# If you want to use official mobile app,
# the notifications would be relayed via a Chatwoot server
ENABLE_PUSH_RELAY_SERVER=true

# Stripe API key
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=

# Set to true if you want to upload files to cloud storage using the signed url
# Make sure to follow https://edgeguides.rubyonrails.org/active_storage_overview.html#cross-origin-resource-sharing-cors-configuration on the cloud storage after setting this to true.
DIRECT_UPLOADS_ENABLED=

#MS OAUTH creds
AZURE_APP_ID=
AZURE_APP_SECRET=

## Advanced configurations
## Change these values to fine tune performance
# control the concurrency setting of sidekiq
# SIDEKIQ_CONCURRENCY=10


# AI powered features
## OpenAI key
# OPENAI_API_KEY=

# Housekeeping/Performance related configurations
# Set to true if you want to remove stale contact inboxes
# contact_inboxes with no conversation older than 90 days will be removed
# REMOVE_STALE_CONTACT_INBOX_JOB_STATUS=false

docker-compose.yaml

wget -O docker-compose.yaml https://raw.githubusercontent.com/chatwoot/chatwoot/develop/docker-compose.production.yaml
version: '3'

services:
  base: &base
    image: chatwoot/chatwoot:latest
    env_file: .env ## Change this file for customized env variables
    volumes:
      - ./storage:/app/storage

  rails:
    <<: *base
    depends_on:
      - postgres
      - redis
    ports:
      - '127.0.0.1:3000:3000'
    environment:
      - NODE_ENV=production
      - RAILS_ENV=production
      - INSTALLATION_ENV=docker
    entrypoint: docker/entrypoints/rails.sh
    command: ['bundle', 'exec', 'rails', 's', '-p', '3000', '-b', '0.0.0.0']
    restart: always

  sidekiq:
    <<: *base
    depends_on:
      - postgres
      - redis
    environment:
      - NODE_ENV=production
      - RAILS_ENV=production
      - INSTALLATION_ENV=docker
    command: ['bundle', 'exec', 'sidekiq', '-C', 'config/sidekiq.yml']
    restart: always

  postgres:
    image: pgvector/pgvector:pg16
    restart: always
    ports:
      - '127.0.0.1:5432:5432'
    volumes:
      - ./postgres:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=chatwoot
      - POSTGRES_USER=postgres
      # Please provide your own password.
      - POSTGRES_PASSWORD=password

  redis:
    image: redis:alpine
    restart: always
    command: ["sh", "-c", "redis-server --requirepass \"$REDIS_PASSWORD\""]
    env_file: .env
    volumes:
      - ./redis:/data
    ports:
      - '127.0.0.1:6479:6379'

准备数据库

docker compose run --rm rails bundle exec rails db:chatwoot_prepare
[root@archlinux chatwoot]# docker compose run --rm rails bundle exec rails db:chatwoot_prepare
[+] Running 26/26
 ✔ postgres Pulled                                                                                                                                                                                                                                         6.9s 
   ✔ a480a496ba95 Pull complete                                                                                                                                                                                                                            2.2s 
   ✔ 894a87c2a602 Pull complete                                                                                                                                                                                                                            2.2s 
   ✔ 5c683167ebb4 Pull complete                                                                                                                                                                                                                            2.4s 
   ✔ a4a2ff601989 Pull complete                                                                                                                                                                                                                            2.5s 
   ✔ f9f18b35445d Pull complete                                                                                                                                                                                                                            2.8s 
   ✔ 4341d9f4d10b Pull complete                                                                                                                                                                                                                            2.9s 
   ✔ d75b4dfa7494 Pull complete                                                                                                                                                                                                                            2.9s 
   ✔ 79531d2c07af Pull complete                                                                                                                                                                                                                            3.0s 
   ✔ 38d735e5fe5b Pull complete                                                                                                                                                                                                                            6.4s 
   ✔ 021a1a38fd6a Pull complete                                                                                                                                                                                                                            6.5s 
   ✔ f79edff05c77 Pull complete                                                                                                                                                                                                                            6.5s 
   ✔ 09219b44bd7a Pull complete                                                                                                                                                                                                                            6.5s 
   ✔ 9b2fb85f538d Pull complete                                                                                                                                                                                                                            6.5s 
   ✔ 1a6cb584f284 Pull complete                                                                                                                                                                                                                            6.5s 
   ✔ 4f41ac91f783 Pull complete                                                                                                                                                                                                                            6.6s 
   ✔ 1329a6ef5c19 Pull complete                                                                                                                                                                                                                            6.7s 
 ✔ redis Pulled                                                                                                                                                                                                                                            2.3s 
   ✔ 1f3e46996e29 Pull complete                                                                                                                                                                                                                            1.2s 
   ✔ 12fe5ac456cc Pull complete                                                                                                                                                                                                                            1.4s 
   ✔ 388474e9a6f9 Pull complete                                                                                                                                                                                                                            1.6s 
   ✔ adb45f7190c7 Pull complete                                                                                                                                                                                                                            1.7s 
   ✔ 3502a8ad5915 Pull complete                                                                                                                                                                                                                            2.1s 
   ✔ 05de3e1b5dd0 Pull complete                                                                                                                                                                                                                            2.1s 
   ✔ 4f4fb700ef54 Pull complete                                                                                                                                                                                                                            2.1s 
   ✔ a863f8dcffe5 Pull complete                                                                                                                                                                                                                            2.1s 
[+] Creating 3/3
 ✔ Network chatwoot_default       Created                                                                                                                                                                                                                  0.1s 
 ✔ Container chatwoot-redis-1     Created                                                                                                                                                                                                                  0.0s 
 ✔ Container chatwoot-postgres-1  Created                                                                                                                                                                                                                  0.0s 
[+] Running 2/2
 ✔ Container chatwoot-redis-1     Started                                                                                                                                                                                                                  0.3s 
 ✔ Container chatwoot-postgres-1  Started                                                                                                                                                                                                                  0.3s 
[+] Running 12/12
 ✔ rails Pulled                                                                                                                                                                                                                                           28.2s 
   ✔ b84a74cde5af Pull complete                                                                                                                                                                                                                            0.4s 
   ✔ c895ececcf9a Pull complete                                                                                                                                                                                                                            1.5s 
   ✔ 1a7293d14d6f Pull complete                                                                                                                                                                                                                            1.6s 
   ✔ e6b6ac5b3a26 Pull complete                                                                                                                                                                                                                            2.9s 
   ✔ e894f191bace Pull complete                                                                                                                                                                                                                            2.9s 
   ✔ 2f064b36509f Pull complete                                                                                                                                                                                                                            7.6s 
   ✔ ada3f8e9dfa9 Pull complete                                                                                                                                                                                                                            7.6s 
   ✔ 69219aa0a172 Pull complete                                                                                                                                                                                                                           25.1s 
   ✔ 9b55ccc9f75c Pull complete                                                                                                                                                                                                                           28.1s 
   ✔ a9c5df089efc Pull complete                                                                                                                                                                                                                           28.1s 
   ✔ 4f4fb700ef54 Pull complete                                                                                                                                                                                                                           28.1s 
+ rm -rf /app/tmp/pids/server.pid
+ rm -rf '/app/tmp/cache/*'
+ echo 'Waiting for postgres to become ready....'
Waiting for postgres to become ready....
+ docker/entrypoints/helpers/pg_database_url.rb
+ export 'POSTGRES_PORT=5432'
+ PG_READY='pg_isready -h postgres -p 5432 -U postgres'
+ pg_isready -h postgres -p 5432 -U postgres
postgres:5432 - accepting connections
+ echo 'Database ready to accept connections.'
Database ready to accept connections.
+ bundle install
Bundle complete! 127 Gemfile dependencies, 253 gems now installed.
Gems in the groups 'development' and 'test' were not installed.
Bundled gems are installed into `/gems`
1 installed gem you directly depend on is looking for funding.
  Run `bundle fund` for details
+ BUNDLE='bundle check'
+ bundle check
The Gemfile's dependencies are satisfied
+ exec bundle exec rails db:chatwoot_prepare
I, [2025-02-11T01:13:47.659755 #1]  INFO -- : [rake ip_lookup:setup] IP_LOOKUP_API_KEY empty. Skipping geoip database setup
Created database 'chatwoot_production'

三、启动与停止服务

[root@archlinux chatwoot]# docker compose down
WARN[0000] /srv/chatwoot/docker-compose.yaml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion 
[+] Running 3/3
 ✔ Container chatwoot-postgres-1  Removed                                                                                                                                                                                                                  0.3s 
 ✔ Container chatwoot-redis-1     Removed                                                                                                                                                                                                                  0.3s 
 ✔ Network chatwoot_default       Removed                                                                                                                                                                                                                  0.1s 
[root@archlinux chatwoot]# docker compose up -d
WARN[0000] /srv/chatwoot/docker-compose.yaml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion 
[+] Running 6/6
 ✔ Network chatwoot_default       Created                                                                                                                                                                                                                  0.1s 
 ✔ Container chatwoot-redis-1     Started                                                                                                                                                                                                                  1.0s 
 ✔ Container chatwoot-base-1      Started                                                                                                                                                                                                                  0.8s 
 ✔ Container chatwoot-postgres-1  Started                                                                                                                                                                                                                  1.0s 
 ✔ Container chatwoot-sidekiq-1   Started                                                                                                                                                                                                                  1.2s 
 ✔ Container chatwoot-rails-1     Started 

四、配置nginx

cd /etc/nginx/vhost/
nano -w yourdomain.com_ssl.conf

server {
  server_name <yourdomain.com>;

  # Point upstream to Chatwoot App Server
  set $upstream 127.0.0.1:3000;

  # Nginx strips out underscore in headers by default
  # Chatwoot relies on underscore in headers for API
  # Make sure that the config is set to on.
  underscores_in_headers on;
  location /.well-known {
    alias /var/www/ssl-proof/chatwoot/.well-known;
  }

  location / {
    proxy_pass_header Authorization;
    proxy_pass http://$upstream;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Ssl on; # Optional

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_http_version 1.1;
    proxy_buffering off;

    client_max_body_size 0;
    proxy_read_timeout 36000s;
    proxy_redirect off;
  }
  listen 80;
}
发表在 Ruby | Docker部署开源客户沟通平台ChatWoot已关闭评论

编译自己的干净的openwrt(x86 && C301 && acrh17)

一、安装依赖环境

# 大多数时候已经安装了
pacman -S zlib libtool findutils gawk gengetopt grep gettext unzip zip rsync subversion which
# 下面的是编译需要安装的
pacman -S binutils bzip2 gcc diffutils patch quilt flex make cmake automake autoconf automake bison screen asciidoc python perl

二、下载 24.10.0 稳定版[最新]

git clone -b v24.10.0 git://git.openwrt.org/openwrt/openwrt.git

或:

wget https://github.com/openwrt/openwrt/archive/refs/tags/v24.10.0.tar.gz

解压缩

tar xzvf v24.10.0.tar.gz
cd openwrt-24.10.0

这里使用feeds增加部分功能

增加xray的管理界面

nano -w feeds.conf.default

src-git-full luci_app_xray https://github.com/yichya/luci-app-xray

更新索引

./scripts/feeds update -a
./scripts/feeds install -a

修改默认语言和备份的文件
nano -w feeds/luci/modules/luci-base/root/etc/config/luci

config core main
         option lang auto
         option mediaurlbase /luci-static/bootstrap
         option resourcebase /luci-static/resources
config extern flash_keep  #如果没有,增加下列保留的配置项
        option uci      "/etc/config/"        
        option dropbear "/etc/dropbear/"
        option openvpn  "/etc/openvpn/"
        option passwd   "/etc/passwd"
        option opkg     "/etc/opkg.conf"        
        option firewall "/etc/firewall.user"
        option uploads  "/lib/uci/upload/"
        option dnsmasq        "/etc/dnsmasq.conf"
        option ocserv         "/etc/ocserv/"
        option openconnect    "/etc/openconnect"
        option samba          "/etc/samba/"  
        option qemu           "/etc/qemu"

这里做一个默认的配置包

default-settings
|– Makefile
|– files
| | `– 99-default-settings

Makefile

include $(TOPDIR)/rules.mk

PKG_NAME:=default-settings
PKG_VERSION:=1
PKG_RELEASE:=1
PKG_LICENSE:=GPLv3
PKG_LICENSE_FILES:=LICENSE

include $(INCLUDE_DIR)/package.mk

define Package/default-settings         #设置包信息和依赖
  SECTION:=luci
  CATEGORY:=LuCI
  TITLE:=LuCI support for Default Settings
  PKGARCH:=all
  DEPENDS:=+luci-base +luci 
endef

define Package/default-settings/description
        LuCI support for Default Settings.
endef

define Build/Compile
endef

# 把文件 99-default-settings 写入 /etc/uci-defaults/ 目录下,如果是其他文件的话也可以用这种方法把特定文件写入固件中,比如证书
define Package/default-settings/install
        $(INSTALL_DIR) $(1)/etc/uci-defaults
        $(INSTALL_BIN) ./files/99-default-settings $(1)/etc/uci-defaults/99-default-settings
endef

$(eval $(call BuildPackage,default-settings))

99-default-settings

#!/bin/sh

#可以直接通过uci的接口修改配置
#比如配置系统时区
uci set system.@system[0].hostname='ovsea'
uci set system.@system[0].timezone=CST-8
uci set system.@system[0].zonename=Asia/Shanghai
uci commit system

# 比如配置无线相关
uci set wireless.radio0.cell_density='0'
uci set wireless.default_radio0.ssid='ovsea'
uci set wireless.default_radio0.encryption='psk2'
uci set wireless.default_radio0.key='1234567890'
uci set wireless.radio1.cell_density='0'
uci set wireless.default_radio1.ssid='ovsea'
uci set wireless.default_radio1.encryption='psk2'
uci set wireless.default_radio1.key='1234567890'
uci commit wireless


#比如配置lan口和wan口
uci set network.lan.ipaddr="172.16.1.1"
uci set network.lan.netmask='255.255.255.0'
uci set network.lan.gateway='172.16.1.1'
uci set network.lan.dns='172.16.1.1 8.8.8.8 1.1.1.1'
uci set network.wan.proto="pppoe" 
uci set network.wan.username="账号"
uci set network.wan.password="密码"
uci commit network
/etc/init.d/network restart

uci set dhcp.lan.start='100'
uci set dhcp.lan.limit='150'
uci set dhcp.lan.leasetime='24h'
uci commit dhcp
/etc/init.d/dnsmasq restart

#比如配置 uhttpd 
#uci del uhttpd.main.listen_http
#uci del uhttpd.main.listen_https
#uci add_list uhttpd.main.listen_http=[::]:1089
#uci add_list uhttpd.main.listen_http=0.0.0.0:1089
#uci add_list uhttpd.main.listen_https=[::]:1443
#uci add_list uhttpd.main.listen_https=0.0.0.0:1443
#uci set uhttpd.main.rfc1918_filter=0
#uci set uhttpd.main.cert=/etc/ssl/certs/certificate.cer
#uci set uhttpd.main.key=/etc/ssl/certs/private.key
#uci set uhttpd.main.redirect_https=1
#uci commit uhttpd


#比如修改root默认密码和设置证书登陆的公钥
echo -e "admin\nadmin" | passwd root
echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCoDav+iFQ4xcrz+NrK+C71+sWc8mm0gS8Z9Vmz5Qv4Ey0yOBBxieundKQXxg2o5SO+/Shja99OLsciFU9qUIW6OF0+PXloAIguoXC5SBCJZtkmDAhdQw9FT4d3pdrovbvnbr6tTK3XxPHZa5zVCUwaUlGx+o3GGLCImelDHwirRVmOVzl+eAMffSvtPVF2Qeo25or2DTxmEZWtwGPPTza5QmwwkWG1FMJMwt7yHcL8Td1kcHLWFd8oLmubuimzS1WKQ1sdAnjp9GhiqI8qaXCpl3jHk05goGwlF85CrsFMLCeSo03uXxIxK0XmkX8DeDCDu8pM553s/+xLg6P9AuVgO7VLEh76bpIUERsnAFN52hWmATfe3HaH8UgvXMoPFikSB140Z7IljKqEHCvAers4Ej6Qlu/u4wa4Mg5hlWy3ta/kUarJMNN7RePiCrC2Y4bQ7U9X2dPqrHcd/ss7obQsBjpYwbZHxzO8uj+oHtTceFoSixMjMz7cGMNiyKQ3dhM= root@vmSrv' > /etc/dropbear/authorized_keys

####################

#### 其他配置 ####

####################

#结束一定要返回 0 只有返回0后,该文件在首次执行后才会被删除
#详见: https://openwrt.org/docs/guide-developer/uci-defaults
exit 0
chmod 755 99-default-settings

添加第三方源码ipk

把第三方ipk源码的package包放进source/feeds/packages目录
把第三方ipk源码的luci包放进source/feeds/luci/applications目录

部分默认参数的修改
增加代理ARP
nano -w package/base-files/files/etc/sysctl.d/10-default.conf

# Enables Proxy ARP on all interfaces
net.ipv4.conf.all.proxy_arp=1 
#net.ipv4.conf.eth0.proxy_arp=1

增加一些别名到shell
nano -w package/base-files/files/etc/profile

alias ls='ls --color=auto'
alias ll='ls -ls --color=auto'

增加diskman的界面

mkdir -p package/download/luci-app-diskman && \
wget https://raw.githubusercontent.com/lisaac/luci-app-diskman/master/applications/luci-app-diskman/Makefile -O package/download/luci-app-diskman/Makefile
mkdir -p package/download/parted && \
wget https://raw.githubusercontent.com/lisaac/luci-app-diskman/master/Parted.Makefile -O package/download/parted/Makefile

增加docker的界面(仅仅适用于x86)

mkdir -p package/download/luci-lib-docker && \
wget https://github.com/lisaac/luci-lib-docker/blob/master/collections/luci-lib-docker/Makefile -O package/download/luci-lib-docker/Makefile

mkdir -p package/download/luci-app-dockerman && \
wget https://github.com/lisaac/luci-app-dockerman/blob/master/applications/luci-app-dockerman/Makefile -O package/download/luci-app-dockerman/Makefile

最后执行make menuconfig

Global build settings
[*] Compile with full language support

进入配置菜单

Target System (x86)
Target System (Qualcomm Atheros IPQ40XX) ->ACRH17

Subtarget (x86_64)
Subtarget (Generic) ->ACRH17

Target Profile (Generic x86/64)
Target Profile (ASUS RT-AC42U) ->ACRH17

Target Images —>

======x86

(OvseaLink) Title for the menu entry in GRUB
[*] Build LiveCD image (ISO)
[*] Build VMware image files (VMDK)
(1024) Root filesystem partition size (in MiB) (NEW)

Image configuration —>
[*] Preinit configuration options —>
(172.16.1.1) IP address for preinit network messages
(255.255.255.0) Netmask for preinit network messages
(172.16.1.255) Broadcast address for preinit network messages

— Version configuration options
((OvseaLink) Release distribution
(1.0.0) Release version number
(Zebra) Release version code
(http://dl.magicwall.org:8/openwrt/18.06.4) Release repository
(http://gating.site) Release Homepage
(ZOTAC) Manufacturer name
(http://www.zotac.com) Manufacturer URL
(ZBOX) Product name
(CI325) Hardware revision

先选择LUCI,会自动选择依赖包
LuCI —> Collections —>
<*> luci
<*> luci-lib-docker
LuCI —> Modules —> Translations
<*> Chinese
LuCI —> Applications —>
<*> luci-app-adblock
<*> luci-app-ddns
<*> luci-app-diskman
<*> luci-app-dockerman
<*> luci-app-hd-idle
<*> luci-app-ksmbd
<*> luci-app-ocserv
<*> luci-app-p910nd
<*> luci-app-qos
<*> luci-app-statistics
<*> luci-app-transmission
<*> luci-app-upnp
<*> luci-app-wol
<*> luci-app-xfrpc

LuCI —> Protocols
<*> luci-proto-openconnect
<*> luci-proto-vpnc. 千万不能有,否则依赖libgpg-error,无法编译

Base syatem
–> <*> blockd
–> <*> dnsmasq
–> <*> wireless-tools

Administration
–> <*> btop

Firmware —>
<*> intel-microcode
<*> iwlwifi-firmware-iwl7260
<*> iwlwifi-firmware-iwl7265
<*> iwlwifi-firmware-iwl7265d
<*> iwlwifi-firmware-iwl8260c
<*> iwlwifi-firmware-iwl8265
<*> iwlwifi-firmware-iwl9000
<*> iwlwifi-firmware-iwl9260

Kernel modules
–>Block Devices
<*> kmod-nvme
<*> kmod-scsi-generic
–>Filesystems
-*- kmod-fs-cifs
<*> kmod-fs-ext4
<*> kmod-fs-ntfs3
–>Native Language Support
—> kmod-nls-utf8
–>Input modules
–>Network Devices
<*> kmod-e1000e
<*> kmod-igb
<*> kmod-igbvf
<*> kmod-r8125
<*> kmod-r8126
<*> kmod-r8168
<*> kmod-vmxnet3
–>Network Support
<*> kmod-pptp
<*> kmod-veth
–>USB Support —>
<*> kmod-usb-hid
<*> kmod-usb-printer
<*> kmod-usb-storage
<*> kmod-usb-storage-extras
Virtualization —>
<*> kmod-kvm-amd
<*> kmod-kvm-intel
<*> kmod-vfio-pci
<*> kmod-vhost-net
–>Wireless Drivers 无线网卡驱动


Libraries —>
<*> libintl-full
<*> libpam
Network
–>File Transfer
<*> curl
<*> rsync
<*> wget-ssl
–>SSH
<*> openssh-sftp-client
<*> openssh-sftp-server
–>VPN
<*> ocserv
-[*] enable seccomp
<*> openconnect
-SSL library (OpenSSL)
(X) OpenSSL
————————————–
<*> 6rd
<*> cifsmount
<*> ethtool-full
<*> geoipupdate
<*> ipset
<*> ipset-dns
<*> tcpdump
<*> xray-core

Utilities —>
<*> dockerd
Compression->
<*> bsdtar
<*> gzip
<*> unrar
<*> unzip
<*> xz-utils
<*> zstd
Disc ->
<*> blkid
<*> cfdisk
<*> hdparm
<*> nvme-cli
Editors —>
<*> nano-plus
Encryption —>
<*> gnupg
<*> gnutls-utils
Virtualization —>
<*> qemu-bridge-helper
<*> qemu-firmware-efi
<*> qemu-firmware-seabios
<*> qemu-firmware-seavgabios
<*> qemu-ga
<*> qemu-img
<*> qemu-nbd
<*> qemu-x86_64-softmmu
[*] QEMU VNC support
[*] QEMU VNC jpeg tight encoding support
[*] QEMU SPICE ui support
[*] QEMU USB passthrough support
[*] Enable support for seccomp in QEMU (NEW)
[*] QEMU ZSTD compression support
<*> virtio-console-helper

Extra packages —>
<*> luci-app-xray
<*> luci-app-xray-status

最后回到界面选择 EXIT 点保存回到命令提示符界面,

修改一次BUG, 否则会导致:
configure: error: Package requirements (protobuf >= 2.6.0) were not met:
需要把feeds/packages/libs/protobuf-c/Makefile的PKG_BUILD_DEPENDS:=protobuf-c/host改为PKG_BUILD_DEPENDS:=protobuf/host

输入nohup make -j8 download V=s & 可以下载dl包
输入nohup make -j1 V=sc &就可以正常编译了(耗时70分钟)
查看详细日志:nohup nohup.out

编译完成后清除之前的编译作业。(使用这个命令前,记得把编译好的固件备份出来,不然会被删除掉,切记)
make clean
恢复默认编译环境
make defconfig

编译单个模块

make package/qos/clean (清除某个模块)
make package/qos/compile (#单独编译某模块 #V=99表示输出详细的debug信息)
make package/qos/install

发表在 Linux | 编译自己的干净的openwrt(x86 && C301 && acrh17)已关闭评论

在macox M2里面使用vmware制作适用于oracle的archLinuxarm

1.下载安装文件包archboot

https://release.archboot.net/aarch64/latest/iso/

建议下载最大的iso结尾的版本, 减少网络依赖,安装完了以后再更新吧

2.vmware创建虚拟机,其他ARM64位版本,注意内存一定要选择到4G+,否则启动会被卡住

点击自定义配置
更改自己的文件路径

选择磁盘
更改类型为SCSI,关闭文件拆分

弄好了应用一下啊

修改内容到4G,否则启动困难

选第一个正常安装即可

3.压缩镜像包

拷贝VM文件包里面的 虚拟磁盘.vmdk, 然后进行转换和压缩

qemu-img convert -f vmdk -O raw 虚拟磁盘.vmdk archbase-aarch64.raw
xz -z archbase-aarch64.raw

4.在系统中恢复新的系统盘

复制到目标服务器

xzcat archbase-aarch64.raw.xz | dd of=/dev/sdb bs=4M status=progress

5.在控制台把磁盘设置成引导盘即可启动

发表在 Linux | 在macox M2里面使用vmware制作适用于oracle的archLinuxarm已关闭评论

ocserv 配合 freeradius 进行流量统计


ocserv 配合 FreeRADIUS 实现用户流量统计是一种常见的配置方式,通过 FreeRADIUS 的 radacct 表记录用户流量数据(包括上行流量、下行流量和总流量),并可进一步扩展为流量限制。

1. 安装和配置 FreeRADIUS

1.1 安装 FreeRADIUS

在服务器上安装 FreeRADIUS 和数据库支持(这里全部都是自己编译,因为需要支持MySQL):

pacman -U libmysqlclient* mysql-clients* freeradius* radcli* ocserv-allinone* 

1.2 配置数据库支持

1.2.0. 初始化数据库

mkdir -p /srv/mysql/{data,inno}
chown -R mysql:mysql /srv/mysql

nano -w /etc/mysql/my.cnf
innodb_data_home_dir = /srv/mysql/inno
innodb_log_group_home_dir = /srv/mysql/inno
basedir = /usr
datadir = /srv/mysql/data


mysqld --initialize --user=mysql --basedir=/usr --datadir=/srv/mysql/data --innodb_data_home_dir=/srv/mysql/inno --innodb_log_group_home_dir=/srv/mysql/inno

ALTER USER USER() IDENTIFIED BY 'password';

CREATE USER 'root'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

1.2.1. 创建数据库

登录数据库并创建 FreeRADIUS 的数据库和用户:

CREATE DATABASE radius;
CREATE USER 'radius'@'localhost' IDENTIFIED BY 'radius';
GRANT ALL PRIVILEGES ON radius.* TO 'radius'@'localhost';
FLUSH PRIVILEGES;

1.2.2. 导入 FreeRADIUS 数据库结构

mysql -u radius -p radius < /etc/raddb/mods-config/sql/main/mysql/schema.sql

修改表结构,方便统计操作

在 radcheck 和 radreply 表中添加 Domain 字段:

ALTER TABLE radcheck ADD COLUMN domain VARCHAR(64);
ALTER TABLE radreply ADD COLUMN domain VARCHAR(64);

创建用户

INSERT INTO radcheck (username, attribute, op, value, domain) 
VALUES ('test@domain.com', 'Cleartext-Password', ':=', 'password', 'domain.com');
  • username:用户名, @后的是主机名。
  • attribute:认证属性,Cleartext-Password 用于明文密码。
  • op:操作符,:= 表示赋值。
  • value:密码。
  • domain: 服务器的域名, 用于分开不同的服务器

添加应答属性(可选)
在 radreply 表中为用户配置会话的应答属性。
示例:VIP用户可以自定义路由

INSERT INTO radreply (username, attribute, op, value) 
VALUES ('user@domain.com', 'Framed-Route', ':=', '41.57.120.0/22');
  • attribute:应答属性,Framed-Route 表示分配的 IP 地址。
  • value:具体的值,这里是 41.57.120.0/22。

创建用户组

INSERT INTO radgroupcheck (groupname, attribute, op, value) VALUES ('free', 'Auth-Type', ':=', 'Accept');
INSERT INTO radgroupcheck (groupname, attribute, op, value) VALUES ('user', 'Auth-Type', ':=', 'Accept');
INSERT INTO radgroupcheck (groupname, attribute, op, value) VALUES ('vip', 'Auth-Type', ':=', 'Accept');
INSERT INTO radgroupcheck (groupname, attribute, op, value) VALUES ('admin', 'Auth-Type', ':=', 'Accept');
  • groupname:组的名称。
  • attribute:检查条件属性(如 Auth-Type)。
  • op:操作符,通常为 :=。
  • value:属性值(如 Accept)。

上面的配置了会导致计费功能失效,请不要设置,这里只是演示而已

将用户分配到组
在 radusergroup 表中,将用户加入指定组。
示例:将用户加入user 组, 注意,这里只是中间组, 由radius管理的, 实际的组需要在响应里面配置

INSERT INTO radusergroup (username, groupname, priority)
VALUES ('test@domain.com', 'vip', 1);
  • username:用户名。
  • groupname:组名(如 admin、user)。
  • priority:优先级,数值越小优先级越高。


配置组的返回属性
在 radgroupreply 表中,为组配置应答属性。

基础组匹配信息

INSERT INTO radgroupreply (groupname, attribute, op, value)
VALUES ('free', 'Class', '=', 'optimize');
INSERT INTO radgroupreply (groupname, attribute, op, value)
VALUES ('user', 'Class', '=', 'optimize');
INSERT INTO radgroupreply (groupname, attribute, op, value)
VALUES ('user', 'Class', '=', 'cnnoroute');
INSERT INTO radgroupreply (groupname, attribute, op, value)
VALUES ('vip', 'Class', '=', 'optimize');
INSERT INTO radgroupreply (groupname, attribute, op, value)
VALUES ('vip', 'Class', '=', 'cnnoroute');
INSERT INTO radgroupreply (groupname, attribute, op, value)
VALUES ('vip', 'Class', '=', 'transmitted');
  • groupname:组的名称。
  • attribute:返回的 RADIUS 属性(如 Class 表示组名)。
  • op:操作符, =为追加,:=为替换。
  • value:返回值(如组的标识 transmitted)。

1.2.3. 配置 FreeRADIUS 使用数据库

nano -w /etc/raddb/mods-available/sql

dialect = "mysql"
driver = "rlm_sql_${dialect}"

mysql {
        # If any of the files below are set, TLS encryption is enabled
        tls {
                #ca_file = "/etc/ssl/certs/my_ca.crt"
                #ca_path = "/etc/ssl/certs/"
                #certificate_file = "/etc/ssl/certs/private/client.crt"
                #private_key_file = "/etc/ssl/certs/private/client.key"
                #cipher = "DHE-RSA-AES256-SHA:AES128-SHA"

                tls_required = no 
                tls_check_cert = no
                tls_check_cert_cn = no
        }

        # If yes, (or auto and libmysqlclient reports warnings are
        # available), will retrieve and log additional warnings from
        # the server if an error has occured. Defaults to 'auto'
        warnings = auto
}

server = "localhost"
port = 3306
login = "radius"
password = "radius"
radius_db = "radius"

read_clients = yes
read_groups = yes          # 启用组功能


启用 SQL 模块

ln -s /etc/raddb/mods-available/sql /etc/raddb/mods-enabled/

1.2.4. 在 FreeRADIUS 服务器中配置

nano -w /etc/raddb/clients.conf , 也可在localhost里面直接改密码

client localhost {
    ipaddr = 127.0.0.1           # ocserv 的服务器地址
    secret = testing123          # 共享密钥
    shortname = ocserv           # 客户端的名称
    require_message_authenticator = yes
                                 # 发送包含 Message-Authenticator 的请求
    nas_type = other             # NAS 类型,可选值:other、cisco、nokia 等
}
  • ipaddr:客户端的 IP 地址(可以是单个 IP 或子网)
  • secret:共享密钥,需与客户端配置一致
  • shortname:客户端的标识名称(可选,用于日志和管理)

1.2.5 生成自签名证书

nano -w /etc/raddb/certs/ca.cnf
nano -w /etc/raddb/certs/server.cnf

[ req_distinguished_name ]
commonName = radius.example.com  # 将 "radius.example.com" 替换为主机名
cd /etc/raddb/certs
nano -w client.cnf         替换为主机名
./bootstrap

该脚本会生成以下文件:

  • server.pem:服务器证书
  • server.key:服务器私钥
  • ca.pem:CA 证书(客户端需要)

2. 配置 ocserv 使用 FreeRADIUS

2.1 安装 FreeRADIUS 客户端工具

先测试一下

[root@ocserv certs]# radtest test@domain.com password 127.0.0.1 0 testing123
Sent Access-Request Id 58 from 0.0.0.0:44492 to 127.0.0.1:1812 length 74
        User-Name = "test"
        User-Password = "password"
        NAS-IP-Address = 172.16.1.187
        NAS-Port = 0
        Message-Authenticator = 0x00
        Cleartext-Password = "password"
Received Access-Accept Id 34 from 127.0.0.1:1812 to 127.0.0.1:44805 length 83
        Message-Authenticator = 0x52136e587e33a7d07e8ee9c2a620ca1a
        Framed-IP-Address = 172.16.200.100
        Class = 0x6f7074696d697a65
        Framed-Route = "41.57.120.0/22 172.16.200.1"

2.2 配置 ocserv

nano -w /etc/ocserv/ocserv.conf

#auth = "radius[config=/etc/radiusclient.default/radiusclient.conf]"
auth = "radius[config=/etc/radcli/radiusclient.conf]"

注意不要覆盖本地组配置的组配置属性

2.3 配置 radiusclient.conf

#nano -w /etc/radiusclient.default/radiusclient.conf
nano -w /etc/radcli/radiusclient.conf

authserver 127.0.0.1
acctserver 127.0.0.1:1813

#servers                /etc/radiusclient/servers
servers                /etc/radiusclient.default/servers

#dictionary     /etc/radiusclient/dictionary
#dictionary      /etc/radiusclient.default/dictionary
dictionary     /usr/share/radcli/dictionary

#nano -w /etc/radiusclient.default/servers
nano -w /etc/radcli/servers

localhost/localhost                            testing123

3. 配置 FreeRADIUS 记录用户流量

3.1 启用会计记录

确保 FreeRADIUS 的 acct 模块启用,记录用户会话流量。

nano -w /etc/raddb/sites-available/default

authorize {
    ...
    -sql
    # 检查用户是否超出流量限制
    if ("%{sql:SELECT disabled FROM user_limits WHERE username = SUBSTRING_INDEX('%{SQL-User-Name}', '@', 1)}" == 1) {
        reject  # 立即拒绝认证
        update reply {
            Reply-Message := "Your account has been disabled due to exceeding the traffic limit."
        }
    }
    ...
}

accounting {
    ...
    -sql
    ...
}

session {
    ...
    sql
    ...
}

3.2 检查会计记录

• 用户连接后,FreeRADIUS 会在 radacct 表中记录用户流量信息。

• 可以通过以下 SQL 查询查看用户流量:

SELECT UserName, AcctInputOctets, AcctOutputOctets, AcctSessionTime FROM radacct;

4. 扩展:流量限制,自动禁用超出的用户

4.1 流量限制表

创建一个用于存储用户流量限制和状态的表:

CREATE TABLE user_limits (
username VARCHAR(64) PRIMARY KEY, — 用户名,统一限制流量,domain可以不同
maxtraffic BIGINT NOT NULL, — 最大流量限制(字节)
currenttraffic BIGINT DEFAULT 0, — 当前已用流量(字节)
disabled TINYINT(1) DEFAULT 0 — 用户是否被禁用(0: 启用, 1: 禁用)
);

4.2 为用户添加初始限额

连接后,可以通过以下 SQL 查询验证用户流量是否被正确记录:

INSERT INTO user_limits (username, maxtraffic) VALUES
('test', 21474836480);  -- 20 GB

5.3 显示用户每个月的流量

当用户流量超出 Max-Monthly-Traffic 值时,FreeRADIUS 会自动断开用户的 VPN 连接。

CREATE VIEW `radius`.`radtraffic` AS SELECT username,
       SUM(acctinputoctets + acctoutputoctets) AS totaltraffic
FROM radacct
WHERE acctstarttime >= DATE_FORMAT(NOW() ,'%Y-%m-01 00:00:00')
  AND acctstarttime < DATE_FORMAT(NOW() + INTERVAL 1 MONTH,'%Y-%m-01 00:00:00')
GROUP BY username;

5.4 通过 SQL 更新用户的流量数据到 user_limits 表

UPDATE user_limits ul
JOIN (
    SELECT 
        username,
        SUM(acctinputoctets) +
        SUM(acctoutputoctets) AS totaltraffic
    FROM radacct
    GROUP BY username
) rt ON ul.username = rt.username
SET ul.currenttraffic = rt.totaltraffic;

5.5 禁用超出流量限制的用户

UPDATE user_limits
SET disabled = 1
WHERE currenttraffic > maxtraffic;

5.6 禁用超出流量限制的用户

创建时间15分钟执行事件

CREATE EVENT `radius`.`radlimit`
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL '15' MINUTE
DO UPDATE user_limits ul
JOIN (
    SELECT 
        username,
        SUM(acctinputoctets) +
        SUM(acctoutputoctets) AS totaltraffic
    FROM radacct
    GROUP BY username
) rt ON ul.username = rt.username
SET ul.currenttraffic = rt.totaltraffic;

UPDATE user_limits
SET disabled = 1
WHERE currenttraffic > maxtraffic;

发表在 Linux | ocserv 配合 freeradius 进行流量统计已关闭评论

Gulp 使用简单介绍


Gulp 是一个基于 Node.js 的前端自动化构建工具,采用代码优于配置的理念,能够自动完成常见的前端任务,如压缩代码、编译 Sass/Less、实时刷新浏览器等。以下是 Gulp 的简单使用方法:

1. 安装 Node.js 和 npm

在使用 Gulp 之前,需要确保已经安装了 Node.js 和 npm(Node 包管理器)。可以在终端中输入以下命令检查是否已安装:

node -v
npm -v

2. 全局安装 Gulp CLI

使用 npm 全局安装 Gulp 的命令行工具,以便在命令行中使用 gulp 命令:

npm install --global gulp-cli

3. 初始化项目

在项目的根目录下,初始化 package.json 文件:

npm init -y


这将创建一个默认的 package.json 文件。

4. 安装 Gulp 到项目依赖

将 Gulp 安装到项目的开发依赖中:

npm install --save-dev gulp

5. 创建 gulpfile.js 文件

在项目根目录下创建一个名为 gulpfile.js 的文件,这是 Gulp 的配置文件,用于定义任务。

6. 编写 Gulp 任务

以下是一个简单的 Gulp 任务示例,用于压缩 JavaScript 文件:

// 引入 Gulp 和插件
const gulp = require('gulp');
const uglify = require('gulp-uglify');

// 定义一个名为 'scripts' 的任务
gulp.task('scripts', function() {
    return gulp.src('src/js/**/*.js') // 指定源文件路径
        .pipe(uglify())               // 压缩文件
        .pipe(gulp.dest('dist/js'));  // 输出到目标路径
});

7. 运行 Gulp 任务

在终端中,执行以下命令运行指定的任务:

gulp scripts

这将执行名为 scripts 的任务,压缩指定的 JavaScript 文件。

8. 监视文件变化

可以使用 Gulp 的 watch 功能,当文件发生变化时自动执行任务:

// 定义一个默认任务,监视文件变化
gulp.task('default', function() {
    gulp.watch('src/js/**/*.js', gulp.series('scripts'));
});

在终端中执行 gulp 命令即可开始监视:

gulp

9. 编译 Sass 文件

如需编译 Sass 文件,可以安装 gulp-sass 插件:

npm install --save-dev gulp-sass sass

在 gulpfile.js 中添加任务:

const sass = require('gulp-sass')(require('sass'));

gulp.task('styles', function() {
    return gulp.src('src/scss/**/*.scss') // 指定 Sass 源文件
        .pipe(sass().on('error', sass.logError)) // 编译 Sass
        .pipe(gulp.dest('dist/css')); // 输出到目标路径
});

更新默认任务,监视 Sass 文件变化:

gulp.task('default', function() {
    gulp.watch('src/js/**/*.js', gulp.series('scripts'));
    gulp.watch('src/scss/**/*.scss', gulp.series('styles'));
});

10. 合并多个任务

可以使用 gulp.series 或 gulp.parallel 方法来组合任务:

gulp.task('build', gulp.series('scripts', 'styles'));

执行 gulp build 命令即可依次运行 scripts 和 styles 任务。

11. 常用插件

gulp-uglify:压缩 JavaScript 文件。

gulp-sass:编译 Sass 文件。

gulp-concat:合并文件。

gulp-rename:重命名文件。

gulp-clean-css:压缩 CSS 文件。

gulp-imagemin:优化图像文件。

browser-sync:实时刷新浏览器。


12. 示例完整的 gulpfile.js

const gulp = require('gulp');
const uglify = require('gulp-uglify');
const sass = require('gulp-sass')(require('sass'));
const browserSync = require('browser-sync').create();

// 压缩 JavaScript
gulp.task('scripts', function() {
    return gulp.src('src/js/**/*.js')
        .pipe(uglify())
        .pipe(gulp.dest('dist/js'))
        .pipe(browserSync.stream());
});

// 编译 Sass
gulp.task('styles', function() {
    return gulp.src('src/scss/**/*.scss')
        .pipe(sass().on('error', sass.logError))
        .pipe(gulp.dest('dist/css'))
        .pipe(browserSync.stream());
});

// 静态服务器 + 监视文件变化
gulp.task('serve', function() {
    browserSync.init({
        server: './dist'
    });

    gulp.watch('src/js/**/*.js', gulp.series('scripts'));
    gulp.watch('src/scss/**/*.scss', gulp.series('styles'));
    gulp.watch('dist/*.html').on('change', browserSync.reload);
});

// 默认任务
gulp.task('default', gulp.series('scripts', 'styles', 'serve'));

13. 执行默认任务

在终端中运行:

gulp

Gulp 将执行默认任务,启动服务器并监视文件变化。

发表在 Javascript | Gulp 使用简单介绍已关闭评论

QML .pragma library

在 QML 中,.pragma library 是一种用于声明 JavaScript 文件为 共享库的指令。通过 .pragma library,可以将一个 JavaScript 文件作为一个全局可用的库,使得该文件中的所有变量和函数在应用程序的多个 QML 文件中保持一致。这在需要共享数据或状态的场景中非常有用。

如何使用 .pragma library

1.  创建一个 JavaScript 文件,例如 shared.js。
2.  在文件顶部添加 .pragma library。
3.  定义全局变量和函数。
.pragma library

var count = 0;

function increment() {
    count += 1;
    return count;
}

在 QML 中使用 shared.js

在 QML 文件中引用 shared.js 后,可以访问和修改其中的变量 count。

import QtQuick 2.15
import "shared.js" as Shared

Rectangle {
    width: 200; height: 200

    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log("Count: " + Shared.increment());
        }
    }
}

注意事项

•   .pragma library 指令仅允许在 JavaScript 文件中使用,且必须位于文件顶部。
•   在启用 .pragma library 后,所有变量和函数在引用该库的所有 QML 文件中都共享相同的实例。

总结

.pragma library 是实现 跨 QML 文件共享状态的有力工具,适用于需要全局共享数据或状态的应用场景。

发表在 C/C++ | QML .pragma library已关闭评论

QML的Logic-Model-View

在 QML 开发中,Logic-Model-View 是一种常见的架构模式。这种模式有助于分离应用的不同逻辑层,使代码更加清晰和易于维护。接下来,我将详细介绍它们之间的关系,以及在 QML 中如何使用这些模块。

  1. View (视图层)

QML 作为声明式 UI 框架,主要用来构建用户界面,即 View 层。它负责展示模型中的数据,并将用户的交互传递给逻辑层。

特点:

•   使用 QML 文件定义界面(如按钮、列表、布局等)。
•   视图和数据是通过模型绑定在一起的(如 ListView 绑定到一个模型)。
•   视图本身不会包含复杂的业务逻辑。

示例:ListView 视图绑定模型

ListView {
    width: 200; height: 300
    model: myModel  // 绑定数据模型

    delegate: Item {
        height: 40
        Text {
            text: modelData  // 展示模型中的数据
        }
    }
}

2. Model (模型层)模型层管理应用中的数据。

QML 支持多种模型,例如:

•   ListModel:适用于静态数据。
•   JS 数组:用 JavaScript 变量管理数据。
•   C++ 数据模型:适用于复杂场景,使用 C++ 提供自定义模型。

特点:

•   模型可以是简单的键值对,或者是复杂的结构。
•   支持通过 notify 信号实现数据的自动更新。

示例:ListModel

ListModel {
    id: myModel
    ListElement { name: "Apple"; price: 10 }
    ListElement { name: "Banana"; price: 5 }
}

示例:JS 数组

var items = [
    { name: "Apple", price: 10 },
    { name: "Banana", price: 5 }
];

3. Logic (逻辑层)逻辑层处理用户的交互和业务逻辑。在 QML 中,这一层通常使用 JavaScript 或 C++ 实现。

特点:

•   响应用户的操作(如按钮点击、滑动等)。
•   更新模型中的数据。
•   可以与 C++ 后端逻辑通信(如网络请求、数据库操作)。

示例:逻辑层使用 JavaScript

Button {
    text: "Add Item"
    onClicked: {
        myModel.append({ name: "Orange", price: 8 })  // 动态更新模型
    }
}

C++ 实现逻辑层:你可以使用 C++ 定义业务逻辑并通过 QML Context 将 C++ 对象暴露给 QML。
示例:将 C++ 对象暴露给 QML

QList<QVariant> data = { QVariant::fromValue(Item("Apple", 10)) };
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("myData", QVariant::fromValue(data));
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

Logic-Model-View 三者之间的关系

1.  View:展示模型数据,并将用户交互传递给逻辑层。
2.  Model:存储和管理数据,并将更新反馈给视图层(通常通过绑定)。
3.  Logic:处理用户输入或事件,并更新模型中的数据。

数据流示例:

1.  用户点击按钮(事件发生在 View 层)。
2.  逻辑层(JavaScript 或 C++)捕获事件,并更新数据模型。
3.  数据模型通知 View 更新,UI 自动刷新。

总结

•   View (视图层):用 QML 定义,负责 UI 和交互。
•   Model (模型层):管理数据,支持通过绑定更新 UI。
•   Logic (逻辑层):实现业务逻辑,使用 JS 或 C++。

这种分层结构使得代码模块化和职责明确。你可以根据项目需求,将复杂逻辑封装在 C++ 中,并通过模型和 QML 进行交互,使代码更易于维护和扩展。

发表在 C/C++ | QML的Logic-Model-View已关闭评论

将xcode移动到外置硬盘上

我们很多人买的macbook磁盘空间不足,因此我们把占用大户xcode移动到外置硬盘上

1.将 Xcode.app 从 系统的应用程序文件夹拖动到移动硬盘中的某个文件夹。

mv /Applications/Xcode.app /Volumes/mindata/Applications

2.更新工具链路径

sudo xcode-select -s /Volumes/mindata/Applications/Xcode.app/Contents/Developer

2.移动所有的缓存数据到移动硬盘上


mkdir -p /Volumes/mindata/Applications/XcodeData
mkdir -p /Volumes/mindata/Applications/XcodeData/DerivedData
mkdir -p /Volumes/mindata/Applications/XcodeData/CoreSimulator
mkdir -p /Volumes/mindata/Applications/XcodeData/Archives
# 移动 DerivedData
mv ~/Library/Developer/Xcode/DerivedData /Volumes/mindata/Applications/XcodeData/DerivedData

# 移动 CoreSimulator
mv ~/Library/Developer/CoreSimulator /Volumes/mindata/Applications/XcodeData/CoreSimulator

# 移动 Archives
mv ~/Library/Developer/Xcode/Archives /Volumes/mindata/Applications/XcodeData/Archives
# 为 DerivedData 创建符号链接
ln -s /Volumes/mindata/Applications/XcodeData/DerivedData ~/Library/Developer/Xcode/DerivedData

# 为 CoreSimulator 创建符号链接
ln -s /Volumes/mindata/Applications/XcodeData/CoreSimulator ~/Library/Developer/CoreSimulator

# 为 Archives 创建符号链接
ln -s /Volumes/mindata/Applications/XcodeData/Archives ~/Library/Developer/Xcode/Archives

3.6. 重启 Xcode 并测试

重新打开 Xcode,尝试进行编译和运行。Xcode 应该能正常使用移动硬盘上的缓存和数据。

发表在 Mac | 将xcode移动到外置硬盘上已关闭评论

Apple Silicon 安装 Qt

在 Apple Silicon (M1/M2) 上安装和配置 Qt 需要一些特定步骤,因为 Apple Silicon 与传统的 x86 架构存在差异。以下是如何在 macOS M1/M2 设备上顺利安装和运行 Qt。

步骤 1:准备工作

1. 更新 Homebrew(如果你没有安装 Homebrew,请先安装它):

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

2.安装 Xcode 和命令行工具:
在终端中运行:

xcode-select --install

打开 Xcode,确保在 Preferences > Locations 中选择了 Command Line Tools。

    步骤 2:通过 Homebrew 安装 Qt

    在 Apple Silicon 上使用 Homebrew 安装 Qt 是最简单的方法。运行以下命令:

    brew install qt

    Qt 将安装在 /opt/homebrew/opt/qt 目录中。

    确保 Qt 的路径已添加到你的环境变量中:

    echo 'export PATH="/opt/homebrew/opt/qt/bin:$PATH"' >> ~/.zshrc
    source ~/.zshrc

    步骤 3:验证 Qt 是否安装成功

    检查 Qt 版本:

    qmake --version

    输出示例:

    QMake version 3.1
    Using Qt version 6.x.x in /opt/homebrew/Cellar/qt/6.x.x/lib

    如果你看到 Qt 版本信息,说明安装成功。

    步骤 4:使用官方 Qt Installer(备用方法)

    如果你希望使用 Qt Creator 及其集成开发环境,可以下载官方的 Qt Online Installer。

    1.  前往 Qt 官方下载页面。
    2.  下载 Qt Online Installer,并运行安装程序。
    3.  在安装过程中:
    •   选择 macOS (arm64) 平台的 Qt 版本(适用于 Apple Silicon)。
    •   确保选择你需要的组件(如 Qt Creator、Qt WebEngine 等)。
    4.  安装完成后,打开 Qt Creator,检查是否能成功构建和运行项目。

    Rosetta 兼容性问题

    如果某些 Qt 模块未完全适配 Apple Silicon,可以通过 Rosetta 运行 Qt:

    arch -x86_64 /Applications/Qt/Qt\ Creator.app/Contents/MacOS/Qt\ Creator

    发表在 C/C++ | Apple Silicon 安装 Qt已关闭评论

    ArchLinux创建多用户VNC

    1.安装xfce4

    [root@vmSrv srv]# pacman -S xorg xfce4 xfce4-goodies alsa-utils kmix pipewire-pulse pavucontrol

    2安装LightDM(如果你需要在显示器里面登录)

    [root@vmSrv srv]# pacman -S lightdm lightdm-gtk-greeter
    [root@vmSrv srv]# systemctl enable lightdm

    2.安装一些依赖软件

     [root@vmSrv srv]# pacman -S tigervnc novnc websockify
     [root@vmSrv software]# pacman -U websockify-0.12.0-1-any.pkg.tar.zst novnc-1.4.0-1-any.pkg.tar.zst

    3.设置文字环境

    [root@vmSrv srv]# pacman -S wqy-microhei wqy-microhei-lite wqy-bitmapfont wqy-zenhei ttf-arphic-ukai ttf-arphic-uming adobe-source-han-sans-cn-fonts adobe-source-han-serif-cn-fonts noto-fonts-cjk

    nano -w /etc/locale.conf

    LANG=en_US.UTF-8
    LANGUAGE=zh_CN:zh:en_US:en
    LC_ALL=C
    LC_COLLATE=C
    LC_MESSAGES=C
    LC_TIME=en_US.UTF-8
    SUPPORTED=zh_CN.UTF-8:zh_CN:zh:en_US.UTF-8:en_US:en

    4.安装浏览器和中文输入法
    [root@vmSrv srv]# pacman -S fcitx5-im fcitx5-chinese-addons fcitx5-material-color

    nano -w /etc/environment

    #
    # This file is parsed by pam_env module
    #
    # Syntax: simple "KEY=VAL" pairs on separate lines
    #
    LANG=en_US.UTF-8
    LANGUAGE=zh_CN:zh:en_US:en

    GTK_IM_MODULE=fcitx
    QT_IM_MODULE=fcitx
    XMODIFIERS=@im=fcitx
    SDL_IM_MODULE=fcitx
    GLFW_IM_MODULE=ibus


    5.配置TigerVNC

    [root@vmSrv srv]# useradd -m zeno
    [root@vmSrv srv]# passwd zeno
    [root@vmSrv srv]# su – zeno
    [zeno@vmSrv srv]# vncpasswd
    [zeno@vmSrv srv]# exit

    [root@vmSrv srv]# nano -w /etc/tigervnc/vncserver.users

    # TigerVNC User assignment
    #
    # This file assigns users to specific VNC display numbers.
    # The syntax is <display>=<username>. E.g.:
    #
    # :2=andrew
    # :3=lisa
    :2=zeno

    [root@vmSrv srv]# su – zeno
    [zeno@vmSrv srv]# mkdir -p ~/.config/vnc/ && nano ~/.config/vnc/config

    session=xfce4
    geometry=1920x1080
    #localhost
    alwaysshared

    nano -w ~/.config/vnc/xstartup

    #!/bin/sh
    
    # Start the window manager
    unset SESSION_MANAGER
    unset DBUS_SESSION_BUS_ADDRESS
    exec /usr/bin/startxfce4 &

    [root@vmSrv srv]$ nano /usr/bin/vncsrv.sh

    #!/bin/bash
    #
    #  Copyright 2019 Pierre Ossman for Cendio AB
    #
    #  This is free software; you can redistribute it and/or modify
    #  it under the terms of the GNU General Public License as published by
    #  the Free Software Foundation; either version 2 of the License, or
    #  (at your option) any later version.
    #
    #  This software is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this software; if not, write to the Free Software
    #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
    #  USA.
    #
    
    USERSFILE="/etc/tigervnc/vncserver.users"
    CMD=/usr/bin/vncsession
    
    if [ $# -ne 1 ]; then
            echo "Syntax:" >&2
            echo "    $0 <display>" >&2
            exit 1
    fi
    
    if [ ! -f "${USERSFILE}" ]; then
            echo "Users file ${USERSFILE} missing" >&2
            exit 1
    fi
    
    DISPLAY="$1"
    
    USER=`grep "^ *${DISPLAY}=" "${USERSFILE}" 2>/dev/null | head -1 | cut -d = -f 2- | sed 's/ *$//g'`
    
    if [ -z "${USER}" ]; then
            echo "No user configured for display ${DISPLAY}" >&2
            exit 1
    fi
    
    cd /home/${USER}/
    
    exec "/usr/bin/vncsession" "${USER}" "${DISPLAY}"

    [root@vmSrv srv]$ systemctl enable vncserver@:2
    [root@vmSrv srv]$ systemctl start vncserver@:2

    6.配置noVNC

    [root@vmSrv srv]$ systemctl enable novnc@localhost:5902
    [root@vmSrv srv]$ systemctl start novnc@localhost:5902

    发表在 Linux, 默认分类 | ArchLinux创建多用户VNC已关闭评论