纯净系统纯手工打造独角数卡发卡站点环境,抛弃各种面板、一键网站环境。

https://github.com/assimon/dujiaoka

支付接口已集成

基本环境要求

  • (PHP + PHPCLI) version >= 7.2
  • Nginx version >= 1.16
  • MYSQL version >= 5.6
  • Redis (高性能缓存服务)
  • Supervisor (一个python编写的进程管理服务)
  • Composer (PHP包管理器)
  • Linux/Win (Win下未测试,建议直接Linux)

实测Supervisor不装也是可以运行的

PHP环境要求

星号(*)为必须执行的要求,其他为建议内容

  • *安装fileinfo扩展
  • *安装redis扩展
  • *终端需支持php-cli,测试php -v(版本必须一致)
  • *需要开启的函数:putenv,proc_open,pcntl_signal,pcntl_alarm
  • 安装opcache扩展

网络上各类发卡网站程序,比如ZFAKA、独角数卡环境搭建教程都是基于宝塔面板、LNMP等等环境搭建的教程。

ZFAKA可以在宝塔面板后台一键部署安装,也可以使用Docker版

为什么要手工搭建发卡网站环境

  1. 怕有后门(被害妄想症)
  2. 近期某某面板强迫用户注册才能使用
  3. 享受折腾的乐趣

测试使用环境Debian 10,其它系统可以参考修改搭建。

独角数卡发卡站环境搭建

Nginx、MYSQL的搭建具体教程请点击查看,这里重点只讲独角数卡发卡站环境搭建PHP环境的配置

PHP和一些必要组件的安装

apt -y install php-fpm php-mysql php-redis php-fileinfo php-cli php-gd redis-server php-mbstring php-bcmath php-curl php-xml php-dom

配置PHP组件

配置PHP的redis缓存组件

echo "extension=redis.so" >> /etc/php/7.3/fpm/php.ini

配置PHP的mbstring缓存组件

echo "extension=mbstring.so" >> /etc/php/7.3/fpm/php.ini
sed -i 's/;extension=mbstring/extension=mbstring/' /etc/php/7.3/fpm/php.ini
echo "extesion=bcmath.so" >> /etc/php/7.3/fpm/php.ini

安装Composer

php -r "copy('https://install.phpcomposer.com/installer', 'composer-setup.php');"
php composer-setup.php
mv composer.phar /usr/local/bin/composer

确保你的php环境没有禁用以下函数:

nano /etc/php/7.3/fpm/php.ini

按Ctrl+W组合键依次分别搜索putenv、proc_open、pcntl_signal、pcntl_alarm字段并删除它们

重启PHP生效

systemctl restart php7.3-fpm

站点nginx配置文件

echo "server {
  listen 80;
  listen [::]:80;
  server_name example.com;
  root /var/www/example.com/public;
  index index.html index.htm index.php;
  #return 301 https://$server_name$request_uri;
  location / {
    try_files $uri $uri/ /index.php$is_args$query_string;
   }
  #php
  location ~ \.php$ {
  include snippets/fastcgi-php.conf;
  fastcgi_pass unix:/run/php/php7.3-fpm.sock;
  }
}
server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name example.com;
  root /var/www/example.com/public;
  index index.html index.htm index.php;
  #独角数卡伪静态
  location / {
    try_files $uri $uri/ /index.php$is_args$query_string;
   }
   #SSL
    ssl on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_certificate      /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/example.com/privkey.pem;  
    ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
  #php
  location ~ \.php$ {
  include snippets/fastcgi-php.conf;
  fastcgi_pass unix:/run/php/php7.3-fpm.sock;
  }
}" > /etc/nginx/sites-available/example.com

创建软链接

ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

重启Nginx

systemctl restart nginx

下载独角数卡v1.7.1

wget https://github.com/assimon/dujiaoka/releases/download/v1.7.1/v1.7.1_build.tar.gz
tar -zxvf v1.7.1_build.tar.gz
mv dujiaoka_build /var/www/example.com

设置站点权限

我也不知道具体哪些目录,文件需要什么权限,这里无脑给777权限吧

chown -R www-data:www-data /var/www/example.com

修改项目配置文件

mv /var/www/example.com/.env.example /var/www/example.com/.env

然后编辑/var/www/example.com/.env把站点URL,数据库,SMTP邮件发送修改为自己的。

邮件服务

编辑根目录下.env配置,配置邮件服务

# 邮件服务配置
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_FROM_ADDRESS=server@emails.dujiaoka.com
MAIL_FROM_NAME=独角发卡
MAIL_ENCRYPTION=tls

如果不能发送邮件,就请尝试更换一下端口:587,465,22,挨个试试! MAIL_ENCRYPTION设置为ssl或者tls

修改后台登录地址

编辑项目根目录下.env里面的ADMIN_ROUTE_PREFIX即可

默认后台路径 域名/admin
默认管理员账号 admin
默认管理员密码 admin

导入sql

根目录下执行:

php artisan dujiao install

独角数卡 「2.0.0.beta」如果出现如下错误提示

RuntimeException
The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths.

可以在站点根目录下执行以下命令

php artisan key:generate
php artisan config:cache

配置supervisor

Supervisor (一个python编写的进程管理服务),不配置supervisor会导致SMTP不能发送订单邮件通知,如果不想装supervisor的话必须在站点目录/var/www/example.com下面执行php artisan queue:work,这里还是推荐使用Supervisor管理 Laravel 队列进程

安装supervisor

apt-get install supervisor

或者使用pip工具进行安装pip install supervisor还有其他的安装方式,请见Supervisor官网

Supervisor 的配置

运行这个命令可以生成一个默认的配置文件:

echo_supervisord_conf > /etc/supervisor/supervisord.conf

再执行

echo "[include]
files = /etc/supervisor/*.conf" >> /etc/supervisor/supervisord.conf

运行

supervisorctl

会提示unix:///tmp/supervisor.sock no such file的问题,需要编辑文件/etc/supervisor/supervisord.conf所有的/tmp路径改掉.

  1. /tmp/supervisor.sock 改成 /var/run/supervisor.sock
  2. /tmp/supervisord.log 改成 /var/log/supervisor.log
  3. /tmp/supervisord.pid 改成 /var/run/supervisor.pid

改完后的完整的/etc/supervisor/supervisord.conf如下

; Sample supervisor config file.
;
; For more information on the config file, please see:
; http://supervisord.org/configuration.html
;
; Notes:
;  - Shell expansion ("~" or "$HOME") is not supported.  Environment
;    variables can be expanded using this syntax: "%(ENV_HOME)s".
;  - Quotes around values are not supported, except in the case of
;    the environment= options as shown below.
;  - Comments must have a leading space: "a=b ;comment" not "a=b;comment".
;  - Command will be truncated if it looks like a config file comment, e.g.
;    "command=bash -c 'foo ; bar'" will truncate to "command=bash -c 'foo ".

[unix_http_server]
file=/var/run/supervisor.sock   ; the path to the socket file
;chmod=0700                 ; socket file mode (default 0700)
;chown=nobody:nogroup       ; socket file uid:gid owner
;username=user              ; default is no username (open server)
;password=123               ; default is no password (open server)

;[inet_http_server]         ; inet (TCP) server disabled by default
;port=127.0.0.1:9001        ; ip_address:port specifier, *:port for all iface
;username=user              ; default is no username (open server)
;password=123               ; default is no password (open server)

[supervisord]
logfile=/var/log/supervisor.log ; main log file; default $CWD/supervisord.log
logfile_maxbytes=50MB        ; max main logfile bytes b4 rotation; default 50MB
logfile_backups=10           ; # of main logfile backups; 0 means none, default 10
loglevel=info                ; log level; default info; others: debug,warn,trace
pidfile= /var/run/supervisor.pid ; supervisord pidfile; default supervisord.pid
nodaemon=false               ; start in foreground if true; default false
minfds=1024                  ; min. avail startup file descriptors; default 1024
minprocs=200                 ; min. avail process descriptors;default 200
;umask=022                   ; process file creation umask; default 022
;user=chrism                 ; default is current user, required if root
;identifier=supervisor       ; supervisord identifier, default is 'supervisor'
;directory=/tmp              ; default is not to cd during start
;nocleanup=true              ; don't clean up tempfiles at start; default false
;childlogdir=/tmp            ; 'AUTO' child log dir, default $TEMP
;environment=KEY="value"     ; key value pairs to add to environment
;strip_ansi=false            ; strip ansi escape codes in logs; def. false

; The rpcinterface:supervisor section must remain in the config file for
; RPC (supervisorctl/web interface) to work.  Additional interfaces may be
; added by defining them in separate [rpcinterface:x] sections.

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

; The supervisorctl section configures how supervisorctl will connect to
; supervisord.  configure it match the settings in either the unix_http_server
; or inet_http_server section.

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL  for a unix socket
;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
;username=chris              ; should be same as in [*_http_server] if set
;password=123                ; should be same as in [*_http_server] if set
;prompt=mysupervisor         ; cmd line prompt (default "supervisor")
;history_file=~/.sc_history  ; use readline history if available

; The sample program section below shows all possible program subsection values.
; Create one or more 'real' program: sections to be able to control them under
; supervisor.

;[program:theprogramname]
;command=/bin/cat              ; the program (relative uses PATH, can take args)
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
;numprocs=1                    ; number of processes copies to start (def 1)
;directory=/tmp                ; directory to cwd to before exec (def no cwd)
;umask=022                     ; umask for process (default None)
;priority=999                  ; the relative start priority (default 999)
;autostart=true                ; start at supervisord start (default: true)
;startsecs=1                   ; # of secs prog must stay up to be running (def. 1)
;startretries=3                ; max # of serial start failures when starting (default 3)
;autorestart=unexpected        ; when to restart if exited after running (def: unexpected)
;exitcodes=0,2                 ; 'expected' exit codes used with autorestart (default 0,2)
;stopsignal=QUIT               ; signal used to kill process (default TERM)
;stopwaitsecs=10               ; max num secs to wait b4 SIGKILL (default 10)
;stopasgroup=false             ; send stop signal to the UNIX process group (default false)
;killasgroup=false             ; SIGKILL the UNIX process group (def false)
;user=chrism                   ; setuid to this UNIX account to run the program
;redirect_stderr=true          ; redirect proc stderr to stdout (default false)
;stdout_logfile=/a/path        ; stdout log path, NONE for none; default AUTO
;stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10     ; # of stdout logfile backups (0 means none, default 10)
;stdout_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false   ; emit events on stdout writes (default false)
;stderr_logfile=/a/path        ; stderr log path, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups=10     ; # of stderr logfile backups (0 means none, default 10)
;stderr_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false   ; emit events on stderr writes (default false)
;environment=A="1",B="2"       ; process environment additions (def no adds)
;serverurl=AUTO                ; override serverurl computation (childutils)

; The sample eventlistener section below shows all possible eventlistener
; subsection values.  Create one or more 'real' eventlistener: sections to be
; able to handle event notifications sent by supervisord.

;[eventlistener:theeventlistenername]
;command=/bin/eventlistener    ; the program (relative uses PATH, can take args)
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
;numprocs=1                    ; number of processes copies to start (def 1)
;events=EVENT                  ; event notif. types to subscribe to (req'd)
;buffer_size=10                ; event buffer queue size (default 10)
;directory=/tmp                ; directory to cwd to before exec (def no cwd)
;umask=022                     ; umask for process (default None)
;priority=-1                   ; the relative start priority (default -1)
;autostart=true                ; start at supervisord start (default: true)
;startsecs=1                   ; # of secs prog must stay up to be running (def. 1)
;startretries=3                ; max # of serial start failures when starting (default 3)
;autorestart=unexpected        ; autorestart if exited after running (def: unexpected)
;exitcodes=0,2                 ; 'expected' exit codes used with autorestart (default 0,2)
;stopsignal=QUIT               ; signal used to kill process (default TERM)
;stopwaitsecs=10               ; max num secs to wait b4 SIGKILL (default 10)
;stopasgroup=false             ; send stop signal to the UNIX process group (default false)
;killasgroup=false             ; SIGKILL the UNIX process group (def false)
;user=chrism                   ; setuid to this UNIX account to run the program
;redirect_stderr=false         ; redirect_stderr=true is not allowed for eventlisteners
;stdout_logfile=/a/path        ; stdout log path, NONE for none; default AUTO
;stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10     ; # of stdout logfile backups (0 means none, default 10)
;stdout_events_enabled=false   ; emit events on stdout writes (default false)
;stderr_logfile=/a/path        ; stderr log path, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups=10     ; # of stderr logfile backups (0 means none, default 10)
;stderr_events_enabled=false   ; emit events on stderr writes (default false)
;environment=A="1",B="2"       ; process environment additions
;serverurl=AUTO                ; override serverurl computation (childutils)

; The sample group section below shows all possible group values.  Create one
; or more 'real' group: sections to create "heterogeneous" process groups.

;[group:thegroupname]
;programs=progname1,progname2  ; each refers to 'x' in [program:x] definitions
;priority=999                  ; the relative start priority (default 999)

; The [include] section can just contain the "files" setting.  This
; setting can list multiple files (separated by whitespace or
; newlines).  It can also contain wildcards.  The filenames are
; interpreted as relative to this file.  Included files *cannot*
; include files themselves.

;[include]
;files = relative/directory/*.ini


[include]
files = /etc/supervisor/*.conf

使用Supervisor管理 Laravel 队列进程

我们使用Laravel队列,会用到php artisan queue:work命令,让它监听队列,我们可以通过nohup方式让它在后台运行,但是进程如果意外中断是不会自动重启的,所以使用Supervisor来监控进程是个很好的方式。

首先在/etc/supervisor目录下新增一个Supervisor的配置文件,如下:

echo "[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/example.com/artisan queue:work --tries=3
autostart=true
autorestart=true
user=root
numprocs=8
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-queue.log" > /etc/supervisor/dujiaoka.conf

这里user填写Debian系统登陆用户,如 root,numprocs表示启动多少个进程来监听Laravel队列。

Supervisor进程管理

一切就绪后,我们使用如下命令就可以启动队列进程的监听了:

supervisorctl reread
supervisorctl update

启动Supervisor

supervisorctl start laravel-worker:*

Supervisor其它

/usr/bin/supervisord -h

如果顺利的话就可以打开站点,登陆后台管理了

Enjoy…

【补充更新】独角数卡-2.0.0

打开域名在线安装完成后,网站正式上线后务必关闭调试模式

sed -i 's/APP_DEBUG=true/APP_DEBUG=false/' /var/www/example.com/.env

如需要开启https登陆后台【可选】

echo "ADMIN_HTTPS=true" >> /var/www/example.com/.env

然后重启Supervisor

supervisorctl restart laravel-worker:*

替换favicon.ico

/var/www/example.com/public/assets/style/favicon.ico
/var/www/example.com/public/favicon.ico